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
|
replaced
|
||||||
}
|
}
|
||||||
def transformInc[T](result: Result[T]): Result[T] =
|
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 = {
|
def taskToKey: Incomplete => Incomplete = {
|
||||||
case in @ Incomplete(Some(node: Task[_]), _, _, _, _) => in.copy(node = transformNode(node))
|
case in @ Incomplete(Some(node: Task[_]), _, _, _, _) => in.copy(node = transformNode(node))
|
||||||
case i => i
|
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 = {
|
def liftAnonymous: Incomplete => Incomplete = {
|
||||||
case i @ Incomplete(node, tpe, None, causes, None) =>
|
case i @ Incomplete(node, tpe, None, causes, None) =>
|
||||||
causes.find( inc => inc.message.isDefined || inc.directCause.isDefined) match {
|
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 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] =
|
def runKeep[T](root: A[T])(implicit strategy: Strategy): RMap[A,Result] =
|
||||||
{
|
{
|
||||||
assert(state.isEmpty, "Execute already running/ran.")
|
assert(state.isEmpty, "Execute already running/ran.")
|
||||||
|
|
@ -64,7 +64,10 @@ final class Execute[A[_] <: AnyRef](checkCycles: Boolean)(implicit view: NodeVie
|
||||||
{
|
{
|
||||||
pre {
|
pre {
|
||||||
assert( !reverse.isEmpty, "Nothing to process." )
|
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()
|
(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)
|
def call[T](node: A[T], target: A[T])(implicit strategy: Strategy)
|
||||||
{
|
{
|
||||||
if(checkCycles) cycleCheck(node, target)
|
if(checkCycles) cycleCheck(node, target)
|
||||||
|
|
@ -296,6 +298,10 @@ final class Execute[A[_] <: AnyRef](checkCycles: Boolean)(implicit view: NodeVie
|
||||||
|
|
||||||
// cyclic reference checking
|
// 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])
|
def cycleCheck[T](node: A[T], target: A[T])
|
||||||
{
|
{
|
||||||
if(node eq target) cyclic(node, target, "Cannot call self")
|
if(node eq target) cyclic(node, target, "Cannot call self")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue