diff --git a/main/Act.scala b/main/Act.scala index 442872e59..39c40c135 100644 --- a/main/Act.scala +++ b/main/Act.scala @@ -26,7 +26,7 @@ object Act // the index should be an aggregated index for proper tab completion def scopedKeyAggregated(current: ProjectRef, defaultConfigs: Option[ResolvedReference] => Seq[String], structure: BuildStructure): KeysParser = for(selected <- scopedKeySelected(structure.index.aggregateKeyIndex, current, defaultConfigs, structure.index.keyMap, structure.data) ) yield - Resolve.aggregateDeps(selected.key, selected.mask, structure.extra) + Aggregation.aggregate(selected.key, selected.mask, structure.extra) def scopedKeySelected(index: KeyIndex, current: ProjectRef, defaultConfigs: Option[ResolvedReference] => Seq[String], keyMap: Map[String, AttributeKey[_]], data: Settings[Scope]): Parser[ParsedKey] = diff --git a/main/Aggregation.scala b/main/Aggregation.scala index b42f45f52..831e16eff 100644 --- a/main/Aggregation.scala +++ b/main/Aggregation.scala @@ -4,7 +4,7 @@ package sbt import Project.ScopedKey - import Load.BuildStructure + import Load.{BuildStructure,LoadedBuildUnit} import Keys.{aggregate, showSuccess, showTiming, timingFormat} import sbt.complete.Parser import java.net.URI @@ -14,13 +14,6 @@ package sbt sealed trait Aggregation final object Aggregation { - def apply(dependencies: Seq[ProjectReference], transitive: Boolean = true): Aggregation = new Explicit(dependencies, transitive) - implicit def fromBoolean(b: Boolean): Aggregation = if(b) Enabled else Disabled - val Enabled = new Implicit(true) - val Disabled = new Implicit(false) - final case class Implicit(enabled: Boolean) extends Aggregation - final class Explicit(val dependencies: Seq[ProjectReference], val transitive: Boolean) extends Aggregation - final case class KeyValue[+T](key: ScopedKey[_], value: T) def printSettings[T](xs: Seq[KeyValue[T]], log: Logger)(implicit display: Show[ScopedKey[_]]) = @@ -118,4 +111,56 @@ final object Aggregation } private[this] def maps[T, S](vs: Values[T])(f: T => S): Values[S] = vs map { case KeyValue(k,v) => KeyValue(k, f(v)) } + + + def projectAggregates[Proj](proj: Option[Reference], extra: BuildUtil[Proj], reverse: Boolean): Seq[ProjectRef] = + { + val resRef = proj.map(p => extra.projectRefFor(extra.resolveRef(p))) + resRef.toList.flatMap(ref => + if(reverse) extra.aggregates.reverse(ref) else extra.aggregates.forward(ref) + ) + } + + def aggregate[T, Proj](key: ScopedKey[T], rawMask: ScopeMask, extra: BuildUtil[Proj], reverse: Boolean = false): Seq[ScopedKey[T]] = + { + val mask = rawMask.copy(project = true) + Dag.topologicalSort(key) { k => + if(reverse) + reverseAggregatedKeys(k, extra, mask) + else if(aggregationEnabled(key, extra.data)) + aggregatedKeys(k, extra, mask) + else + Nil + } + } + def reverseAggregatedKeys[T](key: ScopedKey[T], extra: BuildUtil[_], mask: ScopeMask): Seq[ScopedKey[T]] = + projectAggregates(key.scope.project.toOption, extra, reverse = true) flatMap { ref => + val toResolve = key.scope.copy(project = Select(ref)) + val resolved = Resolve(extra, Global, key.key, mask)(toResolve) + val skey = ScopedKey(resolved, key.key) + if( aggregationEnabled(skey, extra.data) ) skey :: Nil else Nil + } + + def aggregatedKeys[T](key: ScopedKey[T], extra: BuildUtil[_], mask: ScopeMask): Seq[ScopedKey[T]] = + projectAggregates(key.scope.project.toOption, extra, reverse = false) map { ref => + val toResolve = key.scope.copy(project = Select(ref)) + val resolved = Resolve(extra, Global, key.key, mask)(toResolve) + ScopedKey(resolved, key.key) + } + + def aggregationEnabled(key: ScopedKey[_], data: Settings[Scope]): Boolean = + Keys.aggregate in Scope.fillTaskAxis(key.scope, key.key) get data getOrElse true + + def relation(units: Map[URI, LoadedBuildUnit]): Relation[ProjectRef, ProjectRef] = + { + val depPairs = + for { + (uri, unit) <- units.toIterable + project <- unit.defined.values + ref = ProjectRef(uri, project.id) + agg <- project.aggregate + } yield + (ref, agg) + Relation.empty ++ depPairs + } } \ No newline at end of file diff --git a/main/BuildUtil.scala b/main/BuildUtil.scala index a358215fa..fec4d346a 100644 --- a/main/BuildUtil.scala +++ b/main/BuildUtil.scala @@ -4,6 +4,7 @@ import java.net.URI final class BuildUtil[Proj]( val keyIndex: KeyIndex, + val data: Settings[Scope], val root: URI, val rootProjectID: URI => String, val project: (URI, String) => Proj, diff --git a/main/Defaults.scala b/main/Defaults.scala index 1600e8bde..98878b4f5 100644 --- a/main/Defaults.scala +++ b/main/Defaults.scala @@ -95,7 +95,7 @@ object Defaults extends BuildCommon sbtPlugin :== false, crossPaths :== true, classpathTypes :== Set("jar", "bundle"), - aggregate :== Aggregation.Enabled, + aggregate :== true, maxErrors :== 100, showTiming :== true, timingFormat :== Aggregation.defaultFormat, diff --git a/main/KeyIndex.scala b/main/KeyIndex.scala index 2383e78b8..c3456b808 100644 --- a/main/KeyIndex.scala +++ b/main/KeyIndex.scala @@ -118,7 +118,7 @@ private final class KeyIndex0(val data: BuildIndex) extends ExtendableKeyIndex def addAggregated(scoped: ScopedKey[_], extra: BuildUtil[_]): ExtendableKeyIndex = if(validID(scoped.key.label)) { - val aggregateProjects = Resolve.aggregateDeps(scoped, ScopeMask(), extra, reverse = true) + val aggregateProjects = Aggregation.aggregate(scoped, ScopeMask(), extra, reverse = true) ((this: ExtendableKeyIndex) /: aggregateProjects)(_ add _) } else diff --git a/main/Keys.scala b/main/Keys.scala index d4bc31146..cd2ba855b 100644 --- a/main/Keys.scala +++ b/main/Keys.scala @@ -149,7 +149,7 @@ object Keys val definesClass = TaskKey[DefinesClass]("defines-class", "Internal use: provides a function that determines whether the provided file contains a given class.") val doc = TaskKey[File]("doc", "Generates API documentation.") val copyResources = TaskKey[Seq[(File,File)]]("copy-resources", "Copies resources to the output directory.") - val aggregate = SettingKey[Aggregation]("aggregate", "Configures task aggregation.") + val aggregate = SettingKey[Boolean]("aggregate", "Configures task aggregation.") // package keys val packageBin = TaskKey[File]("package-bin", "Produces a main artifact, such as a binary jar.") diff --git a/main/Load.scala b/main/Load.scala index e7b61e04f..9cdf6cb9f 100644 --- a/main/Load.scala +++ b/main/Load.scala @@ -121,7 +121,7 @@ object Load val settings = finalTransforms(buildConfigurations(loaded, getRootProject(projects), rootEval, config.injectSettings)) val delegates = config.delegates(loaded) val data = Project.makeSettings(settings, delegates, config.scopeLocal)( Project.showLoadingKey( loaded ) ) - val index = structureIndex(data, settings, loaded.extra) + val index = structureIndex(data, settings, loaded.extra(data)) val streams = mkStreams(projects, loaded.root, data) (rootEval, new BuildStructure(projects, loaded.root, settings, data, index, streams, delegates, config.scopeLocal)) } @@ -175,7 +175,7 @@ object Load { val transformed = finalTransforms(newSettings) val newData = Project.makeSettings(transformed, structure.delegates, structure.scopeLocal) - val newIndex = structureIndex(newData, transformed, index => buildUtil(structure.root, structure.units, index)) + val newIndex = structureIndex(newData, transformed, index => buildUtil(structure.root, structure.units, index, newData)) val newStreams = mkStreams(structure.units, structure.root, newData) new BuildStructure(units = structure.units, root = structure.root, settings = transformed, data = newData, index = newIndex, streams = newStreams, delegates = structure.delegates, scopeLocal = structure.scopeLocal) } @@ -547,7 +547,7 @@ object Load { checkCycles(units) def allProjectRefs: Seq[(ProjectRef, ResolvedProject)] = for( (uri, unit) <- units.toSeq; (id, proj) <- unit.defined ) yield ProjectRef(uri, id) -> proj - def extra(keyIndex: KeyIndex): BuildUtil[ResolvedProject] = buildUtil(root, units, keyIndex) + def extra(data: Settings[Scope])(keyIndex: KeyIndex): BuildUtil[ResolvedProject] = buildUtil(root, units, keyIndex, data) } def checkCycles(units: Map[URI, LoadedBuildUnit]) { @@ -588,15 +588,15 @@ object Load def allProjects(build: URI): Seq[ResolvedProject] = units(build).defined.values.toSeq def allProjectRefs: Seq[ProjectRef] = units.toSeq flatMap { case (build, unit) => refs(build, unit.defined.values.toSeq) } def allProjectRefs(build: URI): Seq[ProjectRef] = refs(build, allProjects(build)) - val extra: BuildUtil[ResolvedProject] = buildUtil(root, units, index.keyIndex) + val extra: BuildUtil[ResolvedProject] = buildUtil(root, units, index.keyIndex, data) private[this] def refs(build: URI, projects: Seq[ResolvedProject]): Seq[ProjectRef] = projects.map { p => ProjectRef(build, p.id) } } - def buildUtil(root: URI, units: Map[URI, LoadedBuildUnit], keyIndex: KeyIndex): BuildUtil[ResolvedProject] = + def buildUtil(root: URI, units: Map[URI, LoadedBuildUnit], keyIndex: KeyIndex, data: Settings[Scope]): BuildUtil[ResolvedProject] = { val getp = (build: URI, project: String) => Load.getProject(units, build, project) val configs = (_: ResolvedProject).configurations.map(c => ConfigKey(c.name)) - val aggregates = Resolve.aggregates(units) - new BuildUtil(keyIndex, root, Load getRootProject units, getp, configs, aggregates) + val aggregates = Aggregation.relation(units) + new BuildUtil(keyIndex, data, root, Load getRootProject units, getp, configs, aggregates) } final case class LoadBuildConfiguration(stagingDirectory: File, classpath: Seq[Attributed[File]], loader: ClassLoader, compilers: Compilers, evalPluginDef: (BuildStructure, State) => Seq[Attributed[File]], definesClass: DefinesClass, delegates: LoadedBuild => Scope => Seq[Scope], scopeLocal: ScopeLocal, injectSettings: InjectSettings, globalPlugin: Option[GlobalPlugin], log: Logger) { diff --git a/main/Project.scala b/main/Project.scala index f7ce6927d..b87de657f 100755 --- a/main/Project.scala +++ b/main/Project.scala @@ -85,7 +85,7 @@ final case class Extracted(structure: BuildStructure, session: SessionSettings, def runAggregated[T](key: TaskKey[T], state: State): State = { val rkey = resolve(key.scopedKey) - val keys = Resolve.aggregateDeps(rkey, ScopeMask(), structure.extra) + val keys = Aggregation.aggregate(rkey, ScopeMask(), structure.extra) val tasks = Act.keyValues(structure)(keys) Aggregation.runTasks(state, structure, tasks, Aggregation.Dummies(KNil, HNil), show = false )(showKey) } diff --git a/main/Resolve.scala b/main/Resolve.scala index de1c0709c..712f9a49f 100644 --- a/main/Resolve.scala +++ b/main/Resolve.scala @@ -1,7 +1,6 @@ package sbt import java.net.URI - import Load.LoadedBuildUnit object Resolve { @@ -43,42 +42,4 @@ object Resolve val config: ScopeAxis[ConfigKey] = (Global +: projectConfigs) find definesKey getOrElse Global scope.copy(config = config) } - - import Load.BuildStructure - import Project.ScopedKey - - def projectAggregate[Proj](proj: Option[Reference], extra: BuildUtil[Proj], reverse: Boolean): Seq[ProjectRef] = - { - val resRef = proj.map(p => extra.projectRefFor(extra.resolveRef(p))) - resRef.toList.flatMap(ref => - if(reverse) extra.aggregates.reverse(ref) else extra.aggregates.forward(ref) - ) - } - - def aggregateDeps[T, Proj](key: ScopedKey[T], rawMask: ScopeMask, extra: BuildUtil[Proj], reverse: Boolean = false): Seq[ScopedKey[T]] = - { - val mask = rawMask.copy(project = true) - Dag.topologicalSort(key) { k => - val kref = k.scope.project - for( ref <- projectAggregate(kref.toOption, extra, reverse)) yield - { - val toResolve = k.scope.copy(project = Select(ref)) - val resolved = apply(extra, Global, k.key, mask)(toResolve) - ScopedKey(resolved, k.key) - } - } - } - - def aggregates(units: Map[URI, LoadedBuildUnit]): Relation[ProjectRef, ProjectRef] = - { - val depPairs = - for { - (uri, unit) <- units.toIterable - project <- unit.defined.values - ref = ProjectRef(uri, project.id) - agg <- project.aggregate - } yield - (ref, agg) - Relation.empty ++ depPairs - } } diff --git a/main/src/test/scala/TestBuild.scala b/main/src/test/scala/TestBuild.scala index 07dd0be7e..56caee148 100644 --- a/main/src/test/scala/TestBuild.scala +++ b/main/src/test/scala/TestBuild.scala @@ -56,7 +56,7 @@ object TestBuild val extra: BuildUtil[Proj] = { val getp = (build: URI, project: String) => env.buildMap(build).projectMap(project) - new BuildUtil(keyIndex, env.root.uri, env.rootProject, getp, _.configurations.map(c => ConfigKey(c.name)), const(Nil)) + new BuildUtil(keyIndex, data, env.root.uri, env.rootProject, getp, _.configurations.map(c => ConfigKey(c.name)), Relation.empty) } lazy val allAttributeKeys: Set[AttributeKey[_]] = data.data.values.flatMap(_.keys).toSet