mirror of https://github.com/sbt/sbt.git
New method `toTask` on `Initialize[InputTask[T]]` to apply the full input and get a plain task out.
This commit is contained in:
parent
e3e95f902d
commit
9dcb8727d8
|
|
@ -4,6 +4,7 @@ package sbt
|
|||
import complete.Parser
|
||||
import java.io.File
|
||||
import Scope.ThisScope
|
||||
import KeyRanks.{DTask, Invisible}
|
||||
|
||||
/** A concrete settings system that uses `sbt.Scope` for the scope type. */
|
||||
object Def extends Init[Scope] with TaskMacroExtra
|
||||
|
|
@ -87,6 +88,17 @@ object Def extends Init[Scope] with TaskMacroExtra
|
|||
def settingKey[T](description: String): SettingKey[T] = macro std.KeyMacro.settingKeyImpl[T]
|
||||
def taskKey[T](description: String): TaskKey[T] = macro std.KeyMacro.taskKeyImpl[T]
|
||||
def inputKey[T](description: String): InputKey[T] = macro std.KeyMacro.inputKeyImpl[T]
|
||||
|
||||
private[sbt] def dummy[T: Manifest](name: String, description: String): (TaskKey[T], Task[T]) = (TaskKey[T](name, description, DTask), dummyTask(name))
|
||||
private[sbt] def dummyTask[T](name: String): Task[T] =
|
||||
{
|
||||
import std.TaskExtra.{task => newTask, _}
|
||||
val base: Task[T] = newTask( sys.error("Dummy task '" + name + "' did not get converted to a full task.") ) named name
|
||||
base.copy(info = base.info.set(isDummyTask, true))
|
||||
}
|
||||
private[sbt] def isDummy(t: Task[_]): Boolean = t.info.attributes.get(isDummyTask) getOrElse false
|
||||
private[sbt] val isDummyTask = AttributeKey[Boolean]("is-dummy-task", "Internal: used to identify dummy tasks. sbt injects values for these tasks at the start of task execution.", Invisible)
|
||||
private[sbt] val (stateKey, dummyState) = dummy[State]("state", "Current build state.")
|
||||
}
|
||||
// these need to be mixed into the sbt package object because the target doesn't involve Initialize or anything in Def
|
||||
trait TaskMacroExtra
|
||||
|
|
|
|||
|
|
@ -30,6 +30,20 @@ object InputTask
|
|||
implicit class InitializeInput[T](i: Initialize[InputTask[T]]) {
|
||||
def partialInput(in: String): Initialize[InputTask[T]] = i(_ partialInput in)
|
||||
def fullInput(in: String): Initialize[InputTask[T]] = i(_ fullInput in)
|
||||
|
||||
import std.FullInstance._
|
||||
def toTask(in: String): Initialize[Task[T]] = flatten(
|
||||
(Def.stateKey zipWith i) ( (sTask, it) =>
|
||||
sTask map ( s =>
|
||||
Parser.parse(in, it.parser(s)) match {
|
||||
case Right(t) => Def.value(t)
|
||||
case Left(msg) =>
|
||||
val indented = msg.lines.map(" " + _).mkString("\n")
|
||||
sys.error(s"Invalid programmatic input:\n$indented")
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
implicit def inputTaskParsed[T](in: InputTask[T]): std.ParserInputTask[T] = ???
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
package sbt
|
||||
|
||||
import java.io.File
|
||||
import Def.{displayFull, ScopedKey, Setting}
|
||||
import Def.{displayFull, dummyState, ScopedKey, Setting}
|
||||
import Keys.{streams, Streams, TaskStreams}
|
||||
import Keys.{dummyRoots, dummyState, dummyStreamsManager, executionRoots, pluginData, streamsManager, taskDefinitionKey, transformState}
|
||||
import Keys.{dummyRoots, dummyStreamsManager, executionRoots, pluginData, streamsManager, taskDefinitionKey, transformState}
|
||||
import Project.richInitializeTask
|
||||
import Scope.{GlobalScope, ThisScope}
|
||||
import Types.const
|
||||
|
|
|
|||
|
|
@ -325,11 +325,17 @@ object Keys
|
|||
val cancelable = SettingKey[Boolean]("cancelable", "Enables (true) or disables (false) the ability to interrupt task execution with CTRL+C.", BMinusSetting)
|
||||
val settingsData = std.FullInstance.settingsData
|
||||
val streams = TaskKey[TaskStreams]("streams", "Provides streams for logging and persisting data.", DTask)
|
||||
val isDummyTask = AttributeKey[Boolean]("is-dummy-task", "Internal: used to identify dummy tasks. sbt injects values for these tasks at the start of task execution.", Invisible)
|
||||
val taskDefinitionKey = AttributeKey[ScopedKey[_]]("task-definition-key", "Internal: used to map a task back to its ScopedKey.", Invisible)
|
||||
val (executionRoots, dummyRoots)= dummy[Seq[ScopedKey[_]]]("execution-roots", "The list of root tasks for this task execution. Roots are the top-level tasks that were directly requested to be run.")
|
||||
val (state, dummyState) = dummy[State]("state", "Current build state.")
|
||||
val (streamsManager, dummyStreamsManager) = dummy[Streams]("streams-manager", "Streams manager, which provides streams for different contexts.")
|
||||
val (executionRoots, dummyRoots)= Def.dummy[Seq[ScopedKey[_]]]("execution-roots", "The list of root tasks for this task execution. Roots are the top-level tasks that were directly requested to be run.")
|
||||
|
||||
val state = Def.stateKey
|
||||
|
||||
@deprecated("Implementation detail.", "0.13.1")
|
||||
val isDummyTask = Def.isDummyTask
|
||||
@deprecated("Implementation detail.", "0.13.1")
|
||||
val dummyState = Def.dummyState
|
||||
|
||||
val (streamsManager, dummyStreamsManager) = Def.dummy[Streams]("streams-manager", "Streams manager, which provides streams for different contexts.")
|
||||
val stateStreams = AttributeKey[Streams]("streams-manager", "Streams manager, which provides streams for different contexts. Setting this on State will override the default Streams implementation.")
|
||||
val resolvedScoped = Def.resolvedScoped
|
||||
val pluginData = TaskKey[PluginData]("plugin-data", "Information from the plugin build needed in the main build definition.", DTask)
|
||||
|
|
@ -344,11 +350,10 @@ object Keys
|
|||
type Streams = std.Streams[ScopedKey[_]]
|
||||
type TaskStreams = std.TaskStreams[ScopedKey[_]]
|
||||
|
||||
def dummy[T: Manifest](name: String, description: String): (TaskKey[T], Task[T]) = (TaskKey[T](name, description, DTask), dummyTask(name))
|
||||
def dummyTask[T](name: String): Task[T] =
|
||||
{
|
||||
val base: Task[T] = task( sys.error("Dummy task '" + name + "' did not get converted to a full task.") ) named name
|
||||
base.copy(info = base.info.set(isDummyTask, true))
|
||||
}
|
||||
def isDummy(t: Task[_]): Boolean = t.info.attributes.get(isDummyTask) getOrElse false
|
||||
@deprecated("Implementation detail.", "0.13.1")
|
||||
def dummy[T: Manifest](name: String, description: String): (TaskKey[T], Task[T]) = Def.dummy(name, description)
|
||||
@deprecated("Implementation detail.", "0.13.1")
|
||||
def dummyTask[T](name: String): Task[T] = Def.dummyTask(name)
|
||||
@deprecated("Implementation detail.", "0.13.1")
|
||||
def isDummy(t: Task[_]): Boolean = Def.isDummy(t)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ package sbt
|
|||
import Compiler.{Compilers,Inputs}
|
||||
import inc.{FileValueCache, Locate}
|
||||
import Project.{inScope,makeSettings}
|
||||
import Def.{ScopedKey, ScopeLocal, Setting}
|
||||
import Def.{isDummy, ScopedKey, ScopeLocal, Setting}
|
||||
import Keys.{appConfiguration, baseDirectory, configuration, fullResolvers, fullClasspath, pluginData, streams, thisProject, thisProjectRef, update}
|
||||
import Keys.{exportedProducts, isDummy, loadedBuild, onLoadMessage, resolvedScoped, sbtPlugin, scalacOptions, taskDefinitionKey}
|
||||
import Keys.{exportedProducts, loadedBuild, onLoadMessage, resolvedScoped, sbtPlugin, scalacOptions, taskDefinitionKey}
|
||||
import tools.nsc.reporters.ConsoleReporter
|
||||
import Build.analyzed
|
||||
import Attributed.data
|
||||
|
|
|
|||
|
|
@ -194,6 +194,7 @@ Preapplying input
|
|||
=================
|
||||
|
||||
Because `InputTasks` are built from `Parsers`, it is possible to generate a new `InputTask` by applying some input programmatically.
|
||||
(It is also possible to generate a `Task`, which is covered in the next section.)
|
||||
Two convenience methods are provided on `InputTask[T]` and `Initialize[InputTask[T]]` that accept the String to apply.
|
||||
|
||||
* `partialInput` applies the input and allows further input, such as from the command line
|
||||
|
|
@ -212,18 +213,16 @@ NOTE: the current implementation of `:=` doesn't actually support applying input
|
|||
|
||||
::
|
||||
|
||||
val run2 = inputKey[Unit]("Runs the main class twice: " +
|
||||
lazy val run2 = inputKey[Unit]("Runs the main class twice: " +
|
||||
"once with the project name and version as arguments"
|
||||
"and once with command line arguments preceded by hard coded values.")
|
||||
|
||||
// The argument string for the first run task is ' <name> <version>'
|
||||
val firstInput: Initialize[String] =
|
||||
lazy val firstInput: Initialize[String] =
|
||||
Def.setting(s" ${name.value} ${version.value}")
|
||||
|
||||
// Make the first arguments to the second run task ' red blue'
|
||||
val secondInput: String = " red blue"
|
||||
|
||||
val separator: Parser[String] = "--"
|
||||
lazy val secondInput: String = " red blue"
|
||||
|
||||
run2 := {
|
||||
val one = (run in Compile).fullInput(firstInput.value).evaluated
|
||||
|
|
@ -243,3 +242,62 @@ For a main class Demo that echoes its arguments, this looks like:
|
|||
red
|
||||
blue
|
||||
green
|
||||
|
||||
|
||||
Get a Task from an InputTask
|
||||
============================
|
||||
|
||||
The previous section showed how to derive a new `InputTask` by applying input.
|
||||
In this section, applying input produces a `Task`.
|
||||
The `toTask` method on `Initialize[InputTask[T]]` accepts the `String` input to apply and produces a task that can be used normally.
|
||||
For example, the following defines a plain task `runFixed` that can be used by other tasks or run directly without providing any input, ::
|
||||
|
||||
lazy val runFixed = taskKey[Unit]("A task that hard codes the values to `run`")
|
||||
|
||||
runFixed := {
|
||||
val _ = (run in Compile).toTask(" blue green").value
|
||||
println("Done!")
|
||||
}
|
||||
|
||||
|
||||
For a main class Demo that echoes its arguments, running `runFixed` looks like:
|
||||
|
||||
::
|
||||
|
||||
$ sbt
|
||||
> runFixed
|
||||
[info] Running Demo blue green
|
||||
blue
|
||||
green
|
||||
Done!
|
||||
|
||||
|
||||
Each call to `toTask` generates a new task, but each task is configured the same as the original `InputTask` (in this case, `run`) but with different input applied.
|
||||
For example, ::
|
||||
|
||||
lazy val runFixed2 = taskKey[Unit]("A task that hard codes the values to `run`")
|
||||
|
||||
fork in run := true
|
||||
|
||||
runFixed2 := {
|
||||
val x = (run in Compile).toTask(" blue green").value
|
||||
val y = (run in Compile).toTask(" red orange").value
|
||||
println("Done!")
|
||||
}
|
||||
|
||||
The different `toTask` calls define different tasks that each run the project's main class in a new jvm.
|
||||
That is, the `fork` setting configures both, each has the same classpath, and each run the same main class.
|
||||
However, each task passes different arguments to the main class.
|
||||
For a main class Demo that echoes its arguments, the output of running `runFixed2` might look like:
|
||||
|
||||
::
|
||||
|
||||
$ sbt
|
||||
> runFixed2
|
||||
[info] Running Demo blue green
|
||||
[info] Running Demo red orange
|
||||
blue
|
||||
green
|
||||
red
|
||||
orange
|
||||
Done!
|
||||
|
|
|
|||
Loading…
Reference in New Issue