From a19d5a799c2e99a6539257dc5e8fc5cf7774458c Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Thu, 4 Aug 2011 07:20:25 -0400 Subject: [PATCH] try out simplified display of scoped keys --- main/Act.scala | 5 ++-- main/Aggregation.scala | 14 +++++----- main/Build.scala | 10 +++---- main/Defaults.scala | 17 +++++++----- main/EvaluateTask.scala | 2 +- main/Load.scala | 6 ++-- main/Main.scala | 14 +++++----- main/Output.scala | 8 +++--- main/Project.scala | 51 ++++++++++++++++++++++------------ main/Scope.scala | 7 +++-- util/collection/Settings.scala | 21 +++++++------- util/collection/Show.scala | 5 ++++ 12 files changed, 93 insertions(+), 67 deletions(-) create mode 100644 util/collection/Show.scala diff --git a/main/Act.scala b/main/Act.scala index fb4d43173..9f042b2d5 100644 --- a/main/Act.scala +++ b/main/Act.scala @@ -3,7 +3,7 @@ */ package sbt - import Project.ScopedKey + import Project.{ScopedKey, showContextKey} import Keys.{sessionSettings, thisProject} import Load.BuildStructure import complete.{DefaultParsers, Parser} @@ -143,8 +143,9 @@ object Act private[this] def actParser0(state: State) = { val extracted = Project extract state + import extracted.{showKey, structure} showParser.flatMap { show => - scopedKeyParser(extracted) flatMap Aggregation.valueParser(state, extracted.structure, show) + scopedKeyParser(extracted) flatMap Aggregation.valueParser(state, structure, show) } } def showParser = token( ("show" ~ Space) ^^^ true) ?? false diff --git a/main/Aggregation.scala b/main/Aggregation.scala index 2c8aa6fbd..18fca7e7f 100644 --- a/main/Aggregation.scala +++ b/main/Aggregation.scala @@ -60,21 +60,21 @@ final object Aggregation case Some(current) => Scope.resolveBuildOnly(current, ref) } - def printSettings[T](xs: Seq[KeyValue[T]], log: Logger) = + def printSettings[T](xs: Seq[KeyValue[T]], log: Logger)(implicit display: Show[ScopedKey[_]]) = xs match { case KeyValue(_,x) :: Nil => log.info(x.toString) - case _ => xs foreach { case KeyValue(key, value) => log.info(Project.display(key) + "\n\t" + value.toString) } + case _ => xs foreach { case KeyValue(key, value) => log.info(display(key) + "\n\t" + value.toString) } } type Values[T] = Seq[KeyValue[T]] def seqParser[T](ps: Values[Parser[T]]): Parser[Seq[KeyValue[T]]] = seq(ps.map { case KeyValue(k,p) => p.map(v => KeyValue(k,v) ) }) - def applyTasks[T](s: State, structure: BuildStructure, ps: Values[Parser[Task[T]]], show: Boolean): Parser[() => State] = + def applyTasks[T](s: State, structure: BuildStructure, ps: Values[Parser[Task[T]]], show: Boolean)(implicit display: Show[ScopedKey[_]]): Parser[() => State] = Command.applyEffect(seqParser(ps)) { ts => runTasks(s, structure, ts, Dummies(KNil, HNil), show) s } - def runTasks[HL <: HList, T](s: State, structure: Load.BuildStructure, ts: Values[Task[T]], extra: Dummies[HL], show: Boolean) + def runTasks[HL <: HList, T](s: State, structure: Load.BuildStructure, ts: Values[Task[T]], extra: Dummies[HL], show: Boolean)(implicit display: Show[ScopedKey[_]]) { import EvaluateTask._ import std.TaskExtra._ @@ -129,7 +129,7 @@ final object Aggregation } final case class Dummies[HL <: HList](tasks: KList[Task,HL], values: HL) - def applyDynamicTasks[I](s: State, structure: BuildStructure, inputs: Values[InputDynamic[I]], show: Boolean): Parser[() => State] = + def applyDynamicTasks[I](s: State, structure: BuildStructure, inputs: Values[InputDynamic[I]], show: Boolean)(implicit display: Show[ScopedKey[_]]): Parser[() => State] = { val parsers = inputs.map { case KeyValue(k,t) => KeyValue(k, t parser s) } Command.applyEffect(seqParser(parsers)) { parseds => @@ -141,10 +141,10 @@ final object Aggregation s } } - def valueParser(s: State, structure: BuildStructure, show: Boolean)(key: ScopedKey[_]): Parser[() => State] = + def valueParser(s: State, structure: BuildStructure, show: Boolean)(key: ScopedKey[_])(implicit display: Show[ScopedKey[_]]): Parser[() => State] = getTasks(key, structure, true).toList match { - case Nil => failure("No such setting/task: " + (Project display key)) + case Nil => failure("No such setting/task: " + display(key)) case xs @ KeyValue(_, _: InputStatic[t]) :: _ => applyTasks(s, structure, maps(xs.asInstanceOf[Values[InputStatic[t]]])(_.parser(s)), show) case xs @ KeyValue(_, _: InputDynamic[t]) :: _ => applyDynamicTasks(s, structure, xs.asInstanceOf[Values[InputDynamic[t]]], show) case xs @ KeyValue(_, _: Task[t]) :: _ => applyTasks(s, structure, maps(xs.asInstanceOf[Values[Task[t]]])(x => success(x)), show) diff --git a/main/Build.scala b/main/Build.scala index f5273e2d5..cf77e5512 100644 --- a/main/Build.scala +++ b/main/Build.scala @@ -199,7 +199,7 @@ object Index object BuildStreams { import Load.{BuildStructure, LoadedBuildUnit} - import Project.display + import Project.displayFull import std.{TaskExtra,Transform} import Path._ import BuildPaths.outputDirectory @@ -209,7 +209,7 @@ object BuildStreams final val StreamsDirectory = "streams" def mkStreams(units: Map[URI, LoadedBuildUnit], root: URI, data: Settings[Scope]): Streams = - std.Streams( path(units, root, data), display, LogManager.construct(data) ) + std.Streams( path(units, root, data), displayFull, LogManager.construct(data) ) def path(units: Map[URI, LoadedBuildUnit], root: URI, data: Settings[Scope])(scoped: ScopedKey[_]): File = resolvePath( projectPath(units, root, scoped, data), nonProjectPath(scoped) ) @@ -221,7 +221,7 @@ object BuildStreams axis match { case Global => GlobalPath - case This => error("Unresolved This reference for " + label + " in " + display(scoped)) + case This => error("Unresolved This reference for " + label + " in " + Project.displayFull(scoped)) case Select(t) => show(t) } def nonProjectPath[T](scoped: ScopedKey[T]): Seq[String] = @@ -240,8 +240,8 @@ object BuildStreams case Global => refTarget(GlobalScope, units(root).localBase, data) / GlobalPath case Select(br @ BuildRef(uri)) => refTarget(br, units(uri).localBase, data) / BuildUnitPath case Select(pr @ ProjectRef(uri, id)) => refTarget(pr, units(uri).defined(id).base, data) - case Select(pr) => error("Unresolved project reference (" + pr + ") in " + display(scoped)) - case This => error("Unresolved project reference (This) in " + display(scoped)) + case Select(pr) => error("Unresolved project reference (" + pr + ") in " + displayFull(scoped)) + case This => error("Unresolved project reference (This) in " + displayFull(scoped)) } def refTarget(ref: ResolvedReference, fallbackBase: File, data: Settings[Scope]): File = diff --git a/main/Defaults.scala b/main/Defaults.scala index fd16f6f0b..736237a3b 100644 --- a/main/Defaults.scala +++ b/main/Defaults.scala @@ -218,7 +218,7 @@ object Defaults extends BuildCommon override def watchPaths(s: State) = EvaluateTask.evaluateTask(Project structure s, key, s, base) match { case Some(Value(ps)) => ps case Some(Inc(i)) => throw i - case None => error("key not found: " + Project.display(key)) + case None => error("key not found: " + Project.displayFull(key)) } } } @@ -244,14 +244,16 @@ object Defaults extends BuildCommon definedTests <<= TaskData.writeRelated(detectTests)(_.map(_.name).distinct) triggeredBy compile, testListeners in GlobalScope :== Nil, testOptions in GlobalScope :== Nil, - executeTests <<= (streams in test, loadedTestFrameworks, parallelExecution in test, testOptions in test, testLoader, definedTests, resolvedScoped) flatMap { - (s, frameworkMap, par, options, loader, discovered, scoped) => Tests(frameworkMap, loader, discovered, options, par, noTestsMessage(ScopedKey(scoped.scope, test.key)), s.log) + executeTests <<= (streams in test, loadedTestFrameworks, parallelExecution in test, testOptions in test, testLoader, definedTests, resolvedScoped, state) flatMap { + (s, frameworkMap, par, options, loader, discovered, scoped, st) => + implicit val display = Project.showContextKey(st) + Tests(frameworkMap, loader, discovered, options, par, noTestsMessage(ScopedKey(scoped.scope, test.key)), s.log) }, test <<= (executeTests, streams) map { (results, s) => Tests.showResults(s.log, results) }, testOnly <<= testOnlyTask ) - private[this] def noTestsMessage(scoped: ScopedKey[_]): String = - "No tests to run for " + Project.display(scoped) + private[this] def noTestsMessage(scoped: ScopedKey[_])(implicit display: Show[ScopedKey[_]]): String = + "No tests to run for " + display(scoped) lazy val TaskGlobal: Scope = ThisScope.copy(task = Global) def testTaskOptions(key: Scoped): Seq[Setting[_]] = inTask(key)( Seq( @@ -276,10 +278,11 @@ object Defaults extends BuildCommon def testOnlyTask = InputTask( TaskData(definedTests)(testOnlyParser)(Nil) ) { result => - (streams, loadedTestFrameworks, parallelExecution in testOnly, testOptions in testOnly, testLoader, definedTests, resolvedScoped, result) flatMap { - case (s, frameworks, par, opts, loader, discovered, scoped, (tests, frameworkOptions)) => + (streams, loadedTestFrameworks, parallelExecution in testOnly, testOptions in testOnly, testLoader, definedTests, resolvedScoped, result, state) flatMap { + case (s, frameworks, par, opts, loader, discovered, scoped, (tests, frameworkOptions), st) => val filter = selectedFilter(tests) val modifiedOpts = Tests.Filter(filter) +: Tests.Argument(frameworkOptions : _*) +: opts + implicit val display = Project.showContextKey(st) Tests(frameworks, loader, discovered, modifiedOpts, par, noTestsMessage(scoped), s.log) map { results => Tests.showResults(s.log, results) } diff --git a/main/EvaluateTask.scala b/main/EvaluateTask.scala index 87ca2e3ca..c4f368444 100644 --- a/main/EvaluateTask.scala +++ b/main/EvaluateTask.scala @@ -102,7 +102,7 @@ object EvaluateTask case _ => c.toString } def name(node: Task[_]): String = - node.info.name orElse transformNode(node).map(Project.display) getOrElse ("") + node.info.name orElse transformNode(node).map(Project.displayFull) getOrElse ("") def liftAnonymous: Incomplete => Incomplete = { case i @ Incomplete(node, tpe, None, causes, None) => causes.find( inc => !inc.node.isDefined && (inc.message.isDefined || inc.directCause.isDefined)) match { diff --git a/main/Load.scala b/main/Load.scala index db4cf6fa4..c595312d7 100644 --- a/main/Load.scala +++ b/main/Load.scala @@ -120,7 +120,7 @@ object Load lazy val rootEval = lazyEval(loaded.units(loaded.root).unit) val settings = finalTransforms(buildConfigurations(loaded, getRootProject(projects), rootEval, config.injectSettings)) val delegates = config.delegates(loaded) - val data = Project.makeSettings(settings, delegates, config.scopeLocal) + val data = Project.makeSettings(settings, delegates, config.scopeLocal)( Project.showLoadingKey( loaded ) ) val index = structureIndex(data, settings) val streams = mkStreams(projects, loaded.root, data) (rootEval, new BuildStructure(projects, loaded.root, settings, data, index, streams, delegates, config.scopeLocal)) @@ -150,7 +150,7 @@ object Load case resolvedScoped.key => Some(defining.asInstanceOf[T]) case parseResult.key => import std.TaskExtra._ - val getResult = InputTask.inputMap map { m => m get defining getOrElse error("No parsed value for " + Project.display(defining) + "\n" + m) } + val getResult = InputTask.inputMap map { m => m get defining getOrElse error("No parsed value for " + Project.displayFull(defining) + "\n" + m) } Some(getResult.asInstanceOf[T]) case _ => None } @@ -169,7 +169,7 @@ object Load } // Reevaluates settings after modifying them. Does not recompile or reload any build components. - def reapply(newSettings: Seq[Setting[_]], structure: BuildStructure): BuildStructure = + def reapply(newSettings: Seq[Setting[_]], structure: BuildStructure)(implicit display: Show[ScopedKey[_]]): BuildStructure = { val transformed = finalTransforms(newSettings) val newData = Project.makeSettings(transformed, structure.delegates, structure.scopeLocal) diff --git a/main/Main.scala b/main/Main.scala index 470a8a1bd..36f152aa5 100644 --- a/main/Main.scala +++ b/main/Main.scala @@ -315,7 +315,7 @@ object BuiltinCommands def reapply(newSession: SessionSettings, structure: Load.BuildStructure, s: State): State = { logger(s).info("Reapplying settings...") - val newStructure = Load.reapply(newSession.mergeSettings, structure) + val newStructure = Load.reapply(newSession.mergeSettings, structure)( Project.showContextKey(newSession, structure) ) Project.setProject(newSession, newStructure, s) } def set = Command.single(SetCommand, setBrief, setDetailed) { (s, arg) => @@ -327,14 +327,14 @@ object BuiltinCommands reapply(newSession, structure, s) } def inspect = Command(InspectCommand, inspectBrief, inspectDetailed)(inspectParser) { case (s,(actual,sk)) => - val detailString = Project.details(Project.structure(s), actual, sk.scope, sk.key) + val detailString = Project.details(Project.structure(s), actual, sk.scope, sk.key)( Project.showContextKey(s) ) logger(s).info(detailString) s } def lastGrep = Command(LastGrepCommand, lastGrepBrief, lastGrepDetailed)(lastGrepParser) { case (s, (pattern,Some(sk))) => - val (str, ref) = extractLast(s) - Output.lastGrep(sk, str, pattern) + val (str, ref, display) = extractLast(s) + Output.lastGrep(sk, str, pattern)(display) s case (s, (pattern, None)) => Output.lastGrep(CommandSupport.globalLogging(s).backing, pattern) @@ -342,7 +342,7 @@ object BuiltinCommands } def extractLast(s: State) = { val ext = Project.extract(s) - (ext.structure, Select(ext.currentRef)) + (ext.structure, Select(ext.currentRef), ext.showKey) } def inspectParser = (s: State) => token((Space ~> ("actual" ^^^ true)) ?? false) ~ spacedKeyParser(s) val spacedKeyParser = (s: State) => Act.requireSession(s, token(Space) ~> Act.scopedKeyParser(s)) @@ -350,8 +350,8 @@ object BuiltinCommands def lastGrepParser(s: State) = Act.requireSession(s, (token(Space) ~> token(NotSpace, "")) ~ optSpacedKeyParser(s)) def last = Command(LastCommand, lastBrief, lastDetailed)(optSpacedKeyParser) { case (s,Some(sk)) => - val (str, ref) = extractLast(s) - Output.last(sk, str) + val (str, ref, display) = extractLast(s) + Output.last(sk, str)(display) s case (s, None) => Output.last( CommandSupport.globalLogging(s).backing ) diff --git a/main/Output.scala b/main/Output.scala index 8946c6c58..f43a4065f 100644 --- a/main/Output.scala +++ b/main/Output.scala @@ -30,10 +30,10 @@ object Output } final val DefaultTail = "> " - def last(key: ScopedKey[_], structure: BuildStructure): Unit = printLines( flatLines(lastLines(key, structure))(idFun) ) + def last(key: ScopedKey[_], structure: BuildStructure)(implicit display: Show[ScopedKey[_]]): Unit = printLines( flatLines(lastLines(key, structure))(idFun) ) def last(file: File, tailDelim: String = DefaultTail): Unit = printLines(tailLines(file, tailDelim)) - def lastGrep(key: ScopedKey[_], structure: BuildStructure, patternString: String): Unit = + def lastGrep(key: ScopedKey[_], structure: BuildStructure, patternString: String)(implicit display: Show[ScopedKey[_]]): Unit = { val pattern = Pattern compile patternString val lines = flatLines( lastLines(key, structure) )(_ flatMap showMatches(pattern)) @@ -44,12 +44,12 @@ object Output def grep(lines: Seq[String], patternString: String): Seq[String] = lines flatMap showMatches(Pattern compile patternString) - def flatLines(outputs: Seq[KeyValue[Seq[String]]])(f: Seq[String] => Seq[String]): Seq[String] = + def flatLines(outputs: Seq[KeyValue[Seq[String]]])(f: Seq[String] => Seq[String])(implicit display: Show[ScopedKey[_]]): Seq[String] = { val single = outputs.size == 1 outputs flatMap { case KeyValue(key, lines) => val flines = f(lines) - if(!single) bold(Project.display(key)) +: flines else flines + if(!single) bold(display(key)) +: flines else flines } } def printLines(lines: Seq[String]) = lines foreach println diff --git a/main/Project.scala b/main/Project.scala index 33d50786f..219a614b1 100644 --- a/main/Project.scala +++ b/main/Project.scala @@ -61,14 +61,14 @@ sealed trait Project extends ProjectDefinition[ProjectReference] } sealed trait ResolvedProject extends ProjectDefinition[ProjectRef] -final case class Extracted(structure: BuildStructure, session: SessionSettings, currentRef: ProjectRef) +final case class Extracted(structure: BuildStructure, session: SessionSettings, currentRef: ProjectRef)(implicit val showKey: Show[ScopedKey[_]]) { def rootProject = structure.rootProject lazy val currentUnit = structure units currentRef.build lazy val currentProject = currentUnit defined currentRef.project lazy val currentLoader: ClassLoader = currentUnit.loader def get[T](key: ScopedTask[T]): Task[T] = get(key.task) - def get[T](key: ScopedSetting[T]): T = getOrError(inCurrent(key), key.key) + def get[T](key: ScopedSetting[T]) = getOrError(inCurrent(key), key.key) def getOpt[T](key: ScopedSetting[T]): Option[T] = structure.data.get(inCurrent(key), key.key) private[this] def inCurrent[T](key: ScopedSetting[T]): Scope = if(key.scope.project == This) key.scope.copy(project = Select(currentRef)) else key.scope def evalTask[T](key: ScopedTask[T], state: State): T = @@ -80,10 +80,10 @@ final case class Extracted(structure: BuildStructure, session: SessionSettings, val result = getOrError(rkey.scope, rkey.key, value) processResult(result, ConsoleLogger()) } - private def getOrError[T](scope: Scope, key: AttributeKey[_], value: Option[T]): T = - value getOrElse error(Project.display(ScopedKey(scope, key)) + " is undefined.") - private def getOrError[T](scope: Scope, key: AttributeKey[T]): T = - structure.data.get(scope, key) getOrElse error(Project.display(ScopedKey(scope, key)) + " is undefined.") + private def getOrError[T](scope: Scope, key: AttributeKey[_], value: Option[T])(implicit display: Show[ScopedKey[_]]): T = + value getOrElse error(display(ScopedKey(scope, key)) + " is undefined.") + private def getOrError[T](scope: Scope, key: AttributeKey[T])(implicit display: Show[ScopedKey[_]]): T = + structure.data.get(scope, key) getOrElse error(display(ScopedKey(scope, key)) + " is undefined.") def append(settings: Seq[Setting[_]], state: State): State = { @@ -99,6 +99,21 @@ final case class ClasspathDependency(project: ProjectReference, configuration: O object Project extends Init[Scope] with ProjectExtra { + lazy val showFullKey: Show[ScopedKey[_]] = new Show[ScopedKey[_]] { def apply(key: ScopedKey[_]) = displayFull(key) } + def showContextKey(state: State): Show[ScopedKey[_]] = + if(isProjectLoaded(state)) showContextKey( session(state), structure(state) ) else showFullKey + def showContextKey(session: SessionSettings, structure: BuildStructure): Show[ScopedKey[_]] = showRelativeKey(session.current, structure.allProjects.size > 1) + def showLoadingKey(loaded: Load.LoadedBuild): Show[ScopedKey[_]] = showRelativeKey( ProjectRef(loaded.root, loaded.units(loaded.root).rootProjects.head), loaded.allProjectRefs.size > 1 ) + def showRelativeKey(current: ProjectRef, multi: Boolean): Show[ScopedKey[_]] = new Show[ScopedKey[_]] { + def apply(key: ScopedKey[_]) = Scope.display(key.scope, key.key.label, ref => displayRelative(current, multi, ref)) + } + def displayRelative(current: ProjectRef, multi: Boolean, project: Reference): String = project match { + case BuildRef(current.build) => "{.}/" + case `current` => if(multi) current.project + "/" else "" + case ProjectRef(current.build, x) => x + "/" + case _ => display(project) + } + private abstract class ProjectDef[PR <: ProjectReference](val id: String, val base: File, aggregate0: => Seq[PR], dependencies0: => Seq[ClasspathDep[PR]], delegates0: => Seq[PR], settings0: => Seq[Setting[_]], val configurations: Seq[Configuration]) extends ProjectDefinition[PR] { @@ -130,7 +145,7 @@ object Project extends Init[Scope] with ProjectExtra def isProjectLoaded(state: State): Boolean = (state has sessionSettings) && (state has stateBuildStructure) def extract(state: State): Extracted = extract( session(state), structure(state) ) - def extract(se: SessionSettings, st: BuildStructure): Extracted = Extracted(st, se, se.current) + def extract(se: SessionSettings, st: BuildStructure): Extracted = Extracted(st, se, se.current)( showContextKey(se, st) ) def getProjectForReference(ref: Reference, structure: BuildStructure): Option[ResolvedProject] = ref match { case pr: ProjectRef => getProject(pr, structure); case _ => None } @@ -172,10 +187,10 @@ object Project extends Init[Scope] with ProjectExtra } def setCond[T](key: AttributeKey[T], vopt: Option[T], attributes: AttributeMap): AttributeMap = vopt match { case Some(v) => attributes.put(key, v); case None => attributes.remove(key) } - def makeSettings(settings: Seq[Setting[_]], delegates: Scope => Seq[Scope], scopeLocal: ScopedKey[_] => Seq[Setting[_]]) = - translateCyclic( make(settings)(delegates, scopeLocal) ) + def makeSettings(settings: Seq[Setting[_]], delegates: Scope => Seq[Scope], scopeLocal: ScopedKey[_] => Seq[Setting[_]])(implicit display: Show[ScopedKey[_]]) = + translateCyclic( make(settings)(delegates, scopeLocal, display) ) - def display(scoped: ScopedKey[_]): String = Scope.display(scoped.scope, scoped.key.label) + def displayFull(scoped: ScopedKey[_]): String = Scope.display(scoped.scope, scoped.key.label) def display(ref: Reference): String = ref match { @@ -219,7 +234,7 @@ object Project extends Init[Scope] with ProjectExtra def delegates(structure: BuildStructure, scope: Scope, key: AttributeKey[_]): Seq[ScopedKey[_]] = structure.delegates(scope).map(d => ScopedKey(d, key)) - def details(structure: BuildStructure, actual: Boolean, scope: Scope, key: AttributeKey[_]): String = + def details(structure: BuildStructure, actual: Boolean, scope: Scope, key: AttributeKey[_])(implicit display: Show[ScopedKey[_]]): String = { val scoped = ScopedKey(scope,key) lazy val clazz = key.manifest.erasure @@ -242,12 +257,12 @@ 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) + val cMap = 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) def printScopes(label: String, scopes: Iterable[ScopedKey[_]]) = - if(scopes.isEmpty) "" else scopes.map(display).mkString(label + ":\n\t", "\n\t", "\n") + if(scopes.isEmpty) "" else scopes.map(display.apply).mkString(label + ":\n\t", "\n\t", "\n") value + "\n" + description + @@ -257,22 +272,22 @@ object Project extends Init[Scope] with ProjectExtra printScopes("Delegates", delegates(structure, scope, key)) + printScopes("Related", related) } - def graphSettings(structure: BuildStructure, basedir: File) + def graphSettings(structure: BuildStructure, basedir: File)(implicit display: Show[ScopedKey[_]]) { def graph(actual: Boolean, name: String) = graphSettings(structure, actual, name, new File(basedir, name + ".dot")) graph(true, "actual_dependencies") graph(false, "declared_dependencies") } - def graphSettings(structure: BuildStructure, actual: Boolean, graphName: String, file: File) + def graphSettings(structure: BuildStructure, actual: Boolean, graphName: String, file: File)(implicit display: Show[ScopedKey[_]]) { val rel = relation(structure, actual) - val keyToString = (key: ScopedKey[_]) => Project display key + val keyToString = display.apply _ DotGraph.generateGraph(file, graphName, rel, keyToString, keyToString) } - def relation(structure: BuildStructure, actual: Boolean) = + 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) + val cMap = compiled(structure.settings, actual)(structure.delegates, structure.scopeLocal, display) ((Relation.empty: Rel) /: cMap) { case (r, (key, value)) => r + (key, value.dependencies) } diff --git a/main/Scope.scala b/main/Scope.scala index 3e422b8aa..eb5173d14 100644 --- a/main/Scope.scala +++ b/main/Scope.scala @@ -98,16 +98,17 @@ object Scope } def display(config: ConfigKey): String = config.name + ":" - def display(scope: Scope, sep: String): String = + def display(scope: Scope, sep: String): String = display(scope, sep, ref => Project.display(ref) + "/") + def display(scope: Scope, sep: String, showProject: Reference => String): String = { import scope.{project, config, task, extra} - val projectPrefix = project.foldStrict(Project.display, "*", ".") + val projectPrefix = project.foldStrict(showProject, "*/", "./") val configPrefix = config.foldStrict(display, "*:", ".:") 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("(", ", ", ")") - projectPrefix + "/" + configPrefix + sep + postfix + projectPrefix + configPrefix + sep + postfix } def parseScopedKey(command: String): (Scope, String) = diff --git a/util/collection/Settings.scala b/util/collection/Settings.scala index 418b5b737..f37302f7f 100644 --- a/util/collection/Settings.scala +++ b/util/collection/Settings.scala @@ -41,7 +41,8 @@ private final class Settings0[Scope](val data: Map[Scope, AttributeMap], val del // this trait is intended to be mixed into an object trait Init[Scope] { - def display(skey: ScopedKey[_]): String + /** The Show instance used when a detailed String needs to be generated. It is typically used when no context is available.*/ + def showFullKey: Show[ScopedKey[_]] final case class ScopedKey[T](scope: Scope, key: AttributeKey[T]) @@ -72,23 +73,23 @@ trait Init[Scope] def asTransform(s: Settings[Scope]): ScopedKey ~> Id = new (ScopedKey ~> Id) { def apply[T](k: ScopedKey[T]): T = getValue(s, k) } - def getValue[T](s: Settings[Scope], k: ScopedKey[T]) = s.get(k.scope, k.key) getOrElse error("Internal settings error: invalid reference to " + display(k)) + def getValue[T](s: Settings[Scope], k: ScopedKey[T]) = s.get(k.scope, k.key) getOrElse error("Internal settings error: invalid reference to " + showFullKey(k)) def asFunction[T](s: Settings[Scope]): ScopedKey[T] => T = k => getValue(s, k) - def compiled(init: Seq[Setting[_]], actual: Boolean = true)(implicit delegates: Scope => Seq[Scope], scopeLocal: ScopeLocal): CompiledMap = + def compiled(init: Seq[Setting[_]], actual: Boolean = true)(implicit delegates: Scope => Seq[Scope], scopeLocal: ScopeLocal, display: Show[ScopedKey[_]]): 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 = if(actual) delegate(sMap)(delegates) else sMap + val dMap: ScopedMap = if(actual) delegate(sMap)(delegates, display) else sMap // merge Seq[Setting[_]] into Compiled compile(dMap) } - def make(init: Seq[Setting[_]])(implicit delegates: Scope => Seq[Scope], scopeLocal: ScopeLocal): Settings[Scope] = + def make(init: Seq[Setting[_]])(implicit delegates: Scope => Seq[Scope], scopeLocal: ScopeLocal, display: Show[ScopedKey[_]]): Settings[Scope] = { - val cMap = compiled(init)(delegates, scopeLocal) + val cMap = compiled(init)(delegates, scopeLocal, display) // order the initializations. cyclic references are detected here. val ordered: Seq[Compiled] = sort(cMap) // evaluation: apply the initializations. @@ -116,7 +117,7 @@ trait Init[Scope] def addLocal(init: Seq[Setting[_]])(implicit scopeLocal: ScopeLocal): Seq[Setting[_]] = init.flatMap( _.dependsOn flatMap scopeLocal ) ++ init - def delegate(sMap: ScopedMap)(implicit delegates: Scope => Seq[Scope]): ScopedMap = + def delegate(sMap: ScopedMap)(implicit delegates: Scope => Seq[Scope], display: Show[ScopedKey[_]]): ScopedMap = { def refMap(refKey: ScopedKey[_], isFirst: Boolean) = new ValidateRef { def apply[T](k: ScopedKey[T]) = delegateForKey(sMap, k, delegates(k.scope), refKey, isFirst) @@ -156,7 +157,7 @@ trait Init[Scope] map.set(key.scope, key.key, value) } - def showUndefined(u: Undefined, sMap: ScopedMap, delegates: Scope => Seq[Scope]): String = + def showUndefined(u: Undefined, sMap: ScopedMap, delegates: Scope => Seq[Scope])(implicit display: Show[ScopedKey[_]]): String = { val guessed = guessIntendedScope(sMap, delegates, u.referencedKey) display(u.referencedKey) + " from " + display(u.definingKey) + guessed.map(g => "\n Did you mean " + display(g) + " ?").toList.mkString @@ -178,7 +179,7 @@ trait Init[Scope] final class Uninitialized(val undefined: Seq[Undefined], msg: String) extends Exception(msg) final class Undefined(val definingKey: ScopedKey[_], val referencedKey: ScopedKey[_]) def Undefined(definingKey: ScopedKey[_], referencedKey: ScopedKey[_]): Undefined = new Undefined(definingKey, referencedKey) - def Uninitialized(sMap: ScopedMap, delegates: Scope => Seq[Scope], keys: Seq[Undefined]): Uninitialized = + def Uninitialized(sMap: ScopedMap, delegates: Scope => Seq[Scope], keys: Seq[Undefined])(implicit display: Show[ScopedKey[_]]): Uninitialized = { assert(!keys.isEmpty) val suffix = if(keys.length > 1) "s" else "" @@ -187,7 +188,7 @@ trait Init[Scope] } final class Compiled(val key: ScopedKey[_], val dependencies: Iterable[ScopedKey[_]], val eval: Settings[Scope] => Settings[Scope]) { - override def toString = display(key) + override def toString = showFullKey(key) } sealed trait Initialize[T] diff --git a/util/collection/Show.scala b/util/collection/Show.scala new file mode 100644 index 000000000..b19a6ca2d --- /dev/null +++ b/util/collection/Show.scala @@ -0,0 +1,5 @@ +package sbt + +trait Show[T] { + def apply(t: T): String +} \ No newline at end of file