Skip to content

Commit

Permalink
Command to run multiple tasks concurrently: 'all a b'. Fixes #628.
Browse files Browse the repository at this point in the history
  • Loading branch information
harrah authored and eed3si9n committed Mar 21, 2014
1 parent 454fc91 commit 4640d07
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 18 deletions.
44 changes: 34 additions & 10 deletions main/src/main/scala/sbt/Act.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ package sbt
import DefaultParsers._
import Types.idFun
import java.net.URI
import CommandStrings.ShowCommand
import CommandStrings.{MultiTaskCommand, ShowCommand}

final class ParsedKey(val key: ScopedKey[_], val mask: ScopeMask)
object Act
Expand Down Expand Up @@ -234,20 +234,39 @@ object Act
val extracted = Project extract state
import extracted.{showKey, structure}
import Aggregation.evaluatingParser
showParser.flatMap { show =>
actionParser.flatMap { action =>
val akp = aggregatedKeyParser(extracted)
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) =>
evaluate(kvs) map { f => () => tail.map(reconstruct) ::: f() }
def evaluate(kvs: Seq[ScopedKey[_]]): Parser[() => State] = {
val preparedPairs = anyKeyValues(structure, kvs)
val showConfig = Aggregation.defaultShow(state, showTasks = action == ShowAction)
evaluatingParser(state, structure, showConfig)(preparedPairs) map { evaluate =>
() => {
val keyStrings = preparedPairs.map(pp => showKey(pp.key)).mkString(", ")
state.log.debug("Evaluating tasks: " + keyStrings)
evaluate()
}
}
else
akp flatMap evaluate
}
action match {
case SingleAction => akp flatMap evaluate
case ShowAction | MultiAction =>
rep1sep(akp, token(Space)).flatMap( kvss => evaluate(kvss.flatten) )
}
}
}

private[this] final class ActAction
private[this] final val ShowAction, MultiAction, SingleAction = new ActAction

private[this] def actionParser: Parser[ActAction] =
token(
((ShowCommand ^^^ ShowAction) |
(MultiTaskCommand ^^^ MultiAction) ) <~ Space
) ?? SingleAction

@deprecated("No longer used.", "0.13.2")
def showParser = token( (ShowCommand ~ Space) ^^^ true) ?? false

def scopedKeyParser(state: State): Parser[ScopedKey[_]] = scopedKeyParser(Project extract state)
def scopedKeyParser(extracted: Extracted): Parser[ScopedKey[_]] = scopedKeyParser(extracted.structure, extracted.currentRef)
def scopedKeyParser(structure: BuildStructure, currentRef: ProjectRef): Parser[ScopedKey[_]] =
Expand All @@ -265,6 +284,11 @@ object Act
keys.flatMap { key =>
getValue(structure.data, key.scope, key.key) map { value => KeyValue(key, value) }
}
private[this] def anyKeyValues(structure: BuildStructure, keys: Seq[ScopedKey[_]]): Seq[KeyValue[_]] =
keys.flatMap { key =>
getValue(structure.data, key.scope, key.key) map { value => KeyValue(key, value) }
}

private[this] def getValue[T](data: Settings[Scope], scope: Scope, key: AttributeKey[T]): Option[T] =
if(java.lang.Boolean.getBoolean("sbt.cli.nodelegation")) data.getDirect(scope, key) else data.get(scope, key)

Expand Down
8 changes: 4 additions & 4 deletions main/src/main/scala/sbt/Aggregation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ final object Aggregation
final case class KeyValue[+T](key: ScopedKey[_], value: T)

