mirror of https://github.com/sbt/sbt.git
74 lines
1.9 KiB
Scala
74 lines
1.9 KiB
Scala
/* sbt -- Simple Build Tool
|
|
* Copyright 2008, 2009, 2010 David MacIver, Mark Harrah
|
|
*/
|
|
package sbt;
|
|
|
|
trait Dag[Node <: Dag[Node]]{
|
|
self : Node =>
|
|
|
|
def dependencies : Iterable[Node]
|
|
def topologicalSort = Dag.topologicalSort(self)(_.dependencies)
|
|
}
|
|
object Dag
|
|
{
|
|
import scala.collection.{mutable, JavaConverters}
|
|
import JavaConverters.asScalaSetConverter
|
|
|
|
def topologicalSort[T](root: T)(dependencies: T => Iterable[T]): List[T] = topologicalSort(root :: Nil)(dependencies)
|
|
|
|
def topologicalSort[T](nodes: Iterable[T])(dependencies: T => Iterable[T]): List[T] =
|
|
{
|
|
val discovered = new mutable.HashSet[T]
|
|
val finished = (new java.util.LinkedHashSet[T]).asScala
|
|
|
|
def visitAll(nodes: Iterable[T]) = nodes foreach visit
|
|
def visit(node : T){
|
|
if (!discovered(node)) {
|
|
discovered(node) = true;
|
|
try { visitAll(dependencies(node)); } catch { case c: Cyclic => throw node :: c }
|
|
finished += node;
|
|
}
|
|
else if(!finished(node))
|
|
throw new Cyclic(node)
|
|
}
|
|
|
|
visitAll(nodes);
|
|
|
|
finished.toList;
|
|
}
|
|
// doesn't check for cycles
|
|
def topologicalSortUnchecked[T](node: T)(dependencies: T => Iterable[T]): List[T] =
|
|
{
|
|
val discovered = new mutable.HashSet[T]
|
|
var finished: List[T] = Nil
|
|
|
|
def visitAll(nodes: Iterable[T]) = nodes foreach visit
|
|
def visit(node : T){
|
|
if (!discovered(node)) {
|
|
discovered(node) = true;
|
|
visitAll(dependencies(node))
|
|
finished ::= node;
|
|
}
|
|
}
|
|
|
|
visit(node);
|
|
finished;
|
|
}
|
|
final class Cyclic(val value: Any, val all: List[Any], val complete: Boolean)
|
|
extends Exception( "Cyclic reference involving " +
|
|
(if(complete) all.mkString("\n ", "\n ", "") else value)
|
|
)
|
|
{
|
|
def this(value: Any) = this(value, value :: Nil, false)
|
|
override def toString = getMessage
|
|
def ::(a: Any): Cyclic =
|
|
if(complete)
|
|
this
|
|
else if(a == value)
|
|
new Cyclic(value, all, true)
|
|
else
|
|
new Cyclic(value, a :: all, false)
|
|
}
|
|
}
|
|
|