Added Extracted.runInputTask

This provides a convenience function for running an input task from the
extracted state. This is particularly useful for commands, release steps
etc that may want to run input tasks, like scripted.
This commit is contained in:
James Roper 2015-05-07 12:57:26 +10:00
parent 5c6cd94fc3
commit 3625ce5943
4 changed files with 103 additions and 0 deletions

View File

@ -3,6 +3,7 @@ package sbt
import Project._
import Scope.GlobalScope
import Def.{ ScopedKey, Setting }
import sbt.complete.Parser
import std.Transform.DummyTaskMap
final case class Extracted(structure: BuildStructure, session: SessionSettings, currentRef: ProjectRef)(implicit val showKey: Show[ScopedKey[_]]) {
@ -45,6 +46,34 @@ final case class Extracted(structure: BuildStructure, session: SessionSettings,
(newS, processResult(result, newS.log))
}
/**
* Runs the input task specified by `key`, using the `input` as the input to it, and returns the transformed State
* and the resulting value of the input task.
*
* If the project axis is not defined for the key, it is resolved to be the current project.
* Other axes are resolved to `Global` if unspecified.
*
* This method requests execution of only the given task and does not aggregate execution.
*/
def runInputTask[T](key: InputKey[T], input: String, state: State): (State, T) = {
import EvaluateTask._
val scopedKey = Scoped.scopedSetting(
Scope.resolveScope(Load.projectScope(currentRef), currentRef.build, structure.rootProject)(key.scope), key.key)
val rkey = resolve(scopedKey.scopedKey)
val inputTask = get(Scoped.scopedSetting(rkey.scope, rkey.key))
val task = Parser.parse(input, inputTask.parser(state)) match {
case Right(t) => t
case Left(msg) => sys.error(s"Invalid programmatic input:\n$msg")
}
val config = extractedTaskConfig(this, structure, state)
withStreams(structure, state) { str =>
val nv = nodeView(state, str, rkey :: Nil)
val (newS, result) = EvaluateTask.runTask(task, state, str, structure.index.triggers, config)(nv)
(newS, processResult(result, newS.log))
}
}
/**
* Runs the tasks selected by aggregating `key` and returns the transformed State.
* If the project axis is not defined for the key, it is resolved to be the current project.

View File

@ -0,0 +1,11 @@
[@jroper]: http://github.com/jroper
[2006]: https://github.com/sbt/sbt/pull/2006
### Fixes with compatibility implications
### Improvements
- Add an Extracted.runInputTask helper to assist with imperatively executing input tasks. [#2006][2006] by [@jroper][@jroper]
### Bug fixes

View File

@ -0,0 +1,54 @@
import java.util.Locale
lazy val myTask = taskKey[String]("My task")
lazy val myInputTask = inputKey[String]("My input task")
lazy val root = project in file(".")
lazy val sub = project in file("sub")
def testTask[T](name: String, expected: String, task: TaskKey[T]) = TaskKey[Unit](name) := {
val s = state.value
val e = Project.extract(s)
val (_, result) = e.runTask(task, s)
if (expected != result) {
throw sys.error(s"Error in test $name: Expected $expected but got $result")
}
}
myTask := "root"
testTask("testRunTaskRoot", "root", myTask)
myTask in Compile := "root compile"
testTask("testRunTaskRootCompile", "root compile", myTask in Compile)
myTask in sub := "sub"
testTask("testRunTaskSub", "sub", myTask in sub)
myTask in (sub, Compile) := "sub compile"
testTask("testRunTaskSubCompile", "sub compile", myTask in (sub, Compile))
def argFunction(f: String => String) = Def.inputTask {
import sbt.complete.Parsers._
f((OptSpace ~> StringBasic).parsed)
}
def testInputTask[T](name: String, expected: String, task: InputKey[T], arg: String) = TaskKey[Unit](name) := {
val s = state.value
val e = Project.extract(s)
val (_, result) = e.runInputTask(task, arg, s)
if (expected != result) {
throw sys.error(s"Error in test $name: Expected $expected but got $result")
}
}
myInputTask <<= argFunction(_.toUpperCase(Locale.ENGLISH))
testInputTask("testRunInputTaskRoot", "FOO", myInputTask, "foo")
myInputTask in Compile <<= argFunction(_.toLowerCase(Locale.ENGLISH))
testInputTask("testRunInputTaskRootCompile", "foo", myInputTask in Compile, "FOO")
myInputTask in sub <<= argFunction(_.head.toString)
testInputTask("testRunInputTaskSub", "f", myInputTask in sub, "foo")
myInputTask in (sub, Compile) <<= argFunction(_.tail)
testInputTask("testRunInputTaskSubCompile", "oo", myInputTask in (sub, Compile), "foo")

View File

@ -0,0 +1,9 @@
> testRunTaskRoot
> testRunTaskRootCompile
> testRunTaskSub
> testRunTaskSubCompile
> testRunInputTaskRoot
> testRunInputTaskRootCompile
> testRunInputTaskSub
> testRunInputTaskSubCompile