mirror of https://github.com/sbt/sbt.git
more flexible inter-project dependencies
This commit is contained in:
parent
c2ebcba73b
commit
5fbe6e9d97
|
|
@ -0,0 +1,32 @@
|
|||
package sbt
|
||||
|
||||
import Types.idFun
|
||||
import BuildDependencies._
|
||||
|
||||
final class BuildDependencies private(val classpath: DependencyMap[ClasspathDep[ProjectRef]], val aggregate: DependencyMap[ProjectRef])
|
||||
{
|
||||
def classpathRefs(ref: ProjectRef): Seq[ProjectRef] = classpath(ref) map getID
|
||||
def classpathTransitiveRefs(ref: ProjectRef): Seq[ProjectRef] = classpathTransitive(ref)
|
||||
|
||||
lazy val classpathTransitive: DependencyMap[ProjectRef] = transitive(classpath, getID)
|
||||
lazy val aggregateTransitive: DependencyMap[ProjectRef] = transitive(aggregate, idFun[ProjectRef])
|
||||
|
||||
def addClasspath(ref: ProjectRef, deps: ClasspathDep[ProjectRef]*): BuildDependencies =
|
||||
new BuildDependencies( classpath.updated(ref, deps ++ classpath.getOrElse(ref, Nil)), aggregate)
|
||||
def addAggregate(ref: ProjectRef, deps: ProjectRef*): BuildDependencies =
|
||||
new BuildDependencies(classpath, aggregate.updated(ref, deps ++ aggregate.getOrElse(ref, Nil)))
|
||||
}
|
||||
object BuildDependencies
|
||||
{
|
||||
def apply(classpath: DependencyMap[ClasspathDep[ProjectRef]], aggregate: DependencyMap[ProjectRef]): BuildDependencies =
|
||||
new BuildDependencies(classpath, aggregate)
|
||||
|
||||
type DependencyMap[D] = Map[ProjectRef, Seq[D]]
|
||||
def transitive[D](deps: DependencyMap[D], extract: D => ProjectRef): DependencyMap[ProjectRef] =
|
||||
for( (ref, _) <- deps ) yield
|
||||
{
|
||||
val sorted = Dag.topologicalSort(ref)(d => deps(d) map extract)
|
||||
(ref, sorted dropRight 1)
|
||||
}
|
||||
val getID: ClasspathDep[ProjectRef] => ProjectRef = _.project
|
||||
}
|
||||
|
|
@ -48,6 +48,7 @@ object Defaults extends BuildCommon
|
|||
managedDirectory <<= baseDirectory(_ / "lib_managed")
|
||||
))
|
||||
def globalCore: Seq[Setting[_]] = inScope(GlobalScope)(Seq(
|
||||
buildDependencies <<= buildDependencies or Classpaths.constructBuildDependencies,
|
||||
taskTemporaryDirectory := IO.createTemporaryDirectory,
|
||||
onComplete <<= taskTemporaryDirectory { dir => () => IO.delete(dir); IO.createDirectory(dir) },
|
||||
parallelExecution :== true,
|
||||
|
|
@ -839,20 +840,19 @@ object Classpaths
|
|||
|
||||
def deliverPattern(outputPath: File): String = (outputPath / "[artifact]-[revision](-[classifier]).[ext]").absolutePath
|
||||
|
||||
def projectDependenciesTask =
|
||||
(thisProject, settings) map { (p, data) =>
|
||||
p.dependencies flatMap { dep => (projectID in dep.project) get data map { _.copy(configurations = dep.configuration) } }
|
||||
def projectDependenciesTask: Initialize[Task[Seq[ModuleID]]] =
|
||||
(thisProjectRef, settings, buildDependencies) map { (ref, data, deps) =>
|
||||
deps.classpath(ref) flatMap { dep => (projectID in dep.project) get data map { _.copy(configurations = dep.configuration) } }
|
||||
}
|
||||
|
||||
def depMap: Initialize[Task[Map[ModuleRevisionId, ModuleDescriptor]]] =
|
||||
(thisProject, thisProjectRef, settings, streams) flatMap { (root, rootRef, data, s) =>
|
||||
val dependencies = (p: (ProjectRef, ResolvedProject)) => p._2.dependencies.flatMap(pr => thisProject in pr.project get data map { (pr.project, _) })
|
||||
depMap(Dag.topologicalSort((rootRef,root))(dependencies).dropRight(1), data, s.log)
|
||||
(thisProjectRef, settings, buildDependencies, streams) flatMap { (root, data, deps, s) =>
|
||||
depMap(deps classpathTransitiveRefs root, data, s.log)
|
||||
}
|
||||
|
||||
def depMap(projects: Seq[(ProjectRef,ResolvedProject)], data: Settings[Scope], log: Logger): Task[Map[ModuleRevisionId, ModuleDescriptor]] =
|
||||
projects.flatMap { case (p,_) => ivyModule in p get data }.join.map { mods =>
|
||||
mods map { _.dependencyMapping(log) } toMap ;
|
||||
def depMap(projects: Seq[ProjectRef], data: Settings[Scope], log: Logger): Task[Map[ModuleRevisionId, ModuleDescriptor]] =
|
||||
projects.flatMap( ivyModule in _ get data).join.map { mod =>
|
||||
mod map { _.dependencyMapping(log) } toMap ;
|
||||
}
|
||||
|
||||
def projectResolverTask: Initialize[Task[Resolver]] =
|
||||
|
|
@ -868,10 +868,23 @@ object Classpaths
|
|||
(if(useJars) Seq(pkgTask).join else psTask) map { _ map { f => analyzed(f, analysis) } }
|
||||
}
|
||||
|
||||
def constructBuildDependencies: Initialize[BuildDependencies] =
|
||||
loadedBuild { lb =>
|
||||
import collection.mutable.HashMap
|
||||
val agg = new HashMap[ProjectRef, Seq[ProjectRef]]
|
||||
val cp = new HashMap[ProjectRef, Seq[ClasspathDep[ProjectRef]]]
|
||||
for(lbu <- lb.units.values; rp <- lbu.defined.values)
|
||||
{
|
||||
val ref = ProjectRef(lbu.unit.uri, rp.id)
|
||||
cp(ref) = rp.dependencies
|
||||
agg(ref) = rp.aggregate
|
||||
}
|
||||
BuildDependencies(cp.toMap, agg.toMap)
|
||||
}
|
||||
def internalDependencies: Initialize[Task[Classpath]] =
|
||||
(thisProjectRef, thisProject, classpathConfiguration, configuration, settings) flatMap internalDependencies0
|
||||
(thisProjectRef, classpathConfiguration, configuration, settings, buildDependencies) flatMap internalDependencies0
|
||||
def unmanagedDependencies: Initialize[Task[Classpath]] =
|
||||
(thisProjectRef, thisProject, configuration, settings) flatMap unmanagedDependencies0
|
||||
(thisProjectRef, configuration, settings, buildDependencies) flatMap unmanagedDependencies0
|
||||
def mkIvyConfiguration: Initialize[Task[IvyConfiguration]] =
|
||||
(fullResolvers, ivyPaths, otherResolvers, moduleConfigurations, offline, checksums in update, appConfiguration, streams) map { (rs, paths, other, moduleConfs, off, check, app, s) =>
|
||||
new InlineIvyConfiguration(paths, rs, other, moduleConfs, off, Some(lock(app)), check, s.log)
|
||||
|
|
@ -879,19 +892,18 @@ object Classpaths
|
|||
|
||||
import java.util.LinkedHashSet
|
||||
import collection.JavaConversions.asScalaSet
|
||||
def interSort(projectRef: ProjectRef, project: ResolvedProject, conf: Configuration, data: Settings[Scope]): Seq[(ProjectRef,String)] =
|
||||
def interSort(projectRef: ProjectRef, conf: Configuration, data: Settings[Scope], deps: BuildDependencies): Seq[(ProjectRef,String)] =
|
||||
{
|
||||
val visited = asScalaSet(new LinkedHashSet[(ProjectRef,String)])
|
||||
def visit(p: ProjectRef, project: ResolvedProject, c: Configuration)
|
||||
def visit(p: ProjectRef, c: Configuration)
|
||||
{
|
||||
val applicableConfigs = allConfigs(c)
|
||||
for(ac <- applicableConfigs) // add all configurations in this project
|
||||
visited add (p, ac.name)
|
||||
val masterConfs = names(getConfigurations(projectRef, data))
|
||||
|
||||
for( ResolvedClasspathDependency(dep, confMapping) <- project.dependencies)
|
||||
for( ResolvedClasspathDependency(dep, confMapping) <- deps.classpath(p))
|
||||
{
|
||||
val depProject = thisProject in dep get data getOrElse error("Invalid project: " + dep)
|
||||
val configurations = getConfigurations(dep, data)
|
||||
val mapping = mapped(confMapping, masterConfs, names(configurations), "compile", "*->compile")
|
||||
// map master configuration 'c' and all extended configurations to the appropriate dependency configuration
|
||||
|
|
@ -899,21 +911,21 @@ object Classpaths
|
|||
{
|
||||
for(depConf <- confOpt(configurations, depConfName) )
|
||||
if( ! visited( (dep, depConfName) ) )
|
||||
visit(dep, depProject, depConf)
|
||||
visit(dep, depConf)
|
||||
}
|
||||
}
|
||||
}
|
||||
visit(projectRef, project, conf)
|
||||
visit(projectRef, conf)
|
||||
visited.toSeq
|
||||
}
|
||||
def unmanagedDependencies0(projectRef: ProjectRef, project: ResolvedProject, conf: Configuration, data: Settings[Scope]): Task[Classpath] =
|
||||
interDependencies(projectRef, project, conf, conf, data, true, unmanagedLibs)
|
||||
def internalDependencies0(projectRef: ProjectRef, project: ResolvedProject, conf: Configuration, self: Configuration, data: Settings[Scope]): Task[Classpath] =
|
||||
interDependencies(projectRef, project, conf, self, data, false, productsTask)
|
||||
def interDependencies(projectRef: ProjectRef, project: ResolvedProject, conf: Configuration, self: Configuration, data: Settings[Scope], includeSelf: Boolean,
|
||||
def unmanagedDependencies0(projectRef: ProjectRef, conf: Configuration, data: Settings[Scope], deps: BuildDependencies): Task[Classpath] =
|
||||
interDependencies(projectRef, deps, conf, conf, data, true, unmanagedLibs)
|
||||
def internalDependencies0(projectRef: ProjectRef, conf: Configuration, self: Configuration, data: Settings[Scope], deps: BuildDependencies): Task[Classpath] =
|
||||
interDependencies(projectRef, deps, conf, self, data, false, productsTask)
|
||||
def interDependencies(projectRef: ProjectRef, deps: BuildDependencies, conf: Configuration, self: Configuration, data: Settings[Scope], includeSelf: Boolean,
|
||||
f: (ProjectRef, String, Settings[Scope]) => Task[Classpath]): Task[Classpath] =
|
||||
{
|
||||
val visited = interSort(projectRef, project, conf, data)
|
||||
val visited = interSort(projectRef, conf, data, deps)
|
||||
val tasks = asScalaSet(new LinkedHashSet[Task[Classpath]])
|
||||
for( (dep, c) <- visited )
|
||||
if(includeSelf || (dep != projectRef) || (conf.name != c && self.name != c))
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ object Keys
|
|||
val stateBuildStructure = AttributeKey[Load.BuildStructure]("build-structure", "Data structure containing all information about the build definition.")
|
||||
val buildStructure = TaskKey[Load.BuildStructure]("build-structure", "Provides access to the build structure, settings, and streams manager.")
|
||||
val loadedBuild = SettingKey[Load.LoadedBuild]("loaded-build", "Provides access to the loaded project structure. This is the information available before settings are evaluated.")
|
||||
val buildDependencies = SettingKey[BuildDependencies]("build-dependencies", "Definitive source of inter-project dependencies for compilation and dependency management.\n\tThis is populated by default by the dependencies declared on Project instances, but may be modified.\n\tThe main restriction is that new builds may not be introduced.")
|
||||
val appConfiguration = SettingKey[xsbti.AppConfiguration]("app-configuration", "Provides access to the launched sbt configuration, including the ScalaProvider, Launcher, and GlobalLock.")
|
||||
val thisProject = SettingKey[ResolvedProject]("this-project", "Provides the current project for the referencing scope.")
|
||||
val thisProjectRef = SettingKey[ProjectRef]("this-project-ref", "Provides a fully-resolved reference to the current project for the referencing scope.")
|
||||
|
|
|
|||
Loading…
Reference in New Issue