try out simplified display of scoped keys

This commit is contained in:
Mark Harrah 2011-08-04 07:20:25 -04:00
parent 70113c88fa
commit a19d5a799c
12 changed files with 93 additions and 67 deletions

View File

@ -3,7 +3,7 @@
*/ */
package sbt package sbt
import Project.ScopedKey import Project.{ScopedKey, showContextKey}
import Keys.{sessionSettings, thisProject} import Keys.{sessionSettings, thisProject}
import Load.BuildStructure import Load.BuildStructure
import complete.{DefaultParsers, Parser} import complete.{DefaultParsers, Parser}
@ -143,8 +143,9 @@ object Act
private[this] def actParser0(state: State) = private[this] def actParser0(state: State) =
{ {
val extracted = Project extract state val extracted = Project extract state
import extracted.{showKey, structure}
showParser.flatMap { show => 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 def showParser = token( ("show" ~ Space) ^^^ true) ?? false

View File

@ -60,21 +60,21 @@ final object Aggregation
case Some(current) => Scope.resolveBuildOnly(current, ref) 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 xs match
{ {
case KeyValue(_,x) :: Nil => log.info(x.toString) 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]] 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 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 => Command.applyEffect(seqParser(ps)) { ts =>
runTasks(s, structure, ts, Dummies(KNil, HNil), show) runTasks(s, structure, ts, Dummies(KNil, HNil), show)
s 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 EvaluateTask._
import std.TaskExtra._ import std.TaskExtra._
@ -129,7 +129,7 @@ final object Aggregation
} }
final case class Dummies[HL <: HList](tasks: KList[Task,HL], values: HL) 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) } val parsers = inputs.map { case KeyValue(k,t) => KeyValue(k, t parser s) }
Command.applyEffect(seqParser(parsers)) { parseds => Command.applyEffect(seqParser(parsers)) { parseds =>
@ -141,10 +141,10 @@ final object Aggregation
s 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 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(_, _: 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(_, _: 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) case xs @ KeyValue(_, _: Task[t]) :: _ => applyTasks(s, structure, maps(xs.asInstanceOf[Values[Task[t]]])(x => success(x)), show)

View File

@ -199,7 +199,7 @@ object Index
object BuildStreams object BuildStreams
{ {
import Load.{BuildStructure, LoadedBuildUnit} import Load.{BuildStructure, LoadedBuildUnit}
import Project.display import Project.displayFull
import std.{TaskExtra,Transform} import std.{TaskExtra,Transform}
import Path._ import Path._
import BuildPaths.outputDirectory import BuildPaths.outputDirectory
@ -209,7 +209,7 @@ object BuildStreams
final val StreamsDirectory = "streams" final val StreamsDirectory = "streams"
def mkStreams(units: Map[URI, LoadedBuildUnit], root: URI, data: Settings[Scope]): 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 = def path(units: Map[URI, LoadedBuildUnit], root: URI, data: Settings[Scope])(scoped: ScopedKey[_]): File =
resolvePath( projectPath(units, root, scoped, data), nonProjectPath(scoped) ) resolvePath( projectPath(units, root, scoped, data), nonProjectPath(scoped) )
@ -221,7 +221,7 @@ object BuildStreams
axis match axis match
{ {
case Global => GlobalPath 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) case Select(t) => show(t)
} }
def nonProjectPath[T](scoped: ScopedKey[T]): Seq[String] = def nonProjectPath[T](scoped: ScopedKey[T]): Seq[String] =
@ -240,8 +240,8 @@ object BuildStreams
case Global => refTarget(GlobalScope, units(root).localBase, data) / GlobalPath case Global => refTarget(GlobalScope, units(root).localBase, data) / GlobalPath
case Select(br @ BuildRef(uri)) => refTarget(br, units(uri).localBase, data) / BuildUnitPath 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 @ ProjectRef(uri, id)) => refTarget(pr, units(uri).defined(id).base, data)
case Select(pr) => error("Unresolved project reference (" + pr + ") in " + display(scoped)) case Select(pr) => error("Unresolved project reference (" + pr + ") in " + displayFull(scoped))
case This => error("Unresolved project reference (This) in " + display(scoped)) case This => error("Unresolved project reference (This) in " + displayFull(scoped))
} }
def refTarget(ref: ResolvedReference, fallbackBase: File, data: Settings[Scope]): File = def refTarget(ref: ResolvedReference, fallbackBase: File, data: Settings[Scope]): File =

View File

@ -218,7 +218,7 @@ object Defaults extends BuildCommon
override def watchPaths(s: State) = EvaluateTask.evaluateTask(Project structure s, key, s, base) match { override def watchPaths(s: State) = EvaluateTask.evaluateTask(Project structure s, key, s, base) match {
case Some(Value(ps)) => ps case Some(Value(ps)) => ps
case Some(Inc(i)) => throw i 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, definedTests <<= TaskData.writeRelated(detectTests)(_.map(_.name).distinct) triggeredBy compile,
testListeners in GlobalScope :== Nil, testListeners in GlobalScope :== Nil,
testOptions in GlobalScope :== Nil, testOptions in GlobalScope :== Nil,
executeTests <<= (streams in test, loadedTestFrameworks, parallelExecution in test, testOptions in test, testLoader, definedTests, resolvedScoped) flatMap { executeTests <<= (streams in test, loadedTestFrameworks, parallelExecution in test, testOptions in test, testLoader, definedTests, resolvedScoped, state) flatMap {
(s, frameworkMap, par, options, loader, discovered, scoped) => Tests(frameworkMap, loader, discovered, options, par, noTestsMessage(ScopedKey(scoped.scope, test.key)), s.log) (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) }, test <<= (executeTests, streams) map { (results, s) => Tests.showResults(s.log, results) },
testOnly <<= testOnlyTask testOnly <<= testOnlyTask
) )
private[this] def noTestsMessage(scoped: ScopedKey[_]): String = private[this] def noTestsMessage(scoped: ScopedKey[_])(implicit display: Show[ScopedKey[_]]): String =
"No tests to run for " + Project.display(scoped) "No tests to run for " + display(scoped)
lazy val TaskGlobal: Scope = ThisScope.copy(task = Global) lazy val TaskGlobal: Scope = ThisScope.copy(task = Global)
def testTaskOptions(key: Scoped): Seq[Setting[_]] = inTask(key)( Seq( def testTaskOptions(key: Scoped): Seq[Setting[_]] = inTask(key)( Seq(
@ -276,10 +278,11 @@ object Defaults extends BuildCommon
def testOnlyTask = def testOnlyTask =
InputTask( TaskData(definedTests)(testOnlyParser)(Nil) ) { result => InputTask( TaskData(definedTests)(testOnlyParser)(Nil) ) { result =>
(streams, loadedTestFrameworks, parallelExecution in testOnly, testOptions in testOnly, testLoader, definedTests, resolvedScoped, result) flatMap { (streams, loadedTestFrameworks, parallelExecution in testOnly, testOptions in testOnly, testLoader, definedTests, resolvedScoped, result, state) flatMap {
case (s, frameworks, par, opts, loader, discovered, scoped, (tests, frameworkOptions)) => case (s, frameworks, par, opts, loader, discovered, scoped, (tests, frameworkOptions), st) =>
val filter = selectedFilter(tests) val filter = selectedFilter(tests)
val modifiedOpts = Tests.Filter(filter) +: Tests.Argument(frameworkOptions : _*) +: opts 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(frameworks, loader, discovered, modifiedOpts, par, noTestsMessage(scoped), s.log) map { results =>
Tests.showResults(s.log, results) Tests.showResults(s.log, results)
} }

View File

@ -102,7 +102,7 @@ object EvaluateTask
case _ => c.toString case _ => c.toString
} }
def name(node: Task[_]): String = def name(node: Task[_]): String =
node.info.name orElse transformNode(node).map(Project.display) getOrElse ("<anon-" + System.identityHashCode(node).toHexString + ">") node.info.name orElse transformNode(node).map(Project.displayFull) getOrElse ("<anon-" + System.identityHashCode(node).toHexString + ">")
def liftAnonymous: Incomplete => Incomplete = { def liftAnonymous: Incomplete => Incomplete = {
case i @ Incomplete(node, tpe, None, causes, None) => case i @ Incomplete(node, tpe, None, causes, None) =>
causes.find( inc => !inc.node.isDefined && (inc.message.isDefined || inc.directCause.isDefined)) match { causes.find( inc => !inc.node.isDefined && (inc.message.isDefined || inc.directCause.isDefined)) match {

View File

@ -120,7 +120,7 @@ object Load
lazy val rootEval = lazyEval(loaded.units(loaded.root).unit) lazy val rootEval = lazyEval(loaded.units(loaded.root).unit)
val settings = finalTransforms(buildConfigurations(loaded, getRootProject(projects), rootEval, config.injectSettings)) val settings = finalTransforms(buildConfigurations(loaded, getRootProject(projects), rootEval, config.injectSettings))
val delegates = config.delegates(loaded) 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 index = structureIndex(data, settings)
val streams = mkStreams(projects, loaded.root, data) val streams = mkStreams(projects, loaded.root, data)
(rootEval, new BuildStructure(projects, loaded.root, settings, data, index, streams, delegates, config.scopeLocal)) (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 resolvedScoped.key => Some(defining.asInstanceOf[T])
case parseResult.key => case parseResult.key =>
import std.TaskExtra._ 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]) Some(getResult.asInstanceOf[T])
case _ => None case _ => None
} }
@ -169,7 +169,7 @@ object Load
} }
// Reevaluates settings after modifying them. Does not recompile or reload any build components. // 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 transformed = finalTransforms(newSettings)
val newData = Project.makeSettings(transformed, structure.delegates, structure.scopeLocal) val newData = Project.makeSettings(transformed, structure.delegates, structure.scopeLocal)

View File

@ -315,7 +315,7 @@ object BuiltinCommands
def reapply(newSession: SessionSettings, structure: Load.BuildStructure, s: State): State = def reapply(newSession: SessionSettings, structure: Load.BuildStructure, s: State): State =
{ {
logger(s).info("Reapplying settings...") 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) Project.setProject(newSession, newStructure, s)
} }
def set = Command.single(SetCommand, setBrief, setDetailed) { (s, arg) => def set = Command.single(SetCommand, setBrief, setDetailed) { (s, arg) =>
@ -327,14 +327,14 @@ object BuiltinCommands
reapply(newSession, structure, s) reapply(newSession, structure, s)
} }
def inspect = Command(InspectCommand, inspectBrief, inspectDetailed)(inspectParser) { case (s,(actual,sk)) => 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) logger(s).info(detailString)
s s
} }
def lastGrep = Command(LastGrepCommand, lastGrepBrief, lastGrepDetailed)(lastGrepParser) { def lastGrep = Command(LastGrepCommand, lastGrepBrief, lastGrepDetailed)(lastGrepParser) {
case (s, (pattern,Some(sk))) => case (s, (pattern,Some(sk))) =>
val (str, ref) = extractLast(s) val (str, ref, display) = extractLast(s)
Output.lastGrep(sk, str, pattern) Output.lastGrep(sk, str, pattern)(display)
s s
case (s, (pattern, None)) => case (s, (pattern, None)) =>
Output.lastGrep(CommandSupport.globalLogging(s).backing, pattern) Output.lastGrep(CommandSupport.globalLogging(s).backing, pattern)
@ -342,7 +342,7 @@ object BuiltinCommands
} }
def extractLast(s: State) = { def extractLast(s: State) = {
val ext = Project.extract(s) 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) def inspectParser = (s: State) => token((Space ~> ("actual" ^^^ true)) ?? false) ~ spacedKeyParser(s)
val spacedKeyParser = (s: State) => Act.requireSession(s, token(Space) ~> Act.scopedKeyParser(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, "<pattern>")) ~ optSpacedKeyParser(s)) def lastGrepParser(s: State) = Act.requireSession(s, (token(Space) ~> token(NotSpace, "<pattern>")) ~ optSpacedKeyParser(s))
def last = Command(LastCommand, lastBrief, lastDetailed)(optSpacedKeyParser) { def last = Command(LastCommand, lastBrief, lastDetailed)(optSpacedKeyParser) {
case (s,Some(sk)) => case (s,Some(sk)) =>
val (str, ref) = extractLast(s) val (str, ref, display) = extractLast(s)
Output.last(sk, str) Output.last(sk, str)(display)
s s
case (s, None) => case (s, None) =>
Output.last( CommandSupport.globalLogging(s).backing ) Output.last( CommandSupport.globalLogging(s).backing )

View File

@ -30,10 +30,10 @@ object Output
} }
final val DefaultTail = "> " 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 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 pattern = Pattern compile patternString
val lines = flatLines( lastLines(key, structure) )(_ flatMap showMatches(pattern)) val lines = flatLines( lastLines(key, structure) )(_ flatMap showMatches(pattern))
@ -44,12 +44,12 @@ object Output
def grep(lines: Seq[String], patternString: String): Seq[String] = def grep(lines: Seq[String], patternString: String): Seq[String] =
lines flatMap showMatches(Pattern compile patternString) 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 val single = outputs.size == 1
outputs flatMap { case KeyValue(key, lines) => outputs flatMap { case KeyValue(key, lines) =>
val flines = f(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 def printLines(lines: Seq[String]) = lines foreach println

View File

@ -61,14 +61,14 @@ sealed trait Project extends ProjectDefinition[ProjectReference]
} }
sealed trait ResolvedProject extends ProjectDefinition[ProjectRef] 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 def rootProject = structure.rootProject
lazy val currentUnit = structure units currentRef.build lazy val currentUnit = structure units currentRef.build
lazy val currentProject = currentUnit defined currentRef.project lazy val currentProject = currentUnit defined currentRef.project
lazy val currentLoader: ClassLoader = currentUnit.loader lazy val currentLoader: ClassLoader = currentUnit.loader
def get[T](key: ScopedTask[T]): Task[T] = get(key.task) 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) 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 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 = 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) val result = getOrError(rkey.scope, rkey.key, value)
processResult(result, ConsoleLogger()) processResult(result, ConsoleLogger())
} }
private def getOrError[T](scope: Scope, key: AttributeKey[_], value: Option[T]): T = private def getOrError[T](scope: Scope, key: AttributeKey[_], value: Option[T])(implicit display: Show[ScopedKey[_]]): T =
value getOrElse error(Project.display(ScopedKey(scope, key)) + " is undefined.") value getOrElse error(display(ScopedKey(scope, key)) + " is undefined.")
private def getOrError[T](scope: Scope, key: AttributeKey[T]): T = private def getOrError[T](scope: Scope, key: AttributeKey[T])(implicit display: Show[ScopedKey[_]]): T =
structure.data.get(scope, key) getOrElse error(Project.display(ScopedKey(scope, key)) + " is undefined.") structure.data.get(scope, key) getOrElse error(display(ScopedKey(scope, key)) + " is undefined.")
def append(settings: Seq[Setting[_]], state: State): State = 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 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], 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] 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 isProjectLoaded(state: State): Boolean = (state has sessionSettings) && (state has stateBuildStructure)
def extract(state: State): Extracted = extract( session(state), structure(state) ) 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] = def getProjectForReference(ref: Reference, structure: BuildStructure): Option[ResolvedProject] =
ref match { case pr: ProjectRef => getProject(pr, structure); case _ => None } 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 = 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) } 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[_]]) = def makeSettings(settings: Seq[Setting[_]], delegates: Scope => Seq[Scope], scopeLocal: ScopedKey[_] => Seq[Setting[_]])(implicit display: Show[ScopedKey[_]]) =
translateCyclic( make(settings)(delegates, scopeLocal) ) 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 = def display(ref: Reference): String =
ref match ref match
{ {
@ -219,7 +234,7 @@ object Project extends Init[Scope] with ProjectExtra
def delegates(structure: BuildStructure, scope: Scope, key: AttributeKey[_]): Seq[ScopedKey[_]] = def delegates(structure: BuildStructure, scope: Scope, key: AttributeKey[_]): Seq[ScopedKey[_]] =
structure.delegates(scope).map(d => ScopedKey(d, key)) 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) val scoped = ScopedKey(scope,key)
lazy val clazz = key.manifest.erasure 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 Some(sc) => "Provided by:\n\t" + Scope.display(sc, key.label) + "\n"
case None => "" 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 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 depends = cMap.get(scoped) match { case Some(c) => c.dependencies.toSet; case None => Set.empty }
val reverse = reverseDependencies(cMap, scoped) val reverse = reverseDependencies(cMap, scoped)
def printScopes(label: String, scopes: Iterable[ScopedKey[_]]) = 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" + value + "\n" +
description + description +
@ -257,22 +272,22 @@ object Project extends Init[Scope] with ProjectExtra
printScopes("Delegates", delegates(structure, scope, key)) + printScopes("Delegates", delegates(structure, scope, key)) +
printScopes("Related", related) 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")) def graph(actual: Boolean, name: String) = graphSettings(structure, actual, name, new File(basedir, name + ".dot"))
graph(true, "actual_dependencies") graph(true, "actual_dependencies")
graph(false, "declared_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 rel = relation(structure, actual)
val keyToString = (key: ScopedKey[_]) => Project display key val keyToString = display.apply _
DotGraph.generateGraph(file, graphName, rel, keyToString, keyToString) 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[_]] 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)) => ((Relation.empty: Rel) /: cMap) { case (r, (key, value)) =>
r + (key, value.dependencies) r + (key, value.dependencies)
} }

