将项目传递给sbt动态任务
我有一个sbt项目,其中包括代码生成 build.sbt的一部分是将项目传递给sbt动态任务,sbt,Sbt,我有一个sbt项目,其中包括代码生成 build.sbt的一部分是 lazy val generator = (project in file("generator")). settings(mainClass := Some("com.example.Generator")) lazy val generate = (project in file("generate")). dependsOn(generator). settings(runGeneration) de
lazy val generator = (project in file("generator")).
settings(mainClass := Some("com.example.Generator"))
lazy val generate = (project in file("generate")).
dependsOn(generator).
settings(runGeneration)
def runGeneration: SettingsDefinition = sourceGenerators in Compile += Def.taskDyn {
val cachedFun = FileFunction.cached(
streams.value.cacheDirectory / "generation"
) { (in: Set[File]) =>
val dir = (sourceManaged in Compile).value
(generator / run in Compile).toTask(" " + dir.getAbsolutePath).value
collectFiles(dir)
}
val dependentFiles = ((generator / fullClasspath in Compile) map { cp => cp.files }).taskValue.value
val genFiles = cachedFun(dependenctFiles).toSeq
Def.task {
genFiles
}
}.taskValue
这似乎是可行的,并且只在依赖项发生更改时生成文件。但是,我希望有多个发电机。我没有复制代码,而是尝试将generator
项目传递给它:
lazy val generate = (project in file("generate")).
dependsOn(generator).
settings(runGeneration(generator))
def runGeneration(p: project): SettingsDefinition =
<same as before but with p instead of generator>
我猜问题在于它无法在编译时判断是否存在依赖循环,因此它会保守地给出一个错误
有没有办法让它发挥作用?是否有一个完全不同的结构让我知道运行
generator
是否会产生不同的结果?根本的问题是sbt
中的任务定义有两个组件,看起来它们可以混合,但不能。如果你像这样写代码
Def.task {
val doIt = checkIfShouldDoIt()
if (doIt) {
someTask.value
} else {
()
}
}
如果doIt
为真,那么它看起来只会运行someTask
。实际发生的情况是,someTask.value
声明此任务对someTask
的依赖关系,并且在对此任务执行任何操作之前运行someTask
。要以更直接地映射实际发生的情况的方式编写上述代码,可以编写
Def.task {
val someTaskValue = someTask.value
val doIt = checkIfShouldDoIt()
if (doIt) {
someTaskValue
} else {
()
}
}
仅当依赖项已更改时才尝试运行任务无法在单个任务中运行
我的工作解决方案如下所示。我修改了生成器以接受一个附加参数,如果该参数为false,则不执行任何操作。这两项任务是:
// Task to check if we need to generate
def checkGeneration(p: Project) = Def.taskDyn {
var needToGenerate = false
val cachedFunction = FileFunction.cached(someDir) {
(in: Set[File]) =>
needToGenerate = ! in.isEmpty
Set()
}
val dependentFiles = ((p / fullClasspath in Compile) map { cp => cp.files }).taskValue
Def.task {
cachedFun(dependentFiles.value.toSet)
needToGenerate
}
}
// Task to run generation
def runGeneration(p: Project): SettingsDefinition = sourceGenerators in Compile += Def.taskDyn {
val needToGenerate = checkGeneration(p).value
Def.task {
// Run generator as before but pass needToGenerate as additional argument
...
// Used FileFunction.cached as before to find the generated files (but not run the generator)
...
}
}
我可能有比我需要的更多的动态任务,但这是可行的
// Task to check if we need to generate
def checkGeneration(p: Project) = Def.taskDyn {
var needToGenerate = false
val cachedFunction = FileFunction.cached(someDir) {
(in: Set[File]) =>
needToGenerate = ! in.isEmpty
Set()
}
val dependentFiles = ((p / fullClasspath in Compile) map { cp => cp.files }).taskValue
Def.task {
cachedFun(dependentFiles.value.toSet)
needToGenerate
}
}
// Task to run generation
def runGeneration(p: Project): SettingsDefinition = sourceGenerators in Compile += Def.taskDyn {
val needToGenerate = checkGeneration(p).value
Def.task {
// Run generator as before but pass needToGenerate as additional argument
...
// Used FileFunction.cached as before to find the generated files (but not run the generator)
...
}
}