diff --git a/src/main/scala/sbt/BasicProjectTypes.scala b/src/main/scala/sbt/BasicProjectTypes.scala index 03a1d3073..ea4d8e00c 100644 --- a/src/main/scala/sbt/BasicProjectTypes.scala +++ b/src/main/scala/sbt/BasicProjectTypes.scala @@ -520,7 +520,7 @@ trait ReflectiveProject extends ReflectiveModules with ReflectiveTasks with Refl /** This Project subclass is used to contain other projects as dependencies.*/ class ParentProject(val info: ProjectInfo) extends BasicDependencyProject { - def dependencies = info.dependencies ++ subProjects.values.toList + def dependencies: Iterable[Project] = info.dependencies ++ subProjects.values.toList /** The directories to which a project writes are listed here and is used * to check a project and its dependencies for collisions.*/ override def outputDirectories = managedDependencyPath :: outputPath :: Nil diff --git a/src/main/scala/sbt/Dag.scala b/src/main/scala/sbt/Dag.scala index 8a18491e6..8a33b60c7 100644 --- a/src/main/scala/sbt/Dag.scala +++ b/src/main/scala/sbt/Dag.scala @@ -1,28 +1,31 @@ /* sbt -- Simple Build Tool - * Copyright 2008 David MacIver + * Copyright 2008, 2009 David MacIver, Mark Harrah */ package sbt; -import scala.collection.mutable; - trait Dag[Node <: Dag[Node]]{ self : Node => def dependencies : Iterable[Node] + def topologicalSort = Dag.topologicalSort(self)(_.dependencies) +} +object Dag +{ + import scala.collection.mutable; - def topologicalSort = { - val discovered = new mutable.HashSet[Node]; - val finished = new wrap.MutableSetWrapper(new java.util.LinkedHashSet[Node]) + def topologicalSort[T](root: T)(dependencies: T => Iterable[T]) = { + val discovered = new mutable.HashSet[T]; + val finished = new wrap.MutableSetWrapper(new java.util.LinkedHashSet[T]) - def visit(dag : Node){ + def visit(dag : T){ if (!discovered(dag)) { discovered(dag) = true; - dag.dependencies.foreach(visit); + dependencies(dag).foreach(visit); finished += dag; } } - visit(self); + visit(root); finished.toList; } diff --git a/src/main/scala/sbt/Main.scala b/src/main/scala/sbt/Main.scala index aa8f13091..7f58b8e16 100644 --- a/src/main/scala/sbt/Main.scala +++ b/src/main/scala/sbt/Main.scala @@ -72,7 +72,7 @@ object Main import success.project val doNext: RunCompleteAction = // in interactive mode, fill all undefined properties - if(args.length > 0 || fillUndefinedProjectProperties(project.topologicalSort.toList.reverse)) + if(args.length > 0 || fillUndefinedProjectProperties(project.projectClosure.toList.reverse)) startProject(project, args, startTime) else new Exit(NormalExitCode) @@ -191,7 +191,7 @@ object Main **/ private def interactive(baseProject: Project): RunCompleteAction = { - val projectNames = baseProject.topologicalSort.map(_.name) + val projectNames = baseProject.projectClosure.map(_.name) val prefixes = ContinuousExecutePrefix :: CrossBuildPrefix :: Nil val completors = new Completors(ProjectAction, projectNames, interactiveCommands, List(GetAction, SetAction), prefixes) val reader = new JLineReader(baseProject.historyPath, completors, baseProject.log) @@ -235,7 +235,7 @@ object Main else if(trimmed.startsWith(ProjectAction + " ")) { val projectName = trimmed.substring(ProjectAction.length + 1) - baseProject.topologicalSort.find(_.name == projectName) match + baseProject.projectClosure.find(_.name == projectName) match { case Some(newProject) => { @@ -255,7 +255,7 @@ object Main if(trimmed == HelpAction) displayInteractiveHelp() else if(trimmed == ShowProjectsAction) - baseProject.topologicalSort.foreach(listProject) + baseProject.projectClosure.foreach(listProject) else if(trimmed.startsWith(SetAction + " ")) setProperty(currentProject, trimmed.substring(SetAction.length + 1)) else if(trimmed.startsWith(GetAction + " ")) @@ -414,7 +414,7 @@ object Main private def toggleTrace(project: Project) { val newValue = !project.log.traceEnabled - project.topologicalSort.foreach(_.log.enableTrace(newValue)) + project.projectClosure.foreach(_.log.enableTrace(newValue)) printTraceEnabled(project) } private def printTraceEnabled(project: Project) @@ -424,7 +424,7 @@ object Main /** Sets the logging level on the given project.*/ private def setLevel(project: Project, level: Level.Value) { - project.topologicalSort.foreach(_.log.setLevel(level)) + project.projectClosure.foreach(_.log.setLevel(level)) Console.println("Set log level to " + project.log.getLevel) } /** Prints the elapsed time to the given project's log using the given diff --git a/src/main/scala/sbt/Project.scala b/src/main/scala/sbt/Project.scala index 62587ccd3..76f999125 100644 --- a/src/main/scala/sbt/Project.scala +++ b/src/main/scala/sbt/Project.scala @@ -82,15 +82,7 @@ trait Project extends TaskManager with Dag[Project] with BasicEnvironment * specified for the project and are different from those specified in the project constructor. The * main use within sbt is in ParentProject.*/ def subProjects: Map[String, Project] = immutable.Map.empty - /** The name of this project and the names of all subprojects/dependencies, transitively.*/ - def projectNames: Iterable[String] = - { - val names = new mutable.HashSet[String] - names ++= subProjects.keys - for(dependentProject <- topologicalSort) - names ++= dependentProject.tasks.keys - names.toList - } + def projectClosure: List[Project] = Dag.topologicalSort(this)(p => p.dependencies ++ p.subProjects.values.toList) def call(name: String, parameters: Array[String]): Option[String] = { @@ -424,7 +416,7 @@ object Project * output directories. */ private def checkOutputDirectoriesImpl(project: Project): LoadResult = { - val projects = project.topologicalSort + val projects = project.projectClosure import scala.collection.mutable.{HashMap, HashSet, Set} val outputDirectories = new HashMap[Path, Set[Project]] for(p <- projects; path <- p.outputDirectories)