View File

@ -98,16 +98,17 @@ object Scope
} }
def display(config: ConfigKey): String = config.name + ":" 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} import scope.{project, config, task, extra}
val projectPrefix = project.foldStrict(Project.display, "*", ".") val projectPrefix = project.foldStrict(showProject, "*/", "./")
val configPrefix = config.foldStrict(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 extraPostfix = extra.foldStrict(_.entries.map( _.toString ).toList, Nil, Nil)
val extras = taskPostfix ::: extraPostfix val extras = taskPostfix ::: extraPostfix
val postfix = if(extras.isEmpty) "" else extras.mkString("(", ", ", ")") val postfix = if(extras.isEmpty) "" else extras.mkString("(", ", ", ")")
projectPrefix + "/" + configPrefix + sep + postfix projectPrefix + configPrefix + sep + postfix
} }
def parseScopedKey(command: String): (Scope, String) = def parseScopedKey(command: String): (Scope, String) =

View File

@ -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 // this trait is intended to be mixed into an object
trait Init[Scope] 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]) 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 asTransform(s: Settings[Scope]): ScopedKey ~> Id = new (ScopedKey ~> Id) {
def apply[T](k: ScopedKey[T]): T = getValue(s, k) 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 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 // prepend per-scope settings
val withLocal = addLocal(init)(scopeLocal) val withLocal = addLocal(init)(scopeLocal)
// group by Scope/Key, dropping dead initializations // group by Scope/Key, dropping dead initializations
val sMap: ScopedMap = grouped(withLocal) val sMap: ScopedMap = grouped(withLocal)
// delegate references to undefined values according to 'delegates' // 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 // merge Seq[Setting[_]] into Compiled
compile(dMap) 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. // order the initializations. cyclic references are detected here.
val ordered: Seq[Compiled] = sort(cMap) val ordered: Seq[Compiled] = sort(cMap)
// evaluation: apply the initializations. // evaluation: apply the initializations.
@ -116,7 +117,7 @@ trait Init[Scope]
def addLocal(init: Seq[Setting[_]])(implicit scopeLocal: ScopeLocal): Seq[Setting[_]] = def addLocal(init: Seq[Setting[_]])(implicit scopeLocal: ScopeLocal): Seq[Setting[_]] =
init.flatMap( _.dependsOn flatMap scopeLocal ) ++ init 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]) = def refMap(refKey: ScopedKey[_], isFirst: Boolean) = new ValidateRef { def apply[T](k: ScopedKey[T]) =
delegateForKey(sMap, k, delegates(k.scope), refKey, isFirst) delegateForKey(sMap, k, delegates(k.scope), refKey, isFirst)
@ -156,7 +157,7 @@ trait Init[Scope]
map.set(key.scope, key.key, value) 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) 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 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 Uninitialized(val undefined: Seq[Undefined], msg: String) extends Exception(msg)
final class Undefined(val definingKey: ScopedKey[_], val referencedKey: ScopedKey[_]) final class Undefined(val definingKey: ScopedKey[_], val referencedKey: ScopedKey[_])
def Undefined(definingKey: ScopedKey[_], referencedKey: ScopedKey[_]): Undefined = new Undefined(definingKey, referencedKey) 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) assert(!keys.isEmpty)
val suffix = if(keys.length > 1) "s" else "" 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]) 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] sealed trait Initialize[T]

View File

@ -0,0 +1,5 @@
package sbt
trait Show[T] {
def apply(t: T): String
}