diff --git a/main/Main.scala b/main/Main.scala index d10ccc21a..e7fa785a7 100644 --- a/main/Main.scala +++ b/main/Main.scala @@ -238,13 +238,12 @@ object Commands def get = Command.single(GetCommand, getBrief, getDetailed) { (s, arg) => val extracted = Project extract s import extracted._ - val result = session.currentEval().eval(arg, srcName = "get", imports = autoImports(extracted), tpeName = Some("sbt.ScopedSetting[_]")) - val scoped = result.value.asInstanceOf[ScopedSetting[_]] + val result = session.currentEval().eval(arg, srcName = "get", imports = autoImports(extracted), tpeName = Some("sbt.Scoped")) + val scoped = result.value.asInstanceOf[Scoped] val resolve = Scope.resolveScope(Load.projectScope(curi, cid), curi, rootProject) - (structure.data.get(resolve(scoped.scope), scoped.key)) match { - case None => logger(s).error("No entry for key."); s.fail - case Some(v) => logger(s).info(v.toString); s - } + val detailString = Project.details(structure, resolve(scoped.scope), scoped.key) + logger(s).info(detailString) + s } def autoImports(extracted: Extracted): EvalImports = new EvalImports(imports(extracted), "") def imports(extracted: Extracted): Seq[(String,Int)] = diff --git a/main/Project.scala b/main/Project.scala index f799bf628..7ec1b8ae3 100644 --- a/main/Project.scala +++ b/main/Project.scala @@ -106,6 +106,24 @@ object Project extends Init[Scope] throw new Uninitialized(u.key, u.refKey, msg) } + def details(structure: Load.BuildStructure, scope: Scope, key: AttributeKey[_]): String = + { + val scoped = ScopedKey(scope,key) + val value = + (structure.data.get(scope, key)) match { + case None => "No entry for key." + case Some(v: Task[_]) => "Task" + case Some(v: InputTask[_]) => "Input task" + case Some(v) => "Value:\n\t" + v.toString + } + val definedIn = structure.data.definingScope(scope, key) match { case Some(sc) => "Provided by:\n\t" + display(scoped); case None => "" } + val cMap = compiled(structure.settings)(structure.delegates, structure.scopeLocal) + 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 } + def printScopes(label: String, scopes: Iterable[ScopedKey[_]]) = + if(scopes.isEmpty) "" else scopes.map(display).mkString(label + ":\n\t", "\n\t", "\n") + value + "\n" + definedIn + "\n" + printScopes("Dependencies", depends) + printScopes("Related", related) + } val SessionKey = AttributeKey[SessionSettings]("session-settings") val StructureKey = AttributeKey[Load.BuildStructure]("build-structure") diff --git a/main/Scope.scala b/main/Scope.scala index f0ce9c5a4..ad8739131 100644 --- a/main/Scope.scala +++ b/main/Scope.scala @@ -59,7 +59,7 @@ object Scope import scope.{project, config, task, extra} val projectPrefix = project.foldStrict(Project.display, "*", ".") val configPrefix = config.foldStrict(display, "*:", ".:") - val taskPostfix = task.foldStrict(x => (" for " + x.label) :: Nil, Nil, Nil) + val taskPostfix = task.foldStrict(x => ("for " + x.label) :: Nil, Nil, Nil) val extraPostfix = extra.foldStrict(_.entries.map( _.toString ).toList, Nil, Nil) val extras = taskPostfix ::: extraPostfix val postfix = if(extras.isEmpty) "" else extras.mkString("(", ", ", ")") diff --git a/util/collection/Settings.scala b/util/collection/Settings.scala index 8d5e37f12..b1b2b6531 100644 --- a/util/collection/Settings.scala +++ b/util/collection/Settings.scala @@ -10,6 +10,7 @@ sealed trait Settings[Scope] def data: Map[Scope, AttributeMap] def keys(scope: Scope): Set[AttributeKey[_]] def scopes: Set[Scope] + def definingScope(scope: Scope, key: AttributeKey[_]): Option[Scope] def allKeys[T](f: (Scope, AttributeKey[_]) => T): Seq[T] def get[T](scope: Scope, key: AttributeKey[T]): Option[T] def set[T](scope: Scope, key: AttributeKey[T], value: T): Settings[Scope] @@ -23,6 +24,8 @@ private final class Settings0[Scope](val data: Map[Scope, AttributeMap], val del def get[T](scope: Scope, key: AttributeKey[T]): Option[T] = delegates(scope).toStream.flatMap(sc => scopeLocal(sc, key) ).headOption + def definingScope(scope: Scope, key: AttributeKey[_]): Option[Scope] = + delegates(scope).toStream.filter(sc => scopeLocal(sc, key).isDefined ).headOption private def scopeLocal[T](scope: Scope, key: AttributeKey[T]): Option[T] = (data get scope).flatMap(_ get key) @@ -64,15 +67,20 @@ trait Init[Scope] def getValue[T](s: Settings[Scope], k: ScopedKey[T]) = s.get(k.scope, k.key).get def asFunction[T](s: Settings[Scope]): ScopedKey[T] => T = k => getValue(s, k) - def make(init: Seq[Setting[_]])(implicit delegates: Scope => Seq[Scope], scopeLocal: ScopedKey[_] => Seq[Setting[_]]): Settings[Scope] = + def compiled(init: Seq[Setting[_]])(implicit delegates: Scope => Seq[Scope], scopeLocal: ScopedKey[_] => Seq[Setting[_]]): CompiledMap = { + // prepend per-scope settings val withLocal = addLocal(init)(scopeLocal) // group by Scope/Key, dropping dead initializations val sMap: ScopedMap = grouped(withLocal) // delegate references to undefined values according to 'delegates' val dMap: ScopedMap = delegate(sMap)(delegates) // merge Seq[Setting[_]] into Compiled - val cMap: CompiledMap = compile(dMap) + compile(dMap) + } + def make(init: Seq[Setting[_]])(implicit delegates: Scope => Seq[Scope], scopeLocal: ScopedKey[_] => Seq[Setting[_]]): Settings[Scope] = + { + val cMap = compiled(init)(delegates, scopeLocal) // order the initializations. cyclic references are detected here. val ordered: Seq[Compiled] = sort(cMap) // evaluation: apply the initializations.