在SBT中:我想定义一个inputKey,它读取命令行参数,稍微改变它们并使用该结果作为输入到其他inputKeys.
我试过了:
lazy val demo = inputKey[Unit]("A demo input task.")
lazy val root = (project in file(".")).settings(
libraryDependencies += jUnitInterface
).settings(
demo := {
val args: Seq[String] = spaceDelimited("<arg>").parsed
val one = (run in Compile).fullInput(args(0) + "foo").evaluated
}
)
Run Code Online (Sandbox Code Playgroud)
但我得到了error: Illegal dynamic reference: args.
我也尝试过:
demo := {
val args: Seq[String] = spaceDelimited("<arg>").parsed
System.setProperty("args0", args(0))
val one = (run in Compile).fullInput(System.getProperty(args0) + "foo").evaluated
}
Run Code Online (Sandbox Code Playgroud)
这根本不提供输入.我怀疑这是执行顺序的问题(当我需要时,属性不会被设置,因为JVM可以随意移动线路).
所以,在我的绝望中,我甚至尝试过残暴的:
demo := {
val args: Seq[String] = spaceDelimited("<arg>").parsed
try {
System.setProperty("args0", args(0))
} finally {
val one = (run in Compile).fullInput(System.getProperty(args0) + "foo").evaluated
}
}
Run Code Online (Sandbox Code Playgroud)
强迫订单.这只会抛出一个NullPointerException.
正如Daniel C. Sobral提到的那样,parsed并且evaluated是宏,定义于InputWrapper.
由于它们是在编译时执行的,并且在运行时检索参数,因此它们不能很好地混合.特别是,args的值仅在运行时真正定义,并且不能由evaluated宏检索.
编辑:在与OP的聊天会话之后,我已经确定他的目标是写作的捷径 myTask Foo bar 而不是 testOnly *Foo* -- --tests=*bar*,我已经相应地更新了我的答案.
正如所讨论的,因为你基本上想要一个"宏"来myTask Foo bar代替testOnly *Foo* -- --tests=*bar*,这是我的解决方案:
val filtersParser = {
import complete.DefaultParsers._
(token(Space) ~> token(StringBasic, "<classFilter>")) ~
(token(Space) ~> token(StringBasic, "<methodFilter>"))
}
lazy val testFiltered = inputKey[Unit]("runs test methods matching *<methodFilter>* within classes matching *<classFilter>*")
testFiltered.in(Test) := Def.inputTaskDyn {
val (classFilter, methodFilter) = filtersParser.parsed
runTestsFiltered(classFilter, methodFilter)
}.evaluated
def runTestsFiltered(classFilter: String, methodFilter: String) = Def.taskDyn {
(testOnly in Test).toTask(s" *$classFilter* -- --tests *$methodFilter*")
}
Run Code Online (Sandbox Code Playgroud)
您需要一个自定义解析器来检索您期望的两个参数.这是通过以下代码实现的,它基本上定义了两个组,"chomping"两个空格而不记住它们,以及两个StringBasic参数,它们是解析器的结果(filtersParser属于类型Parser[(String, String)])
val filtersParser = {
import complete.DefaultParsers._
(token(Space) ~> token(StringBasic, "<classFilter>")) ~
(token(Space) ~> token(StringBasic, "<methodFilter>"))
}
Run Code Online (Sandbox Code Playgroud)
然后,您需要一个输入任务来使用解析器的结果并将它们转发到测试框架.这是在下一个片段中完成的(如果有些比我知识渊博的人希望在使用它的微妙之处inputTaskDyn,我很乐意开悟:)).请注意.in(Test)授予访问测试依赖关系的任务范围的定义.
lazy val testFiltered = inputKey[Unit]("runs test methods matching *<methodFilter>* within classes matching *<classFilter>*")
testFiltered.in(Test) := Def.inputTaskDyn {
val (classFilter, methodFilter) = filtersParser.parsed
runTestsFiltered(classFilter, methodFilter)
}.evaluated
Run Code Online (Sandbox Code Playgroud)
最后一点代码只是将参数转发给预先存在的testOnly任务:
def runTestsFiltered(classFilter: String, methodFilter: String) = Def.taskDyn {
(testOnly in Test).toTask(s" *$classFilter* -- --tests *$methodFilter*")
}
Run Code Online (Sandbox Code Playgroud)
但是,您应该能够通过在两个任务中拆分定义和用法来解决这个问题:
import sbt._
import complete.DefaultParsers._
lazy val loadArgTask = inputKey[Unit]("loads and transforms argument")
lazy val runStuff = taskKey[Unit]("Runs some stuff")
lazy val loadArgIntoPropertyTask: Def.Initialize[InputTask[Unit]] = Def.inputTask {
val myArg = (token(Space) ~> token(StringBasic, "<myArg>")).parsed
System.setProperty("myArg", myArg + "foo")
}
loadArgTask <<= loadArgIntoPropertyTask
runStuff := {
println(System.getProperty("myArg"))
}
Run Code Online (Sandbox Code Playgroud)
其中可以使用如下
> loadArgTask orange
[success] Total time: 0 s, completed [...]
> runStuff
orangefoo
[success] Total time: 0 s, completed [...]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
664 次 |
| 最近记录: |