mirror of https://github.com/sbt/sbt.git
merge ProjectContainer into Project, rearrange sub project methods
This commit is contained in:
parent
323115e263
commit
0c12c5e2bd
|
|
@ -242,7 +242,7 @@ object Commands
|
|||
def loadProject = Command.simple(LoadProject, LoadProjectBrief, LoadProjectDetailed) { (in, s) =>
|
||||
val base = s.configuration.baseDirectory
|
||||
val p = MultiProject.load(s.configuration, ConsoleLogger() /*TODO*/)(base)
|
||||
val exts = p match { case pc: ProjectContainer => MultiProject.loadExternals(pc :: Nil, p.info.construct); case _ => Map.empty[File, Project] }
|
||||
val exts = MultiProject.loadExternals(p :: Nil, p.info.construct)
|
||||
s.copy(project = p)().put(MultiProject.ExternalProjects, exts.updated(base, p))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import std._
|
|||
import Path._
|
||||
import TaskExtra._
|
||||
import GlobFilter._
|
||||
import Transform.Context
|
||||
import inc.Analysis
|
||||
import build.{Auto, Build}
|
||||
import xsbti.AppConfiguration
|
||||
|
|
@ -58,78 +59,96 @@ object MultiProject
|
|||
Build.binaries(inputs.config.classpath, discovered, getClass.getClassLoader)(construct(info)).head.asInstanceOf[Project]
|
||||
}
|
||||
|
||||
def loadExternals[P](from: Iterable[ProjectContainer], loadImpl: File => P): Map[File, P] =
|
||||
def loadExternals(from: Iterable[Project], loadImpl: File => Project): Map[File, Project] =
|
||||
{
|
||||
def load(loaded: Map[File, P], file: File): Map[File, P] =
|
||||
def load(loaded: Map[File, Project], file: File): Map[File, Project] =
|
||||
(loaded get file) match
|
||||
{
|
||||
case None => doLoad(loaded, file)
|
||||
case Some(p) => loaded
|
||||
}
|
||||
def doLoad(loaded: Map[File, P], file: File): Map[File, P] =
|
||||
def doLoad(loaded: Map[File, Project], file: File): Map[File, Project] =
|
||||
{
|
||||
val loadedProject = loadImpl(file)
|
||||
val newMap = loaded.updated(file, loadedProject)
|
||||
loadedProject match
|
||||
{
|
||||
case container: ProjectContainer => loadAll( externals(container :: Nil), loaded )
|
||||
case _ => newMap
|
||||
}
|
||||
loadAll( externals(loadedProject :: Nil), newMap )
|
||||
}
|
||||
def loadAll(files: Set[File], loaded: Map[File, P]): Map[File, P] = (loaded /: files)(load)
|
||||
def loadAll(files: Set[File], loaded: Map[File, Project]): Map[File, Project] = (loaded /: files)(load)
|
||||
|
||||
loadAll( externals(from) , Map.empty)
|
||||
}
|
||||
|
||||
def externals(containers: Iterable[ProjectContainer]): Set[File] =
|
||||
def externals(containers: Iterable[Project]): Set[File] =
|
||||
{
|
||||
def exts(containers: Iterable[ProjectContainer]): Iterable[File] =
|
||||
containers flatMap { container => container.externalProjects ++ exts(container.internalProjects) }
|
||||
def exts(containers: Iterable[Project]): Iterable[File] =
|
||||
containers flatMap { container => externalProjects(container) ++ exts(internalProjects(container)) }
|
||||
exts(containers).toSet
|
||||
}
|
||||
def externalProjects(p: Project) = p.aggregate._1 ++ p.dependencies._1.map(_.path)
|
||||
def internalProjects(p: Project) = p.aggregate._2 ++ p.dependencies._2.map(_.project)
|
||||
|
||||
def internalTopologicalSort(root: Project): Seq[Project] =
|
||||
Dag.topologicalSort(root)(internalProjects)
|
||||
|
||||
def topologicalSort(root: Project, state: State): Seq[Project] = topologicalSort(root)(externalMap(state))
|
||||
def topologicalSort(root: Project)(implicit resolveExternal: File => Project): Seq[Project] =
|
||||
Dag.topologicalSort(root) { p =>
|
||||
(externalProjects(p) map resolveExternal) ++ internalProjects(p)
|
||||
}
|
||||
def externalMap(state: State): File => Project = state get MultiProject.ExternalProjects getOrElse Map.empty
|
||||
|
||||
def makeContext(root: Project, state: State) =
|
||||
{
|
||||
val allProjects = ProjectContainer.topologicalSort(root, state)
|
||||
val names = allProjects.map { p: Project => (p, p.name) }.toMap
|
||||
//val tasks = allProjects map { p =>
|
||||
ReflectiveContext(root, names.get _)
|
||||
val allProjects = topologicalSort(root, state)
|
||||
val contexts = allProjects map { p => (p, ReflectiveContext(p, p.name)) }
|
||||
val externals = externalMap(state)
|
||||
def subs(f: Project => (Iterable[File], Iterable[Project])): Project => Iterable[Project] = p =>
|
||||
{
|
||||
val (ext, int) = f(p)
|
||||
(ext map externals) ++ int
|
||||
}
|
||||
val deps = (p: Project) => {
|
||||
val (dsI, dsE) = p.dependencies
|
||||
(dsI.map(_.path), dsE.map(_.project))
|
||||
}
|
||||
MultiContext(contexts)(subs(_.aggregate), subs(deps) )
|
||||
}
|
||||
}
|
||||
|
||||
/*trait MultiContext[Owner] extends Context[Owner]
|
||||
object MultiContext
|
||||
{
|
||||
def ownerForName(name: String): Option[Owner]
|
||||
def allTasks(owner: Owner): Iterable[Task[_]]
|
||||
def externalProject(base: File): Project
|
||||
}*/
|
||||
def identityMap[A,B](in: Iterable[(A,B)]): collection.Map[A,B] =
|
||||
{
|
||||
import collection.JavaConversions._
|
||||
val map: collection.mutable.Map[A, B] = new java.util.IdentityHashMap[A,B]
|
||||
for( (a,b) <- in) map(a) = b
|
||||
map
|
||||
}
|
||||
def fun[A,B](map: collection.Map[A,B]): A => Option[B] = map get _
|
||||
def apply[Owner <: AnyRef](contexts: Iterable[(Owner, Context[Owner])])(agg: Owner => Iterable[Owner], deps: Owner => Iterable[Owner]): Context[Owner] = new Context[Owner]
|
||||
{
|
||||
val ownerReverse = (for( (owner, context) <- contexts; name <- context.ownerName(owner).toList) yield (name, owner) ).toMap
|
||||
val ownerMap = identityMap[Task[_],Owner]( for((owner, context) <- contexts; task <- context.allTasks(owner) ) yield (task, owner) )
|
||||
val context = identityMap(contexts)
|
||||
def subMap(f: Owner => Iterable[Owner]) = identityMap( contexts.map { case (o,_) => (o,f(o)) })
|
||||
val aggMap = subMap(agg)
|
||||
val depMap = subMap(deps)
|
||||
|
||||
trait ProjectContainer
|
||||
{
|
||||
/** All projects that are loaded from their base directory instead of being defined in this container's compilation set.
|
||||
* This is for any contained projects, including execution and classpath dependencies. */
|
||||
def externalProjects: Iterable[File]
|
||||
/** All projects directly contained in this that are defined in this container's compilation set.
|
||||
* This is for any contained projects, including execution and classpath dependencies, but not external projects. */
|
||||
def internalProjects: Iterable[Project]
|
||||
def allTasks(owner: Owner): Iterable[Task[_]] = context(owner).allTasks(owner)
|
||||
def ownerForName(name: String): Option[Owner] = ownerReverse get name
|
||||
val staticName: Task[_] => Option[String] = t => owner(t) flatMap { o => context(o).staticName(t) }
|
||||
val ownerName = (o: Owner) => context(o).ownerName(o)
|
||||
val owner = (t: Task[_]) => ownerMap.get(t)
|
||||
val aggregate = (o: Owner) => (aggMap get o).toList.flatten
|
||||
def dependencies(o: Owner): Iterable[Owner] = (depMap get o).toList.flatten
|
||||
val static = (o: Owner, s: String) => context(o).static(o, s)
|
||||
}
|
||||
}
|
||||
|
||||
object ProjectContainer
|
||||
{
|
||||
def internalTopologicalSort(root: Project): Seq[Project] =
|
||||
Dag.topologicalSort(root) { _.internalProjects }
|
||||
|
||||
def topologicalSort(root: Project, state: State): Seq[Project] = topologicalSort(root)(state get MultiProject.ExternalProjects getOrElse Map.empty)
|
||||
def topologicalSort(root: Project)(implicit resolveExternal: File => Project): Seq[Project] =
|
||||
Dag.topologicalSort(root) { p =>
|
||||
(p.externalProjects map resolveExternal) ++ p.internalProjects
|
||||
}
|
||||
}
|
||||
|
||||
trait Project extends Tasked with ProjectContainer
|
||||
trait Project extends Tasked
|
||||
{
|
||||
val info: ProjectInfo
|
||||
def name: String = info.name.get
|
||||
def name: String = info.name getOrElse "'name' not overridden"
|
||||
|
||||
def base = info.projectDirectory
|
||||
def outputRootPath = base / "target"
|
||||
|
|
@ -139,6 +158,10 @@ trait Project extends Tasked with ProjectContainer
|
|||
def input = Dummy.In
|
||||
def state = Dummy.State
|
||||
|
||||
// (external, internal)
|
||||
def aggregate: (Iterable[File], Iterable[Project])
|
||||
def dependencies: (Iterable[ExternalDependency], Iterable[ProjectDependency])
|
||||
|
||||
type Task[T] = sbt.Task[T]
|
||||
def act(input: Input, state: State): Option[(Task[State], Execute.NodeView[Task])] =
|
||||
{
|
||||
|
|
@ -146,28 +169,46 @@ trait Project extends Tasked with ProjectContainer
|
|||
val context = MultiProject.makeContext(this, state)
|
||||
val dummies = new Transform.Dummies(In, State, Streams)
|
||||
def name(t: Task[_]): String = context.staticName(t) getOrElse std.Streams.name(t)
|
||||
val injected = new Transform.Injected( input, state, std.Streams(t => streamBase / name(t), (t, writer) => ConsoleLogger() ) )
|
||||
context.forName(input.name) map { t => (t.merge.map(_ => state), Transform(dummies, injected, context) ) }
|
||||
val actualStreams = std.Streams(t => context.owner(t).get.streamBase / name(t), (t, writer) => ConsoleLogger() )
|
||||
val injected = new Transform.Injected( input, state, actualStreams )
|
||||
context.static(this, input.name) map { t => (t.merge.map(_ => state), Transform(dummies, injected, context) ) }
|
||||
}
|
||||
|
||||
def help: Seq[Help] = Nil
|
||||
}
|
||||
|
||||
trait ReflectiveProject extends Project
|
||||
{
|
||||
import ReflectUtilities.allVals
|
||||
private[this] def vals[T: Manifest] = allVals[T](this).map(_._2)
|
||||
def aggregate: (Iterable[File], Iterable[Project]) = (vals[ExternalProject].map(_.path), vals[Project] )
|
||||
/** All projects directly contained in this that are defined in this container's compilation set.
|
||||
* This is for any contained projects, including execution and classpath dependencies, but not external projects. */
|
||||
def dependencies: (Iterable[ExternalDependency], Iterable[ProjectDependency]) = (vals[ExternalDependency], vals[ProjectDependency])
|
||||
}
|
||||
|
||||
trait ProjectConstructors
|
||||
{
|
||||
val info: ProjectInfo
|
||||
def project(base: Path, name: String, deps: ProjectDependency*): Project
|
||||
def project[P <: Project](path: Path, name: String, builderClass: Class[P], deps: ProjectDependency*): P
|
||||
def project[P <: Project](path: Path, name: String, construct: ProjectInfo => P, deps: ProjectDependency*): P
|
||||
def project(base: Path): ExternalProject = new ExternalProject(base)
|
||||
def project(base: Path): ExternalProject = new ExternalProject(base.asFile)
|
||||
|
||||
implicit def defaultProjectDependency(p: Project): ProjectDependency = new ProjectDependency(p, None)
|
||||
implicit def dependencyConstructor(p: Project): ProjectDependencyConstructor = new ProjectDependencyConstructor {
|
||||
def %(conf: String) = new ProjectDependency(p, Some(conf))
|
||||
}
|
||||
implicit def extDependencyConstructor(p: ExternalProject): ExtProjectDependencyConstructor = new ExtProjectDependencyConstructor {
|
||||
def %(conf: String) = new ExternalDependency(p.path, Some(conf))
|
||||
}
|
||||
}
|
||||
final class ProjectDependency(val project: Project, val configuration: Option[String])
|
||||
sealed trait ProjectDependencyConstructor {
|
||||
def %(conf: String): ProjectDependency
|
||||
}
|
||||
final class ExternalProject(val path: Path)
|
||||
sealed trait ExtProjectDependencyConstructor {
|
||||
def %(conf: String): ExternalDependency
|
||||
}
|
||||
final class ExternalProject(val path: File)
|
||||
final class ExternalDependency(val path: File, val configuration: Option[String])
|
||||
|
|
@ -23,11 +23,11 @@ trait SingleProject extends Tasked with PrintTask with TaskExtra with Types
|
|||
def act(input: Input, state: State): Option[(Task[State], Execute.NodeView[Task])] =
|
||||
{
|
||||
import Dummy._
|
||||
val context = ReflectiveContext(this, (x: SingleProject) => Some("project")) // TODO: project names
|
||||
val context = ReflectiveContext(this, "project")
|
||||
val dummies = new Transform.Dummies(In, State, Streams)
|
||||
def name(t: Task[_]): String = context.staticName(t) getOrElse std.Streams.name(t)
|
||||
val injected = new Transform.Injected( input, state, std.Streams(t => streamBase / name(t), (t, writer) => ConsoleLogger() ) )
|
||||
context.forName(input.name) map { t => (t.merge.map(_ => state), Transform(dummies, injected, context) ) }
|
||||
context.static(this, input.name) map { t => (t.merge.map(_ => state), Transform(dummies, injected, context) ) }
|
||||
}
|
||||
|
||||
def help: Seq[Help] = Nil
|
||||
|
|
@ -118,7 +118,7 @@ final class MapBackedAttribute[T](val default: Option[T], subs: Map[String, MapB
|
|||
newSubs put (h, su
|
||||
|
||||
}
|
||||
trait ConsoleLogManager
|
||||
trait ConsoleLogManager extends LogManager
|
||||
{
|
||||
def makeLogger(context: Context, configuration: Configuration) = (task: Task[_], to: PrintWriter) =>
|
||||
{
|
||||
|
|
@ -144,18 +144,19 @@ trait ConsoleLogManager
|
|||
object ReflectiveContext
|
||||
{
|
||||
import Transform.Context
|
||||
def apply[Owner <: AnyRef : Manifest](context: Owner, name: Owner => Option[String]): Context[Owner] = new Context[Owner]
|
||||
def apply[Owner <: AnyRef : Manifest](context: Owner, name: String): Context[Owner] = new Context[Owner]
|
||||
{
|
||||
private[sbt] lazy val tasks: Map[String, Task[_]] = ReflectUtilities.allVals[Task[_]](context).toMap
|
||||
private[sbt] lazy val reverseName: collection.Map[Task[_], String] = reverseMap(tasks)
|
||||
private[sbt] lazy val sub: collection.Map[String, Owner] = ReflectUtilities.allVals[Owner](context)
|
||||
private[sbt] lazy val reverseSub: collection.Map[Owner, String] = reverseMap(sub)
|
||||
|
||||
def forName(s: String): Option[Task[_]] = tasks get s
|
||||
val staticName: Task[_] => Option[String] = reverseName.get _
|
||||
val ownerName = name
|
||||
val owner = (_: Task[_]) => Some(context)
|
||||
val subs = (o: Owner) => Nil
|
||||
val ownerName = (o: Owner) => if(o eq context) Some(name) else None
|
||||
val owner = (t: Task[_]) => if(reverseName contains t) Some(context) else None
|
||||
def allTasks(o: Owner): Iterable[Task[_]] = if(o eq context) tasks.values else Nil
|
||||
def ownerForName(oname: String): Option[Owner] = if(name == oname) Some(context) else None
|
||||
val aggregate = (_: Owner) => Nil
|
||||
val static = (o: Owner, s: String) => if(o eq context) tasks.get(s) else None
|
||||
|
||||
private def reverseMap[A,B](in: Iterable[(A,B)]): collection.Map[B,A] =
|
||||
|
|
|
|||
|
|
@ -102,12 +102,13 @@ object Transform
|
|||
final class Injected[Input, State](val in: Input, val state: State, val streams: Streams)
|
||||
trait Context[Owner]
|
||||
{
|
||||
def forName(s: String): Option[Task[_]]
|
||||
def staticName: Task[_] => Option[String]
|
||||
def owner: Task[_] => Option[Owner]
|
||||
def ownerName: Owner => Option[String]
|
||||
def subs: Owner => Iterable[Owner]
|
||||
def aggregate: Owner => Iterable[Owner]
|
||||
def static: (Owner, String) => Option[Task[_]]
|
||||
def allTasks(owner: Owner): Iterable[Task[_]]
|
||||
def ownerForName(name: String): Option[Owner]
|
||||
}
|
||||
def setOriginal(delegate: Task ~> Task): Task ~> Task =
|
||||
new (Task ~> Task) {
|
||||
|
|
@ -129,7 +130,7 @@ object Transform
|
|||
import System._
|
||||
import Convert._
|
||||
val inputs = dummyMap(dummyIn, dummyState)(in, state)
|
||||
Convert.taskToNode ∙ setOriginal(streamed(streams, dummyStreams)) ∙ implied(owner, subs, static) ∙ setOriginal(name(staticName)) ∙ getOrId(inputs)
|
||||
Convert.taskToNode ∙ setOriginal(streamed(streams, dummyStreams)) ∙ implied(owner, aggregate, static) ∙ setOriginal(name(staticName)) ∙ getOrId(inputs)
|
||||
}
|
||||
}
|
||||
object Convert
|
||||
|
|
|
|||
Loading…
Reference in New Issue