diff --git a/main/src/main/scala/sbt/Act.scala b/main/src/main/scala/sbt/Act.scala index dbe9fa62d..c72ae69fc 100644 --- a/main/src/main/scala/sbt/Act.scala +++ b/main/src/main/scala/sbt/Act.scala @@ -232,7 +232,8 @@ object Act import Aggregation.evaluatingParser showParser.flatMap { show => val akp = aggregatedKeyParser(extracted) - def evaluate(kvs: Seq[ScopedKey[T]] forSome { type T}): Parser[() => State] = evaluatingParser(state, structure, show)( keyValues(structure)(kvs) ) + def evaluate(kvs: Seq[ScopedKey[T]] forSome { type T}): Parser[() => State] = + evaluatingParser(state, structure, Aggregation.defaultShow(state, show))( keyValues(structure)(kvs) ) def reconstruct(arg: String): String = ShowCommand + " " + arg if(show) ( akp ~ (token(Space) ~> matched(akp)).* ) flatMap { case (kvs, tail) => diff --git a/main/src/main/scala/sbt/Aggregation.scala b/main/src/main/scala/sbt/Aggregation.scala index 26d206bd0..f0b048949 100644 --- a/main/src/main/scala/sbt/Aggregation.scala +++ b/main/src/main/scala/sbt/Aggregation.scala @@ -14,23 +14,25 @@ package sbt sealed trait Aggregation final object Aggregation { + final case class ShowConfig(settingValues: Boolean, taskValues: Boolean, print: String => Unit) final case class KeyValue[+T](key: ScopedKey[_], value: T) - def printSettings[T](xs: Seq[KeyValue[T]], log: Logger)(implicit display: Show[ScopedKey[_]]) = + def defaultShow(state: State, showTasks: Boolean): ShowConfig = ShowConfig(settingValues = true, taskValues = showTasks, s => state.log.info(s)) + def printSettings[T](xs: Seq[KeyValue[T]], print: String => Unit)(implicit display: Show[ScopedKey[_]]) = xs match { - case KeyValue(_,x) :: Nil => log.info(x.toString) - case _ => xs foreach { case KeyValue(key, value) => log.info(display(key) + "\n\t" + value.toString) } + case KeyValue(_,x) :: Nil => print(x.toString) + case _ => xs foreach { case KeyValue(key, value) => print(display(key) + "\n\t" + value.toString) } } type Values[T] = Seq[KeyValue[T]] type AnyKeys = Values[_] 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)(implicit display: Show[ScopedKey[_]]): Parser[() => State] = + def applyTasks[T](s: State, structure: BuildStructure, ps: Values[Parser[Task[T]]], show: ShowConfig)(implicit display: Show[ScopedKey[_]]): Parser[() => State] = Command.applyEffect(seqParser(ps)) { ts => runTasks(s, structure, ts, DummyTaskMap(Nil), show) } - def runTasksWithResult[T](s: State, structure: BuildStructure, ts: Values[Task[T]], extra: DummyTaskMap, show: Boolean)(implicit display: Show[ScopedKey[_]]): (State, Result[Seq[KeyValue[T]]]) = + def runTasksWithResult[T](s: State, structure: BuildStructure, ts: Values[Task[T]], extra: DummyTaskMap, show: ShowConfig)(implicit display: Show[ScopedKey[_]]): (State, Result[Seq[KeyValue[T]]]) = { import EvaluateTask._ import std.TaskExtra._ @@ -49,25 +51,24 @@ final object Aggregation val log = newS.log val success = result match { case Value(_) => true; case Inc(_) => false } - try { onResult(result, log) { results => if(show) printSettings(results, log) } } + try { onResult(result, log) { results => if(show.taskValues) printSettings(results, show.print) } } finally { printSuccess(start, stop, extracted, success, log) } (newS, result) } - def runTasks[HL <: HList, T](s: State, structure: BuildStructure, ts: Values[Task[T]], extra: DummyTaskMap, show: Boolean)(implicit display: Show[ScopedKey[_]]): State = { - runTasksWithResult(s, structure, ts, extra, show)._1 - } + def runTasks[HL <: HList, T](s: State, structure: BuildStructure, ts: Values[Task[T]], extra: DummyTaskMap, show: ShowConfig)(implicit display: Show[ScopedKey[_]]): State = { + runTasksWithResult(s, structure, ts, extra, show)._1 + } - def printSuccess(start: Long, stop: Long, extracted: Extracted, success: Boolean, log: Logger) + def printSuccess(start: Long, stop: Long, extracted: Extracted, success: Boolean, log: Logger) { import extracted._ - lazy val enabled = showSuccess in extracted.currentRef get extracted.structure.data getOrElse true - if(enabled) + def get(key: SettingKey[Boolean]): Boolean = key in currentRef get structure.data getOrElse true + if(get(showSuccess)) { - val timingEnabled = showTiming in currentRef get structure.data getOrElse true - if(timingEnabled) + if(get(showTiming)) { val msg = timingString(start, stop, "", structure.data, currentRef, log) if(success) log.success(msg) else log.error(msg) @@ -93,7 +94,7 @@ final object Aggregation DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM) } - def applyDynamicTasks[I](s: State, structure: BuildStructure, inputs: Values[InputTask[I]], show: Boolean)(implicit display: Show[ScopedKey[_]]): Parser[() => State] = + def applyDynamicTasks[I](s: State, structure: BuildStructure, inputs: Values[InputTask[I]], show: ShowConfig)(implicit display: Show[ScopedKey[_]]): Parser[() => State] = { val parsers = for(KeyValue(k,it) <- inputs) yield it.parser(s).map(v => KeyValue(k,v)) Command.applyEffect(seq(parsers)) { roots => @@ -102,13 +103,13 @@ final object Aggregation } } - def evaluatingParser[T](s: State, structure: BuildStructure, show: Boolean)(keys: Seq[KeyValue[T]])(implicit display: Show[ScopedKey[_]]): Parser[() => State] = + def evaluatingParser[T](s: State, structure: BuildStructure, show: ShowConfig)(keys: Seq[KeyValue[T]])(implicit display: Show[ScopedKey[_]]): Parser[() => State] = keys.toList match { case Nil => failure("No such setting/task") case xs @ KeyValue(_, _: InputTask[t]) :: _ => applyDynamicTasks(s, structure, xs.asInstanceOf[Values[InputTask[t]]], show) case xs @ KeyValue(_, _: Task[t]) :: _ => applyTasks(s, structure, maps(xs.asInstanceOf[Values[Task[t]]])(x => success(x)), show) - case xs => success(() => { printSettings(xs, s.log); s} ) + case xs => success(() => { if(show.settingValues) printSettings(xs, show.print); s} ) } private[this] def maps[T, S](vs: Values[T])(f: T => S): Values[S] = vs map { case KeyValue(k,v) => KeyValue(k, f(v)) } diff --git a/main/src/main/scala/sbt/CommandStrings.scala b/main/src/main/scala/sbt/CommandStrings.scala index 4e4f87603..0c3795ed1 100644 --- a/main/src/main/scala/sbt/CommandStrings.scala +++ b/main/src/main/scala/sbt/CommandStrings.scala @@ -57,15 +57,19 @@ LastCommand + """ See also '""" + LastGrepCommand + "'." - val exportBrief = (ExportCommand, "Displays the equivalent command line(s) for previously executed tasks.") + val exportBrief = (ExportCommand + " +", "Executes tasks and displays the equivalent command lines.") val exportDetailed = -s"""$ExportCommand + - Prints the approximate command line(s) for the previously executed tasks. +s"""$ExportCommand [--last] + + Runs the specified tasks and prints the equivalent command lines or other exportable information for those runs. - NOTE: These command lines are necessarily approximate. Usually tasks do not actually + --last + Uses information from the previous execution + + NOTES: These command lines are necessarily approximate. Usually tasks do not actually execute the command line and the actual command line program may not be installed or - on the PATH. Incremental tasks will typically show the command line for the previous - incremental run and not for a full run. + on the PATH. Incremental tasks will typically show the command line for an + incremental run and not for a full run. Many tasks have no direct command line + equivalent and will show nothing at all. """ val InspectCommand = "inspect" diff --git a/main/src/main/scala/sbt/Extracted.scala b/main/src/main/scala/sbt/Extracted.scala index e801bbda1..b42bc78e7 100644 --- a/main/src/main/scala/sbt/Extracted.scala +++ b/main/src/main/scala/sbt/Extracted.scala @@ -49,7 +49,7 @@ final case class Extracted(structure: BuildStructure, session: SessionSettings, val rkey = resolve(key.scopedKey) val keys = Aggregation.aggregate(rkey, ScopeMask(), structure.extra) val tasks = Act.keyValues(structure)(keys) - Aggregation.runTasks(state, structure, tasks, DummyTaskMap(Nil), show = false )(showKey) + Aggregation.runTasks(state, structure, tasks, DummyTaskMap(Nil), show = Aggregation.defaultShow(state,false) )(showKey) } private[this] def resolve[T](key: ScopedKey[T]): ScopedKey[T] = diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index a1399a3d8..9fc48f551 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -295,8 +295,28 @@ object BuiltinCommands val spacedKeyParser = (s: State) => Act.requireSession(s, token(Space) ~> Act.scopedKeyParser(s)) val spacedAggregatedParser = (s: State) => Act.requireSession(s, token(Space) ~> Act.aggregatedKeyParser(s)) - val exportParser: State => Parser[AnyKeys] = (s: State) => spacedAggregatedParser(s).map(x => Act.keyValues(s)(x) ) - val aggregatedKeyValueParser: State => Parser[Option[AnyKeys]] = s => exportParser(s).? + val aggregatedKeyValueParser: State => Parser[Option[AnyKeys]] = (s: State) => spacedAggregatedParser(s).map(x => Act.keyValues(s)(x) ).? + + val exportParser: State => Parser[() => State] = (s: State) => Act.requireSession(s, token(Space) ~> exportParser0(s)) + private[sbt] def exportParser0(s: State): Parser[() => State] = + { + val extracted = Project extract s + import extracted.{showKey, structure} + val keysParser = token(flag("--last" <~ Space)) ~ Act.aggregatedKeyParser(extracted) + val show = Aggregation.ShowConfig(settingValues = true, taskValues = false, print = println _) + for { + lastOnly_keys <- keysParser + kvs = Act.keyValues(structure)(lastOnly_keys._2) + f <- if(lastOnly_keys._1) success(() => s) else Aggregation.evaluatingParser(s, structure, show)(kvs) + } yield () => { + def export0(s: State): State = lastImpl(s, kvs, Some("export")) + val newS = try f() catch { case e: Exception => + try export0(s) + finally { throw e } + } + export0(newS) + } + } def lastGrepParser(s: State) = Act.requireSession(s, (token(Space) ~> token(NotSpace, "")) ~ aggregatedKeyValueParser(s)) def last = Command(LastCommand, lastBrief, lastDetailed)(aggregatedKeyValueParser) { @@ -306,9 +326,8 @@ object BuiltinCommands Output.last( logFile, printLast(s) ) keepLastLog(s) } - def export = Command(ExportCommand, exportBrief, exportDetailed)(exportParser) { (s, sks) => - lastImpl(s, sks, Some("export")) - } + def export = Command(ExportCommand, exportBrief, exportDetailed)(exportParser)( (s,f) => f() ) + private[this] def lastImpl(s: State, sks: AnyKeys, sid: Option[String]): State = { val (str, ref, display) = extractLast(s)