mirror of https://github.com/sbt/sbt.git
Failed task execution should still preserve State changes. Fixes #804.
Candidate for inclusion in 0.13.0 if there is another RC, otherwise scheduled for 0.13.1.
This commit is contained in:
parent
3e7bedd11b
commit
919d0ac63d
|
|
@ -75,23 +75,11 @@ object MainLoop
|
|||
case Left(t) => handleException(t, state)
|
||||
}
|
||||
|
||||
import ExceptionCategory._
|
||||
@deprecated("Use State.handleError", "0.13.0")
|
||||
def handleException(e: Throwable, s: State): State = s.handleError(e)
|
||||
|
||||
def handleException(e: Throwable, s: State): State =
|
||||
handleException(e, s, s.log)
|
||||
def handleException(t: Throwable, s: State, log: Logger): State =
|
||||
{
|
||||
ExceptionCategory(t) match {
|
||||
case AlreadyHandled => ()
|
||||
case m: MessageOnly => log.error(m.message)
|
||||
case f: Full => logFullException(f.exception, log)
|
||||
}
|
||||
s.fail
|
||||
}
|
||||
def logFullException(e: Throwable, log: Logger)
|
||||
{
|
||||
log.trace(e)
|
||||
log.error(ErrorHandling reducedToString e)
|
||||
log.error("Use 'last' for the full log.")
|
||||
}
|
||||
@deprecated("Use State.handleError", "0.13.0")
|
||||
def handleException(t: Throwable, s: State, log: Logger): State = State.handleException(t, s, log)
|
||||
|
||||
def logFullException(e: Throwable, log: Logger): Unit = State.logFullException(e, log)
|
||||
}
|
||||
|
|
@ -79,6 +79,12 @@ trait StateOps {
|
|||
/** Marks the currently executing command as failing. This triggers failure handling by the command processor. See also `State.onFailure`*/
|
||||
def fail: State
|
||||
|
||||
/** Marks the currently executing command as failing due to the given exception.
|
||||
* This displays the error appropriately and triggers failure handling by the command processor.
|
||||
* Note that this does not throw an exception and returns normally.
|
||||
* It is only once control is returned to the command processor that failure handling at the command level occurs. */
|
||||
def handleError(t: Throwable): State
|
||||
|
||||
/** Schedules `newCommands` to be run after any remaining commands. */
|
||||
def ++ (newCommands: Seq[Command]): State
|
||||
/** Schedules `newCommand` to be run after any remaining commands. */
|
||||
|
|
@ -190,6 +196,7 @@ object State
|
|||
def has(key: AttributeKey[_]) = s.attributes contains key
|
||||
def remove(key: AttributeKey[_]) = s.copy(attributes = s.attributes remove key)
|
||||
def log = s.globalLogging.full
|
||||
def handleError(t: Throwable): State = handleException(t, s, log)
|
||||
def fail =
|
||||
{
|
||||
val remaining = s.remainingCommands.dropWhile(_ != FailureWall)
|
||||
|
|
@ -205,6 +212,7 @@ object State
|
|||
case None => noHandler
|
||||
}
|
||||
|
||||
|
||||
def addExitHook(act: => Unit): State =
|
||||
s.copy(exitHooks = s.exitHooks + ExitHook(act))
|
||||
def runExitHooks(): State = {
|
||||
|
|
@ -221,4 +229,22 @@ object State
|
|||
def initializeClassLoaderCache = s.put(BasicKeys.classLoaderCache, newClassLoaderCache)
|
||||
private[this] def newClassLoaderCache = new classpath.ClassLoaderCache(s.configuration.provider.scalaProvider.launcher.topLoader)
|
||||
}
|
||||
|
||||
import ExceptionCategory._
|
||||
|
||||
private[sbt] def handleException(t: Throwable, s: State, log: Logger): State =
|
||||
{
|
||||
ExceptionCategory(t) match {
|
||||
case AlreadyHandled => ()
|
||||
case m: MessageOnly => log.error(m.message)
|
||||
case f: Full => logFullException(f.exception, log)
|
||||
}
|
||||
s.fail
|
||||
}
|
||||
private[sbt] def logFullException(e: Throwable, log: Logger)
|
||||
{
|
||||
log.trace(e)
|
||||
log.error(ErrorHandling reducedToString e)
|
||||
log.error("Use 'last' for the full log.")
|
||||
}
|
||||
}
|
||||
|
|
@ -47,8 +47,8 @@ final object Aggregation
|
|||
val log = state.log
|
||||
val extracted = Project extract state
|
||||
val success = results match { case Value(_) => true; case Inc(_) => false }
|
||||
try { EvaluateTask.onResult(results, log) { results => if(show.taskValues) printSettings(results, show.print) } }
|
||||
finally { if(show.success) printSuccess(start, stop, extracted, success, log) }
|
||||
results.toEither.right.foreach { r => if(show.taskValues) printSettings(r, show.print) }
|
||||
if(show.success) printSuccess(start, stop, extracted, success, log)
|
||||
}
|
||||
def timedRun[T](s: State, ts: Values[Task[T]], extra: DummyTaskMap): Complete[T] =
|
||||
{
|
||||
|
|
@ -73,7 +73,10 @@ final object Aggregation
|
|||
def runTasks[HL <: HList, T](s: State, structure: BuildStructure, ts: Values[Task[T]], extra: DummyTaskMap, show: ShowConfig)(implicit display: Show[ScopedKey[_]]): State = {
|
||||
val complete = timedRun[T](s, ts, extra)
|
||||
showRun(complete, show)
|
||||
complete.state
|
||||
complete.results match {
|
||||
case Inc(i) => complete.state.handleError(i)
|
||||
case Value(_) => complete.state
|
||||
}
|
||||
}
|
||||
|
||||
def printSuccess(start: Long, stop: Long, extracted: Extracted, success: Boolean, log: Logger)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
import sbt._
|
||||
import Keys._
|
||||
|
||||
object TestBuild extends Build
|
||||
{
|
||||
lazy val akey = AttributeKey[Int]("TestKey")
|
||||
lazy val t = TaskKey[String]("test-task")
|
||||
lazy val check = InputKey[Unit]("check")
|
||||
lazy val root = Project("root", file(".")).aggregate(a, b).settings(
|
||||
check := checkState(checkParser.parsed, state.value)
|
||||
)
|
||||
|
||||
lazy val a = Project("a", file("a")).settings(t := error("Failing"))
|
||||
|
||||
lazy val b = Project("b", file("b")).settings(t <<= Def.task("").updateState(updater))
|
||||
|
||||
def checkState(runs: Int, s: State) {
|
||||
val stored = s.get(akey).getOrElse(0)
|
||||
assert(stored == runs, "Expected " + runs + ", got " + stored)
|
||||
}
|
||||
|
||||
def updater(s: State, a: AnyRef): State = s.update(akey)(_.getOrElse(0) + 1)
|
||||
|
||||
import complete.DefaultParsers._
|
||||
|
||||
lazy val checkParser = token(Space ~> IntBasic)
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
> check 0
|
||||
-> test-task
|
||||
> check 1
|
||||
-> test-task
|
||||
> check 2
|
||||
> b/test-task
|
||||
> check 3
|
||||
-> a/test-task
|
||||
> check 3
|
||||
Loading…
Reference in New Issue