mirror of https://github.com/sbt/sbt.git
taskKey,settingKey,inputKey macros to get name from the defining val
This commit is contained in:
parent
538f687208
commit
3bff14d77a
|
|
@ -0,0 +1,43 @@
|
|||
package sbt
|
||||
package std
|
||||
|
||||
import language.experimental.macros
|
||||
import scala.reflect._
|
||||
import reflect.macros._
|
||||
|
||||
object KeyMacro
|
||||
{
|
||||
def settingKeyImpl[T: c.WeakTypeTag](c: Context)(description: c.Expr[String]): c.Expr[SettingKey[T]] =
|
||||
keyImpl[T, SettingKey[T]](c) { (name, mf) =>
|
||||
c.universe.reify { SettingKey[T](name.splice, description.splice)(mf.splice) }
|
||||
}
|
||||
def taskKeyImpl[T: c.WeakTypeTag](c: Context)(description: c.Expr[String]): c.Expr[TaskKey[T]] =
|
||||
keyImpl[T, TaskKey[T]](c) { (name, mf) =>
|
||||
c.universe.reify { TaskKey[T](name.splice, description.splice)(mf.splice) }
|
||||
}
|
||||
def inputKeyImpl[T: c.WeakTypeTag](c: Context)(description: c.Expr[String]): c.Expr[InputKey[T]] =
|
||||
keyImpl[T, InputKey[T]](c) { (name, mf) =>
|
||||
c.universe.reify { InputKey[T](name.splice, description.splice)(mf.splice) }
|
||||
}
|
||||
|
||||
def keyImpl[T: c.WeakTypeTag, S: c.WeakTypeTag](c: Context)(f: (c.Expr[String], c.Expr[Manifest[T]]) => c.Expr[S]): c.Expr[S] =
|
||||
{
|
||||
import c.universe.{Apply=>ApplyTree,_}
|
||||
val enclosingValName = definingValName(c)
|
||||
val name = c.Expr[String]( Literal(Constant(enclosingValName)) )
|
||||
val mf = c.Expr[Manifest[T]](c.inferImplicitValue( weakTypeOf[Manifest[T]] ) )
|
||||
f(name, mf)
|
||||
}
|
||||
def definingValName(c: Context): String =
|
||||
{
|
||||
import c.universe.{Apply=>ApplyTree,_}
|
||||
val methodName = c.macroApplication.symbol.name.decoded
|
||||
val enclosingTrees = c.asInstanceOf[reflect.macros.runtime.Context].callsiteTyper.context.enclosingContextChain.map(_.tree.asInstanceOf[Tree])
|
||||
enclosingTrees match {
|
||||
case vd @ ValDef(_, name, _, _) :: ts => name.decoded
|
||||
case _ =>
|
||||
c.error(c.enclosingPosition, s"""$methodName must be directly assigned to a val, such as `val x = $methodName[Int]("description")`.""")
|
||||
"<error>"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -492,3 +492,16 @@ object SettingKey
|
|||
|
||||
def local[T: Manifest]: SettingKey[T] = apply[T](AttributeKey.local[T])
|
||||
}
|
||||
|
||||
object settingKey
|
||||
{
|
||||
def apply[T](description: String): SettingKey[T] = macro std.KeyMacro.settingKeyImpl[T]
|
||||
}
|
||||
object taskKey
|
||||
{
|
||||
def apply[T](description: String): TaskKey[T] = macro std.KeyMacro.taskKeyImpl[T]
|
||||
}
|
||||
object inputKey
|
||||
{
|
||||
def apply[T](description: String): TaskKey[T] = macro std.KeyMacro.taskKeyImpl[T]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,19 +24,19 @@ object Assign
|
|||
import Def.{Initialize,macroValueT,parserToInput}
|
||||
// import UseTask.{x,y,z,a,set,plain}
|
||||
|
||||
val ak = TaskKey[Int]("a")
|
||||
val bk = TaskKey[Seq[Int]]("b")
|
||||
val ck = SettingKey[File]("c")
|
||||
val sk = TaskKey[Set[_]]("s")
|
||||
val ak = taskKey[Int]("a")
|
||||
val bk = taskKey[Seq[Int]]("b")
|
||||
val ck = settingKey[File]("c")
|
||||
val sk = taskKey[Set[_]]("s")
|
||||
|
||||
val ik = InputKey[Int]("i")
|
||||
val isk = InputKey[String]("is")
|
||||
val mk = SettingKey[Int]("m")
|
||||
val tk = TaskKey[Int]("t")
|
||||
val name = SettingKey[String]("name")
|
||||
val dummyt = TaskKey[complete.Parser[String]]("dummyt")
|
||||
val dummys = SettingKey[complete.Parser[String]]("dummys")
|
||||
val dummy3 = SettingKey[complete.Parser[(String,Int)]]("dummy3")
|
||||
val ik = inputKey[Int]("i")
|
||||
val isk = inputKey[String]("is")
|
||||
val mk = settingKey[Int]("m")
|
||||
val tk = taskKey[Int]("t")
|
||||
val name = settingKey[String]("name")
|
||||
val dummyt = taskKey[complete.Parser[String]]("dummyt")
|
||||
val dummys = settingKey[complete.Parser[String]]("dummys")
|
||||
val dummy3 = settingKey[complete.Parser[(String,Int)]]("dummy3")
|
||||
val tsk: complete.Parser[TaskKey[String]] = ???
|
||||
|
||||
/* def azy = sk.value
|
||||
|
|
|
|||
|
|
@ -93,14 +93,14 @@ For example:
|
|||
|
||||
::
|
||||
|
||||
val myTask = taskKey[Unit]("My task.")
|
||||
|
||||
myTask := {
|
||||
val (art, file) = packagedArtifact.in(Compile, packageBin).value
|
||||
println("Artifact definition: " + art)
|
||||
println("Packaged file: " + file.getAbsolutePath)
|
||||
}
|
||||
|
||||
where ``val myTask = TaskKey[Unit]``.
|
||||
|
||||
Defining custom artifacts
|
||||
=========================
|
||||
|
||||
|
|
@ -138,6 +138,8 @@ generates the artifact:
|
|||
|
||||
::
|
||||
|
||||
val myImageTask = taskKey[File](...)
|
||||
|
||||
myImageTask := {
|
||||
val artifact: File = makeArtifact(...)
|
||||
artifact
|
||||
|
|
@ -145,8 +147,6 @@ generates the artifact:
|
|||
|
||||
addArtifact( Artifact("myproject", "image", "jpg"), myImageTask )
|
||||
|
||||
where ``val myImageTask = TaskKey[File](...)``.
|
||||
|
||||
``addArtifact`` returns a sequence of settings (wrapped in a
|
||||
`SettingsDefinition <../../api/#sbt.Init$SettingsDefinition>`_).
|
||||
In a full build configuration, usage looks like:
|
||||
|
|
|
|||
|
|
@ -92,11 +92,10 @@ For example:
|
|||
|
||||
::
|
||||
|
||||
lazy val makeFile = TaskKey[File]("makeFile")
|
||||
lazy val makeFile = taskKey[File]("Creates a file with some content.")
|
||||
|
||||
// define a task that creates a file,
|
||||
// writes some content, and returns the File
|
||||
// The write is completely
|
||||
makeFile := {
|
||||
val f: File = file("/tmp/data.txt")
|
||||
IO.write(f, "Some content")
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ to the list of main source generators (``sourceGenerators in Compile``).
|
|||
To insert a named task, which is the better approach for plugins:
|
||||
|
||||
::
|
||||
val mySourceGenerator = TaskKey[Seq[File]](...)
|
||||
val mySourceGenerator = taskKey[Seq[File]](...)
|
||||
|
||||
mySourceGenerator in Compile :=
|
||||
generate( (sourceManaged in Compile).value / "some_directory")
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ build.sbt
|
|||
|
||||
::
|
||||
|
||||
val hello = TaskKey[Unit]("hello", "Prints 'Hello World'")
|
||||
val hello = taskKey[Unit]("Prints 'Hello World'")
|
||||
|
||||
hello := println("hello world!")
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ project/Build.scala
|
|||
scalaVersion := "2.9.0-1"
|
||||
)
|
||||
|
||||
val hello = TaskKey[Unit]("hello", "Prints 'Hello World'")
|
||||
val hello = taskKey[Unit]("Prints 'Hello World'")
|
||||
|
||||
val helloTask = hello := {
|
||||
println("Hello World")
|
||||
|
|
@ -103,21 +103,17 @@ To declare a new task, define a val of type ``TaskKey``, either in ``.sbt`` or `
|
|||
|
||||
::
|
||||
|
||||
val sampleTask = TaskKey[Int]("sampleTask")
|
||||
val sampleTask = taskKey[Int]("A sample task.")
|
||||
|
||||
The name of the ``val`` is used when referring to the task in Scala
|
||||
code. The string passed to the ``TaskKey`` method is used at runtime,
|
||||
such as at the command line. By convention, both the Scala identifier
|
||||
and the runtime identifier are camelCase. The type parameter
|
||||
passed to ``TaskKey`` (here, ``Int``) is the type of value produced by
|
||||
the task.
|
||||
code and at the command line. The string passed to the ``TaskKey`` method is a description of the task. The type parameter passed to ``TaskKey`` (here, ``Int``) is the type of value produced by the task.
|
||||
|
||||
We'll define a couple of other of tasks for the examples:
|
||||
|
||||
::
|
||||
|
||||
val intTask = TaskKey[Int]("intTask")
|
||||
val stringTask = TaskKey[String]("stringTask")
|
||||
val intTask = taskKey[Int]("An int task")
|
||||
val stringTask = taskKey[String]("A string task")
|
||||
|
||||
The examples themselves are valid entries in a ``build.sbt`` or can be
|
||||
provided as part of a sequence to ``Project.settings`` (see
|
||||
|
|
@ -224,9 +220,9 @@ would go in a ``Build`` object in a ``.scala`` file or directly in a ``.sbt`` fi
|
|||
|
||||
::
|
||||
|
||||
val unitTask = TaskKey[Unit]("unitTask")
|
||||
val intTask = TaskKey[Int]("intTask")
|
||||
val stringTask = TaskKey[String]("stringTask")
|
||||
val unitTask = taskKey[Unit]("A side-effecting task.")
|
||||
val intTask = taskKey[Int]("A task that returns an integer.")
|
||||
val stringTask = taskKey[String]("A task that returns String")
|
||||
|
||||
The examples themselves are valid settings in a ``build.sbt`` file or as
|
||||
part of a sequence provided to ``Project.settings``.
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@ Input Keys
|
|||
A key for an input task is of type ``InputKey`` and represents the input
|
||||
task like a ``SettingKey`` represents a setting or a ``TaskKey``
|
||||
represents a task. Define a new input task key using the
|
||||
``InputKey.apply`` factory method:
|
||||
``inputKey.apply`` factory method:
|
||||
|
||||
::
|
||||
|
||||
// goes in <base>/project/Build.scala or in <base>/build.sbt
|
||||
val demo = InputKey[Unit]("demo")
|
||||
val demo = inputKey[Unit]("A demo input task.")
|
||||
|
||||
The definition of an input task is similar to that of a normal task, but it can
|
||||
also use the result of a `Parser </Detailed-Topics/Parsing-Input>`_ applied to
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ Where possible, reuse them in your plugin. For instance, don't define:
|
|||
|
||||
::
|
||||
|
||||
val sourceFiles = SettingKey[Seq[File]]("sourceFiles")
|
||||
val sourceFiles = settingKey[Seq[File]]("Some source files")
|
||||
|
||||
Instead, simply reuse SBT's existing ``sources`` key.
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ Just use a ``val`` prefix
|
|||
|
||||
package sbtobfuscate
|
||||
object Plugin extends sbt.Plugin {
|
||||
val obfuscateStylesheet = SettingKey[File]("obfuscateStylesheet")
|
||||
val obfuscateStylesheet = settingKey[File]("Obfuscate stylesheet")
|
||||
}
|
||||
|
||||
In this approach, every ``val`` starts with ``obfuscate``. A user of the
|
||||
|
|
@ -168,7 +168,7 @@ Configurations should *not* be used to namespace keys for a plugin. e.g.
|
|||
::
|
||||
|
||||
val Config = config("my-plugin")
|
||||
val pluginKey = SettingKey[String]("pluginSpecificKey")
|
||||
val pluginKey = settingKey[String]("A plugin specific key")
|
||||
val settings = pluginKey in Config // DON'T DO THIS!
|
||||
|
||||
Playing nice with configurations
|
||||
|
|
|
|||
|
|
@ -269,8 +269,8 @@ An example of a typical plugin:
|
|||
{
|
||||
// configuration points, like the built in `version`, `libraryDependencies`, or `compile`
|
||||
// by implementing Plugin, these are automatically imported in a user's `build.sbt`
|
||||
val newTask = TaskKey[Unit]("newTask")
|
||||
val newSetting = SettingKey[String]("newSetting")
|
||||
val newTask = taskKey[Unit]("A new task.")
|
||||
val newSetting = settingKey[String]("A new setting.")
|
||||
|
||||
// a group of settings ready to be added to a Project
|
||||
// to automatically add them, do
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ Some examples from `Keys <../../sxr/Keys.scala.html>`_:
|
|||
|
||||
::
|
||||
|
||||
val scalaVersion = SettingKey[String]("scalaVersion", "The version of Scala used for building.")
|
||||
val clean = TaskKey[Unit]("clean", "Deletes files produced by the build, such as generated sources, compiled classes, and task caches.")
|
||||
val scalaVersion = settingKey[String]("The version of Scala used for building.")
|
||||
val clean = taskKey[Unit]("Deletes files produced by the build, such as generated sources, compiled classes, and task caches.")
|
||||
|
||||
The key constructors have two string parameters: the name of the key
|
||||
(``"scalaVersion"``) and a documentation string
|
||||
|
|
|
|||
|
|
@ -103,10 +103,10 @@ The following two files illustrate. First, if your project is in
|
|||
|
||||
object HelloBuild extends Build {
|
||||
|
||||
val sampleKeyA = SettingKey[String]("sampleKeyA", "demo key A")
|
||||
val sampleKeyB = SettingKey[String]("sampleKeyB", "demo key B")
|
||||
val sampleKeyC = SettingKey[String]("sampleKeyC", "demo key C")
|
||||
val sampleKeyD = SettingKey[String]("sampleKeyD", "demo key D")
|
||||
val sampleKeyA = settingKey[String]("demo key A")
|
||||
val sampleKeyB = settingKey[String]("demo key B")
|
||||
val sampleKeyC = settingKey[String]("demo key C")
|
||||
val sampleKeyD = settingKey[String]("demo key D")
|
||||
|
||||
override lazy val settings = super.settings ++
|
||||
Seq(sampleKeyA := "A: in Build.settings in Build.scala", resolvers := Seq())
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ or like this, where ``configuration`` is also a string:
|
|||
|
||||
::
|
||||
|
||||
val libraryDependencies = SettingKey[Seq[ModuleID]]("library-dependencies", "Declares managed dependencies.")
|
||||
val libraryDependencies = settingKey[Seq[ModuleID]]("Declares managed dependencies.")
|
||||
|
||||
The ``%`` methods create ``ModuleID`` objects from strings, then you add
|
||||
those ``ModuleID`` to ``libraryDependencies``.
|
||||
|
|
@ -185,7 +185,7 @@ this:
|
|||
|
||||
::
|
||||
|
||||
val resolvers = SettingKey[Seq[Resolver]]("resolvers", "The user-defined additional resolvers for automatically managed dependencies.")
|
||||
val resolvers = settingKey[Seq[Resolver]]("The user-defined additional resolvers for automatically managed dependencies.")
|
||||
|
||||
The ``at`` method creates a ``Resolver`` object from two strings.
|
||||
|
||||
|
|
|
|||
|
|
@ -197,8 +197,8 @@ Take these two keys (from `Keys <../../sxr/Keys.scala.html>`_):
|
|||
|
||||
::
|
||||
|
||||
val scalacOptions = TaskKey[Seq[String]]("scalac-options", "Options for the Scala compiler.")
|
||||
val checksums = SettingKey[Seq[String]]("checksums", "The list of checksums to generate and to verify for dependencies.")
|
||||
val scalacOptions = taskKey[Seq[String]]("Options for the Scala compiler.")
|
||||
val checksums = settingKey[Seq[String]]("The list of checksums to generate and to verify for dependencies.")
|
||||
|
||||
(``scalacOptions`` and ``checksums`` have nothing to do with each other,
|
||||
they are just two keys with the same value type, where one is a task.)
|
||||
|
|
|
|||
|
|
@ -434,20 +434,12 @@ A basic run task is created by:
|
|||
|
||||
::
|
||||
|
||||
// this lazy val has to go in a full configuration
|
||||
lazy val myRunTask = TaskKey[Unit]("myRunTask")
|
||||
lazy val myRunTask = taskKey[Unit]("A custom run task.")
|
||||
|
||||
// this can go either in a `build.sbt` or the settings member
|
||||
// of a Project in a full configuration
|
||||
fullRunTask(myRunTask, Test, "foo.Foo", "arg1", "arg2")
|
||||
|
||||
or, if you really want to define it inline (as in a basic ``build.sbt``
|
||||
file):
|
||||
|
||||
::
|
||||
|
||||
fullRunTask(TaskKey[Unit]("myRunTask"), Test, "foo.Foo", "arg1", "arg2")
|
||||
|
||||
If you want to be able to supply arguments on the command line, replace
|
||||
``TaskKey`` with ``InputKey`` and ``fullRunTask`` with
|
||||
``fullRunInputTask``. The ``Test`` part can be replaced with another
|
||||
|
|
@ -463,42 +455,6 @@ in the scope. For example:
|
|||
|
||||
javaOptions in myRunTask += "-Xmx6144m"
|
||||
|
||||
How can I delegate settings from one task to another task?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Settings :doc:`scoped </Getting-Started/Scopes>` to one task can fall back to
|
||||
another task if undefined in the first task. This is called delegation.
|
||||
|
||||
The following key definitions specify that settings for ``myRun``
|
||||
delegate to ``aRun``
|
||||
|
||||
::
|
||||
|
||||
val aRun = TaskKey[Unit]("aRun", "A run task.")
|
||||
|
||||
// The last parameter to TaskKey.apply here is a repeated one
|
||||
val myRun = TaskKey[Unit]("myRun", "Custom run task.", aRun)
|
||||
|
||||
In use, this looks like:
|
||||
|
||||
::
|
||||
|
||||
// Make the run task as before.
|
||||
fullRunTask(myRun, Compile, "pkg.Main", "arg1", "arg2")
|
||||
|
||||
// If fork in myRun is not explicitly set,
|
||||
// then this also configures myRun to fork.
|
||||
// If fork in myRun is set, it overrides this setting
|
||||
// because it is more specific.
|
||||
fork in aRun := true
|
||||
|
||||
// Appends "-Xmx2G" to the current options for myRun.
|
||||
// Because we haven't defined them explicitly,
|
||||
// the current options are delegated to aRun.
|
||||
// So, this says to use the same options as aRun
|
||||
// plus -Xmx2G.
|
||||
javaOptions in myRun += "-Xmx2G"
|
||||
|
||||
How should I express a dependency on an outside tool such as proguard?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue