diff --git a/main/Build.scala b/main/Build.scala index e276c7e14b..e80f89ca63 100644 --- a/main/Build.scala +++ b/main/Build.scala @@ -167,7 +167,7 @@ object Index pairs.toMap[Task[_], ScopedKey[Task[_]]] } def allKeys(settings: Seq[Setting[_]]): Set[ScopedKey[_]] = - settings.flatMap(s => s.key +: s.dependencies).toSet + settings.flatMap(s => if(s.key.key.isLocal) Nil else s.key +: s.dependencies).filter(!_.key.isLocal).toSet def attributeKeys(settings: Settings[Scope]): Set[AttributeKey[_]] = settings.data.values.flatMap(_.keys).toSet[AttributeKey[_]] def stringToKeyMap(settings: Set[AttributeKey[_]]): Map[String, AttributeKey[_]] = diff --git a/main/Project.scala b/main/Project.scala index 73eff0c634..39f48084cf 100644 --- a/main/Project.scala +++ b/main/Project.scala @@ -264,7 +264,7 @@ object Project extends Init[Scope] with ProjectExtra case Some(sc) => "Provided by:\n\t" + Scope.display(sc, key.label) + "\n" case None => "" } - val cMap = compiled(structure.settings, actual)(structure.delegates, structure.scopeLocal, display) + val cMap = flattenLocals(compiled(structure.settings, actual)(structure.delegates, structure.scopeLocal, display)) val related = cMap.keys.filter(k => k.key == key && k.scope != scope) val depends = cMap.get(scoped) match { case Some(c) => c.dependencies.toSet; case None => Set.empty } val reverse = reverseDependencies(cMap, scoped) @@ -294,12 +294,12 @@ object Project extends Init[Scope] with ProjectExtra def relation(structure: BuildStructure, actual: Boolean)(implicit display: Show[ScopedKey[_]]) = { type Rel = Relation[ScopedKey[_], ScopedKey[_]] - val cMap = compiled(structure.settings, actual)(structure.delegates, structure.scopeLocal, display) + val cMap = flattenLocals(compiled(structure.settings, actual)(structure.delegates, structure.scopeLocal, display)) ((Relation.empty: Rel) /: cMap) { case (r, (key, value)) => r + (key, value.dependencies) } } - def reverseDependencies(cMap: CompiledMap, scoped: ScopedKey[_]): Iterable[ScopedKey[_]] = + def reverseDependencies(cMap: Map[ScopedKey[_],Flattened], scoped: ScopedKey[_]): Iterable[ScopedKey[_]] = for( (key,compiled) <- cMap; dep <- compiled.dependencies if dep == scoped) yield key object LoadAction extends Enumeration { diff --git a/main/Structure.scala b/main/Structure.scala index d28191b3de..9df3baaed9 100644 --- a/main/Structure.scala +++ b/main/Structure.scala @@ -500,6 +500,8 @@ object TaskKey def apply[T](akey: AttributeKey[Task[T]]): TaskKey[T] = new TaskKey[T](akey) + + def local[T: Manifest]: TaskKey[T] = apply[T](AttributeKey.local[Task[T]]) } object SettingKey { @@ -511,4 +513,6 @@ object SettingKey def apply[T](akey: AttributeKey[T]): SettingKey[T] = new SettingKey[T](akey) + + def local[T: Manifest]: SettingKey[T] = apply[T](AttributeKey.local[T]) } \ No newline at end of file diff --git a/util/collection/Attributes.scala b/util/collection/Attributes.scala index 6474fefb3c..2e2d647bd7 100644 --- a/util/collection/Attributes.scala +++ b/util/collection/Attributes.scala @@ -14,33 +14,46 @@ sealed trait AttributeKey[T] { def label: String def description: Option[String] def extend: Seq[AttributeKey[_]] + def isLocal: Boolean +} +private[sbt] abstract class SharedAttributeKey[T] extends AttributeKey[T] { override final def toString = label override final def hashCode = label.hashCode override final def equals(o: Any) = (this eq o.asInstanceOf[AnyRef]) || (o match { - case a: AttributeKey[t] => a.label == this.label && a.manifest == this.manifest + case a: SharedAttributeKey[t] => a.label == this.label && a.manifest == this.manifest case _ => false }) + final def isLocal: Boolean = false } object AttributeKey { - def apply[T](name: String)(implicit mf: Manifest[T]): AttributeKey[T] = new AttributeKey[T] { + def apply[T](name: String)(implicit mf: Manifest[T]): AttributeKey[T] = new SharedAttributeKey[T] { def manifest = mf def label = name def description = None def extend = Nil } - def apply[T](name: String, description0: String)(implicit mf: Manifest[T]): AttributeKey[T] = new AttributeKey[T] { + def apply[T](name: String, description0: String)(implicit mf: Manifest[T]): AttributeKey[T] = new SharedAttributeKey[T] { def manifest = mf def label = name def description = Some(description0) def extend = Nil } - def apply[T](name: String, description0: String, extend0: Seq[AttributeKey[_]])(implicit mf: Manifest[T]): AttributeKey[T] = new AttributeKey[T] { + def apply[T](name: String, description0: String, extend0: Seq[AttributeKey[_]])(implicit mf: Manifest[T]): AttributeKey[T] = new SharedAttributeKey[T] { def manifest = mf def label = name def description = Some(description0) def extend = extend0 } + private[sbt] def local[T](implicit mf: Manifest[T]): AttributeKey[T] = new AttributeKey[T] { + def manifest = mf + def label = LocalLabel + def description = None + def extend = Nil + override def toString = label + def isLocal: Boolean = true + } + private[sbt] final val LocalLabel = "$local" } trait AttributeMap diff --git a/util/collection/INode.scala b/util/collection/INode.scala index e21c0b6b71..b47031a431 100644 --- a/util/collection/INode.scala +++ b/util/collection/INode.scala @@ -55,7 +55,10 @@ abstract class EvaluateSettings[Scope] } getResults(delegates) } - private[this] def getResults(implicit delegates: Scope => Seq[Scope]) = (empty /: static.toTypedSeq) { case (ss, static.TPair(key, node)) => ss.set(key.scope, key.key, node.get) } + private[this] def getResults(implicit delegates: Scope => Seq[Scope]) = + (empty /: static.toTypedSeq) { case (ss, static.TPair(key, node)) => + if(key.key.isLocal) ss else ss.set(key.scope, key.key, node.get) + } private[this] val getValue = new (INode ~> Id) { def apply[T](node: INode[T]) = node.get } private[this] def submitEvaluate(node: INode[_]) = submit(node.evaluate()) diff --git a/util/collection/Settings.scala b/util/collection/Settings.scala index 0f4c5c83ab..ef30f854f8 100644 --- a/util/collection/Settings.scala +++ b/util/collection/Settings.scala @@ -193,6 +193,25 @@ trait Init[Scope] { override def toString = showFullKey(key) } + final class Flattened(val key: ScopedKey[_], val dependencies: Iterable[ScopedKey[_]]) + + def flattenLocals(compiled: CompiledMap): Map[ScopedKey[_],Flattened] = + { + import collection.breakOut + val locals = compiled.flatMap { case (key, comp) => if(key.key.isLocal) Seq[Compiled[_]](comp) else Nil }(breakOut) + val ordered = Dag.topologicalSort(locals)(_.dependencies.flatMap(dep => if(dep.key.isLocal) Seq[Compiled[_]](compiled(dep)) else Nil)) + def flatten(cmap: Map[ScopedKey[_],Flattened], key: ScopedKey[_], deps: Iterable[ScopedKey[_]]): Flattened = + new Flattened(key, deps.flatMap(dep => if(dep.key.isLocal) cmap(dep).dependencies else dep :: Nil)) + + val empty = Map.empty[ScopedKey[_],Flattened] + val flattenedLocals = (empty /: ordered) { (cmap, c) => cmap.updated(c.key, flatten(cmap, c.key, c.dependencies)) } + compiled.flatMap{ case (key, comp) => + if(key.key.isLocal) + Nil + else + Seq[ (ScopedKey[_], Flattened)]( (key, flatten(flattenedLocals, key, comp.dependencies)) ) + }(breakOut) + } sealed trait Initialize[T] {