mirror of https://github.com/sbt/sbt.git
Capture errors thrown inside `bgRun`
This captures non-fatal errors in `bgRun` background thread, so if needed we can re-throw it for `run`.
This commit is contained in:
parent
b6f2fe7654
commit
9003ed4fac
|
|
@ -5,6 +5,7 @@ import sbt.util.Logger
|
|||
import Def.{ ScopedKey, Classpath }
|
||||
import sbt.internal.util.complete._
|
||||
import java.io.File
|
||||
import scala.util.Try
|
||||
|
||||
abstract class BackgroundJobService extends Closeable {
|
||||
|
||||
|
|
@ -24,6 +25,12 @@ abstract class BackgroundJobService extends Closeable {
|
|||
def shutdown(): Unit
|
||||
def jobs: Vector[JobHandle]
|
||||
def stop(job: JobHandle): Unit
|
||||
|
||||
def waitForTry(job: JobHandle): Try[Unit] = {
|
||||
// This implementation is provided only for backward compatibility.
|
||||
Try(waitFor(job))
|
||||
}
|
||||
|
||||
def waitFor(job: JobHandle): Unit
|
||||
|
||||
/** Copies classpath to temporary directories. */
|
||||
|
|
|
|||
|
|
@ -1168,14 +1168,14 @@ object Defaults extends BuildCommon {
|
|||
Def.inputTask {
|
||||
val handle = bgRunMain.evaluated
|
||||
val service = bgJobService.value
|
||||
service.waitFor(handle)
|
||||
service.waitForTry(handle).get
|
||||
}
|
||||
// run calls bgRun in the background and waits for the result.
|
||||
def foregroundRunTask: Initialize[InputTask[Unit]] =
|
||||
Def.inputTask {
|
||||
val handle = bgRun.evaluated
|
||||
val service = bgJobService.value
|
||||
service.waitFor(handle)
|
||||
service.waitForTry(handle).get
|
||||
}
|
||||
def runMainTask(classpath: Initialize[Task[Classpath]],
|
||||
scalaRun: Initialize[Task[ScalaRun]]): Initialize[InputTask[Unit]] = {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import java.util.concurrent.atomic.AtomicLong
|
|||
import java.io.Closeable
|
||||
import Def.{ ScopedKey, Setting, Classpath }
|
||||
import scala.concurrent.ExecutionContext
|
||||
import scala.util.Try
|
||||
import Scope.GlobalScope
|
||||
import java.io.File
|
||||
import sbt.io.{ IO, Hash }
|
||||
|
|
@ -18,6 +19,13 @@ import sbt.internal.util.{ Attributed, ManagedLogger }
|
|||
private[sbt] abstract class BackgroundJob {
|
||||
def humanReadableName: String
|
||||
def awaitTermination(): Unit
|
||||
|
||||
/** This waits till the job ends, and returns inner error via `Try`. */
|
||||
def awaitTerminationTry(): Try[Unit] = {
|
||||
// This implementation is provided only for backward compatibility.
|
||||
Try(awaitTermination())
|
||||
}
|
||||
|
||||
def shutdown(): Unit
|
||||
// this should be true on construction and stay true until
|
||||
// the job is complete
|
||||
|
|
@ -132,15 +140,27 @@ private[sbt] abstract class AbstractBackgroundJobService extends BackgroundJobSe
|
|||
|
||||
private def withHandle(job: JobHandle)(f: ThreadJobHandle => Unit): Unit = job match {
|
||||
case handle: ThreadJobHandle @unchecked => f(handle)
|
||||
case dead: DeadHandle @unchecked => () // nothing to stop or wait for
|
||||
case _: DeadHandle @unchecked => () // nothing to stop or wait for
|
||||
case other =>
|
||||
sys.error(
|
||||
s"BackgroundJobHandle does not originate with the current BackgroundJobService: $other")
|
||||
}
|
||||
|
||||
private def withHandleTry(job: JobHandle)(f: ThreadJobHandle => Try[Unit]): Try[Unit] =
|
||||
job match {
|
||||
case handle: ThreadJobHandle @unchecked => f(handle)
|
||||
case _: DeadHandle @unchecked => Try(()) // nothing to stop or wait for
|
||||
case other =>
|
||||
Try(sys.error(
|
||||
s"BackgroundJobHandle does not originate with the current BackgroundJobService: $other"))
|
||||
}
|
||||
|
||||
override def stop(job: JobHandle): Unit =
|
||||
withHandle(job)(_.job.shutdown())
|
||||
|
||||
override def waitForTry(job: JobHandle): Try[Unit] =
|
||||
withHandleTry(job)(_.job.awaitTerminationTry())
|
||||
|
||||
override def waitFor(job: JobHandle): Unit =
|
||||
withHandle(job)(_.job.awaitTermination())
|
||||
|
||||
|
|
@ -212,6 +232,9 @@ private[sbt] class BackgroundThreadPool extends java.io.Closeable {
|
|||
@volatile
|
||||
private var status: Status = Waiting
|
||||
|
||||
// This is used to capture exceptions that are caught in this background job.
|
||||
private var exitTry: Option[Try[Unit]] = None
|
||||
|
||||
// double-finally for extra paranoia that we will finishedLatch.countDown
|
||||
override def run() =
|
||||
try {
|
||||
|
|
@ -226,7 +249,11 @@ private[sbt] class BackgroundThreadPool extends java.io.Closeable {
|
|||
throw new RuntimeException("Impossible status of bg thread")
|
||||
}
|
||||
}
|
||||
try { if (go) body() } finally cleanup()
|
||||
try {
|
||||
if (go) {
|
||||
exitTry = Option(Try(body()))
|
||||
}
|
||||
} finally cleanup()
|
||||
} finally finishedLatch.countDown()
|
||||
|
||||
private class StopListener(val callback: () => Unit, val executionContext: ExecutionContext)
|
||||
|
|
@ -269,6 +296,12 @@ private[sbt] class BackgroundThreadPool extends java.io.Closeable {
|
|||
result
|
||||
}
|
||||
override def awaitTermination(): Unit = finishedLatch.await()
|
||||
|
||||
override def awaitTerminationTry(): Try[Unit] = {
|
||||
awaitTermination()
|
||||
exitTry.getOrElse(Try(()))
|
||||
}
|
||||
|
||||
override def humanReadableName: String = taskName
|
||||
override def isRunning(): Boolean =
|
||||
status match {
|
||||
|
|
|
|||
Loading…
Reference in New Issue