def defaultShow(state: State, showTasks: Boolean): ShowConfig = ShowConfig(settingValues = true, taskValues = showTasks, s => state.log.info(s), success = true)
def printSettings[T](xs: Seq[KeyValue[T]], print: String => Unit)(implicit display: Show[ScopedKey[_]]) =
def printSettings(xs: Seq[KeyValue[_]], print: String => Unit)(implicit display: Show[ScopedKey[_]]) =
xs match
{
case KeyValue(_,x) :: Nil => print(x.toString)
Expand All @@ -33,7 +33,7 @@ final object Aggregation
Command.applyEffect(seqParser(ps)) { ts =>
runTasks(s, structure, ts, DummyTaskMap(Nil), show)
}

@deprecated("Use `timedRun` and `showRun` directly or use `runTasks`.", "0.13.0")
def runTasksWithResult[T](s: State, structure: BuildStructure, ts: Values[Task[T]], extra: DummyTaskMap, show: ShowConfig)(implicit display: Show[ScopedKey[_]]): (State, Result[Seq[KeyValue[T]]]) =
{
Expand Down Expand Up @@ -120,7 +120,7 @@ final object Aggregation
}
}

def evaluatingParser[T](s: State, structure: BuildStructure, show: ShowConfig)(keys: Seq[KeyValue[T]])(implicit display: Show[ScopedKey[_]]): Parser[() => State] =
def evaluatingParser(s: State, structure: BuildStructure, show: ShowConfig)(keys: Seq[KeyValue[_]])(implicit display: Show[ScopedKey[_]]): Parser[() => State] =
keys.toList match
{
case Nil => failure("No such setting/task")
Expand Down Expand Up @@ -166,7 +166,7 @@ final object Aggregation
val resolved = Resolve(extra, Global, key.key, mask)(toResolve)
ScopedKey(resolved, key.key)
}

def aggregationEnabled(key: ScopedKey[_], data: Settings[Scope]): Boolean =
Keys.aggregate in Scope.fillTaskAxis(key.scope, key.key) get data getOrElse true

Expand Down
23 changes: 20 additions & 3 deletions main/src/main/scala/sbt/CommandStrings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ object CommandStrings
val ProjectCommand = "project"
val ProjectsCommand = "projects"
val ShowCommand = "show"
val MultiTaskCommand = "all"
val BootCommand = "boot"

val EvalCommand = "eval"
Expand All @@ -21,10 +22,26 @@ EvalCommand + """ <expression>
Evaluates the given Scala expression and prints the result and type."""

@deprecated("Misnomer: was only for `show`. Use showBrief.", "0.13.2")
def actBrief = showBrief
@deprecated("Misnomer: was only for `show`. Use showDetailed.", "0.13.2")
def actDetailed = showDetailed

def actHelp = showHelp ++ multiTaskHelp

def multiTaskHelp = Help(MultiTaskCommand, (multiTaskSyntax, multiTaskBrief), multiTaskDetailed)
def multiTaskDetailed =
s"""$multiTaskSyntax

$multiTaskBrief"""
def multiTaskSyntax = s"""$MultiTaskCommand <task>+"""
def multiTaskBrief = """Executes all of the specified tasks concurrently."""


def showHelp = Help(ShowCommand, (ShowCommand + " <key>", actBrief), actDetailed)
def actBrief = "Displays the result of evaluating the setting or task associated with 'key'."
def actDetailed =
s"""ShowCommand <setting>
def showBrief = "Displays the result of evaluating the setting or task associated with 'key'."
def showDetailed =
s"""$ShowCommand <setting>

Displays the value of the specified setting.

Expand Down
2 changes: 1 addition & 1 deletion main/src/main/scala/sbt/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ object BuiltinCommands
}

def act = Command.customHelp(Act.actParser, actHelp)
def actHelp = (s: State) => CommandStrings.showHelp ++ keysHelp(s)
def actHelp = (s: State) => CommandStrings.showHelp ++ CommandStrings.multiTaskHelp ++ keysHelp(s)
def keysHelp(s: State): Help =
if(Project.isProjectLoaded(s))
Help.detailOnly(taskDetail(allTaskAndSettingKeys(s)))
Expand Down
7 changes: 7 additions & 0 deletions sbt/src/sbt-test/actions/multi-task/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
lazy val a = taskKey[Unit]("a")

lazy val b = taskKey[Unit]("b")

a := IO.touch(baseDirectory.value / "a")

b := IO.touch(baseDirectory.value / "b")
3 changes: 3 additions & 0 deletions sbt/src/sbt-test/actions/multi-task/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
$ absent a b
> all a b
$ exists a b

0 comments on commit 4640d07

Please sign in to comment.