mirror of https://github.com/sbt/sbt.git
Add Initialize[Task[T]].taskValue: Task[T] to allow selecting the Task for use by *Generators. Fixes #866.
This commit is contained in:
parent
1d9b44d5d7
commit
fcb35f3b8f
|
|
@ -63,7 +63,7 @@ object Def extends Init[Scope] with TaskMacroExtra
|
|||
import language.experimental.macros
|
||||
import std.TaskMacro.{inputTaskMacroImpl, inputTaskDynMacroImpl, taskDynMacroImpl, taskMacroImpl}
|
||||
import std.SettingMacro.{settingDynMacroImpl,settingMacroImpl}
|
||||
import std.{InputEvaluated, MacroValue, ParserInput}
|
||||
import std.{InputEvaluated, MacroValue, MacroTaskValue, ParserInput}
|
||||
|
||||
def task[T](t: T): Def.Initialize[Task[T]] = macro taskMacroImpl[T]
|
||||
def taskDyn[T](t: Def.Initialize[Task[T]]): Def.Initialize[Task[T]] = macro taskDynMacroImpl[T]
|
||||
|
|
@ -78,6 +78,7 @@ object Def extends Init[Scope] with TaskMacroExtra
|
|||
implicit def macroValueI[T](in: Initialize[T]): MacroValue[T] = ???
|
||||
implicit def macroValueIT[T](in: Initialize[Task[T]]): MacroValue[T] = ???
|
||||
implicit def macroValueIInT[T](in: Initialize[InputTask[T]]): InputEvaluated[T] = ???
|
||||
implicit def taskMacroValueIT[T](in: Initialize[Task[T]]): MacroTaskValue[T] = ???
|
||||
|
||||
// The following conversions enable the types Parser[T], Initialize[Parser[T]], and Initialize[State => Parser[T]] to
|
||||
// be used in the inputTask macro as an input with an ultimate result of type T
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ object Scoped
|
|||
def set(app: Initialize[Task[S]], source: SourcePosition): Setting[Task[S]] = Def.setting(scopedKey, app, source)
|
||||
def transform(f: S => S, source: SourcePosition): Setting[Task[S]] = set( scopedKey(_ map f), source)
|
||||
|
||||
@deprecated("No longer needed with new task syntax and SettingKey inheriting from Initialize.", "0.13.2")
|
||||
def task: SettingKey[Task[S]] = scopedSetting(scope, key)
|
||||
def get(settings: Settings[Scope]): Option[Task[S]] = settings.get(scope, key)
|
||||
|
||||
|
|
|
|||
|
|
@ -85,12 +85,23 @@ object InputWrapper
|
|||
InputWrapper.wrapInputTask[T](c)(ts,pos)
|
||||
else if(tpe <:< c.weakTypeOf[Initialize[InputTask[T]]])
|
||||
InputWrapper.wrapInitInputTask[T](c)(ts,pos)
|
||||
|
||||
else
|
||||
c.abort(pos, s"Internal sbt error. Unexpected type $tpe")
|
||||
c.abort(pos, s"Internal sbt error. Unexpected type ${tpe.widen}")
|
||||
}
|
||||
def taskValueMacroImpl[T: c.WeakTypeTag](c: Context): c.Expr[Task[T]] =
|
||||
ContextUtil.selectMacroImpl[Task[T]](c) { (ts, pos) =>
|
||||
val tpe = ts.tree.tpe
|
||||
if(tpe <:< c.weakTypeOf[Initialize[Task[T]]])
|
||||
InputWrapper.wrapInit[Task[T]](c)(ts,pos)
|
||||
else
|
||||
c.abort(pos, s"Internal sbt error. Unexpected type ${tpe.widen}")
|
||||
}
|
||||
}
|
||||
|
||||
sealed abstract class MacroTaskValue[T] {
|
||||
@compileTimeOnly("`taskValue` can only be used within a setting macro, such as :=, +=, ++=, or Def.setting.")
|
||||
def taskValue: Task[T] = macro InputWrapper.taskValueMacroImpl[T]
|
||||
}
|
||||
sealed abstract class MacroValue[T] {
|
||||
@compileTimeOnly("`value` can only be used within a task or setting macro, such as :=, +=, ++=, Def.task, or Def.setting.")
|
||||
def value: T = macro InputWrapper.valueMacroImpl[T]
|
||||
|
|
|
|||
|
|
@ -9,31 +9,31 @@ sbt provides standard hooks for adding source or resource generation tasks.
|
|||
:title: Generate sources
|
||||
:type: setting
|
||||
|
||||
sourceGenerators in Compile <+= <your Task[Seq[File]] here>
|
||||
sourceGenerators in Compile += <task of type Seq[File]>.taskValue
|
||||
|
||||
A source generation task should generate sources in a subdirectory of :key:`sourceManaged` and return a sequence of files generated. The key to add the task to is called :key:`sourceGenerators`. It should be scoped according to whether the generated files are main (`Compile`) or test (`Test`) sources. This basic structure looks like:
|
||||
A source generation task should generate sources in a subdirectory of :key:`sourceManaged` and return a sequence of files generated. The key to add the task to is called :key:`sourceGenerators`. Because we want to add the unexecuted task, we use `taskValue` instead of the usual `value`. :key:`sourceGenerators` should be scoped according to whether the generated files are main (`Compile`) or test (`Test`) sources. This basic structure looks like:
|
||||
|
||||
::
|
||||
|
||||
sourceGenerators in Compile <+= <your Task[Seq[File]] here>
|
||||
sourceGenerators in Compile += <task of type Seq[File]>.taskValue
|
||||
|
||||
For example, assuming a method `def makeSomeSources(base: File): Seq[File]`,
|
||||
|
||||
::
|
||||
|
||||
sourceGenerators in Compile <+=
|
||||
Def.task { makeSomeSources( (sourceManaged in Compile).value / "demo" ) }
|
||||
sourceGenerators in Compile +=
|
||||
Def.task( makeSomeSources( (sourceManaged in Compile).value / "demo" ) ).taskValue
|
||||
|
||||
|
||||
As a specific example, the following generates a hello world source file:
|
||||
|
||||
::
|
||||
|
||||
sourceGenerators in Compile <+= Def.task {
|
||||
sourceGenerators in Compile += Def.task {
|
||||
val file = (sourceManaged in Compile).value / "demo" / "Test.scala"
|
||||
IO.write(file, """object Test extends App { println("Hi") }""")
|
||||
Seq(file)
|
||||
}
|
||||
}.taskValue
|
||||
|
||||
Executing 'run' will print "Hi". Change `Compile` to `Test` to make it a test source. For efficiency, you would only want to generate sources when necessary and not every run.
|
||||
|
||||
|
|
@ -44,32 +44,32 @@ By default, generated sources are not included in the packaged source artifact.
|
|||
:title: Generate resources
|
||||
:type: setting
|
||||
|
||||
resourceGenerators in Compile <+= <your Task[Seq[File]] here>
|
||||
resourceGenerators in Compile += <task of type Seq[File]>
|
||||
|
||||
A resource generation task should generate resources in a subdirectory of :key:`resourceManaged` and return a sequence of files generated. The key to add the task to is called :key:`resourceGenerators`. It should be scoped according to whether the generated files are main (`Compile`) or test (`Test`) resources. This basic structure looks like:
|
||||
A resource generation task should generate resources in a subdirectory of :key:`resourceManaged` and return a sequence of files generated. The key to add the task to is called :key:`resourceGenerators`. Because we want to add the unexecuted task, we use `taskValue` instead of the usual `value`. It should be scoped according to whether the generated files are main (`Compile`) or test (`Test`) resources. This basic structure looks like:
|
||||
|
||||
::
|
||||
|
||||
resourceGenerators in Compile <+= <your Task[Seq[File]] here>
|
||||
resourceGenerators in Compile += <task of type Seq[File]>.taskValue
|
||||
|
||||
For example, assuming a method `def makeSomeResources(base: File): Seq[File]`,
|
||||
|
||||
::
|
||||
|
||||
resourceGenerators in Compile <+= Def.task {
|
||||
resourceGenerators in Compile += Def.task {
|
||||
makeSomeResources( (resourceManaged in Compile).value / "demo")
|
||||
}
|
||||
}.taskValue
|
||||
|
||||
As a specific example, the following generates a properties file containing the application name and version:
|
||||
|
||||
::
|
||||
|
||||
resourceGenerators in Compile <+= {
|
||||
resourceGenerators in Compile += Def.task {
|
||||
val file = (resourceManaged in Compile).value / "demo" / "myapp.properties"
|
||||
val contents = "name=%s\nversion=%s".format(name.value,version.value)
|
||||
IO.write(file, contents)
|
||||
Seq(file)
|
||||
}
|
||||
}.taskValue
|
||||
|
||||
Change `Compile` to `Test` to make it a test resource. Normally, you would only want to generate resources when necessary and not every run.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue