mirror of https://github.com/sbt/sbt.git
detect cyclic references after freeze and translate nodes to keys
This commit is contained in:
parent
0b4d8fb505
commit
76ab8f8e53
|
|
@ -178,11 +178,24 @@ object EvaluateTask
|
|||
replaced
|
||||
}
|
||||
def transformInc[T](result: Result[T]): Result[T] =
|
||||
result.toEither.left.map { i => Incomplete.transformBU(i)(liftAnonymous andThen taskToKey ) }
|
||||
result.toEither.left.map { i => Incomplete.transformBU(i)(convertCyclicInc andThen liftAnonymous andThen taskToKey ) }
|
||||
def taskToKey: Incomplete => Incomplete = {
|
||||
case in @ Incomplete(Some(node: Task[_]), _, _, _, _) => in.copy(node = transformNode(node))
|
||||
case i => i
|
||||
}
|
||||
type AnyCyclic = Execute[Task]#CyclicException[_]
|
||||
def convertCyclicInc: Incomplete => Incomplete = {
|
||||
case in @ Incomplete(_, _, _, _, Some(c: AnyCyclic)) => in.copy(directCause = Some(new RuntimeException(convertCyclic(c))) )
|
||||
case i => i
|
||||
}
|
||||
def convertCyclic(c: AnyCyclic): String =
|
||||
(c.caller, c.target) match {
|
||||
case (caller: Task[_], target: Task[_]) =>
|
||||
c.toString + (if(caller eq target) "(task: " + name(caller) + ")" else "(caller: " + name(caller) + ", target: " + name(target) + ")" )
|
||||
case _ => c.toString
|
||||
}
|
||||
def name(node: Task[_]): String =
|
||||
node.info.name orElse transformNode(node).map(Project.display) getOrElse ("<anon-" + System.identityHashCode(node).toHexString + ">")
|
||||
def liftAnonymous: Incomplete => Incomplete = {
|
||||
case i @ Incomplete(node, tpe, None, causes, None) =>
|
||||
causes.find( inc => inc.message.isDefined || inc.directCause.isDefined) match {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ final class Execute[A[_] <: AnyRef](checkCycles: Boolean)(implicit view: NodeVie
|
|||
|
||||
def dump: String = "State: " + state.toString + "\n\nResults: " + results + "\n\nCalls: " + callers + "\n\n"
|
||||
|
||||
def run[T](root: A[T])(implicit strategy: Strategy): Result[T] = runKeep(root)(strategy)(root)
|
||||
def run[T](root: A[T])(implicit strategy: Strategy): Result[T] = try { runKeep(root)(strategy)(root) } catch { case i: Incomplete => Inc(i) }
|
||||
def runKeep[T](root: A[T])(implicit strategy: Strategy): RMap[A,Result] =
|
||||
{
|
||||
assert(state.isEmpty, "Execute already running/ran.")
|
||||
|
|
@ -64,7 +64,10 @@ final class Execute[A[_] <: AnyRef](checkCycles: Boolean)(implicit view: NodeVie
|
|||
{
|
||||
pre {
|
||||
assert( !reverse.isEmpty, "Nothing to process." )
|
||||
assert( state.values.exists( _ == Running ), "Nothing running")
|
||||
if( !state.values.exists( _ == Running ) ) {
|
||||
snapshotCycleCheck()
|
||||
assert(false, "Nothing running.")
|
||||
}
|
||||
}
|
||||
|
||||
(strategy.take()).process()
|
||||
|
|
@ -78,7 +81,6 @@ final class Execute[A[_] <: AnyRef](checkCycles: Boolean)(implicit view: NodeVie
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
def call[T](node: A[T], target: A[T])(implicit strategy: Strategy)
|
||||
{
|
||||
if(checkCycles) cycleCheck(node, target)
|
||||
|
|
@ -296,6 +298,10 @@ final class Execute[A[_] <: AnyRef](checkCycles: Boolean)(implicit view: NodeVie
|
|||
|
||||
// cyclic reference checking
|
||||
|
||||
def snapshotCycleCheck(): Unit =
|
||||
for( (called: A[c], callers) <- callers.toSeq; caller <- callers)
|
||||
cycleCheck(caller.asInstanceOf[A[c]], called)
|
||||
|
||||
def cycleCheck[T](node: A[T], target: A[T])
|
||||
{
|
||||
if(node eq target) cyclic(node, target, "Cannot call self")
|
||||
|
|
|
|||
Loading…
Reference in New Issue