我编写了一个SBT plugin,允许SBT用户在他们的项目中定义可以从SBT本身运行的任意任务(加载完整的类路径和依赖关系)。
功能正文如下所示
def installTask(taskName: String, taskDescription: String = "") = {
TaskKey[Unit](taskName, taskDescription) <<= (dependencyClasspath in Runtime)
.map(loadTask(_, "tasks", taskName.capitalize))
.map(_.run)
}
private def loadTask(dependencies: Keys.Classpath, taskPackage:String, className: String) = {
val dependenciesUrls = dependencies.map(_.data.toURI.toURL).toArray
val classLoader = new URLClassLoader(dependenciesUrls, null)
val taskClass = s"$taskPackage.$className"
classLoader.loadClass(taskClass).newInstance().asInstanceOf[Runnable]
}
所以人们可以在他们的SBT文件中执行此操作
import SbtTasks._
installTask("seedDB")
当调用sbt seedDB
tasks.SeedDB
将在应用程序上下文中执行时。
现在问题 - 我需要这样做但接受参数。我已经理解了如何接受参数
def installTaskWithArgs(taskName: String, taskDescription: String = "") = {
val input = InputKey[Unit](taskName, taskDescription)
input := {
val args: Seq[String] = Def.spaceDelimited("<arg>").parsed
println(args)
}
}
但是我无法弄清楚如何在这个上下文中访问InputTask中dependencyClasspath
的值
val dc = (dependencyClasspath in Runtime)
我也尝试过命令,但它们看起来有点麻烦,所有内容似乎都会提升InputTasks over Commands。
那么 - 我如何接受任务中的参数,同时还可以访问dependencyClasspath
?
注意:为简洁起见,代码已被省略,请原谅任何明显的排除
答案 0 :(得分:1)
我认为inputTaskDyn
是你的朋友:
input :=
Def.inputTaskDyn {
val args = Def.spaceDelimited("<arg>").parsed
val dc = (dependencyClasspath in Runtime).value
...
}.evaluated
有关某些背景信息以及进一步阅读的链接,请参阅https://github.com/sbt/sbt/issues/999
答案 1 :(得分:0)
经过几天的实验,我终于找到了一个可行的解决方案,
def installTaskWithArgs(taskName: String, taskDescription: String = "") = {
val input = InputKey[Unit](taskName, taskDescription)
input := {
val args: Seq[String] = Def.spaceDelimited("<arg>").parsed
val dc = (dependencyClasspath in Runtime).result.value.toEither.right.get
println(args)
println(dc)
}
}
我想特别提出行
val dc = (dependencyClasspath in Runtime).result.value.toEither.right.get
虽然这不是最稳定的路线(它假定是快乐的路径),但这至少是一个很好的起点(并且目前我的需求是有效的)