我需要了解如何在任务中正确注册任务并添加依赖项。例如,这是我的任务:
open class CodeGeneratorTask: DefaultTask() {
@TaskAction
fun action() {
project.extensions.findByType(GenerationConfiguration::class.java)!!.let {
it.contracts.forEach { contract ->
createContractFileTask(project.tasks, contract) //creates tasks named contract.downloadTaskName
project.tasks.register(contract.generateTaskName, GenerateTask::class.java, generateClasses(contract))
project.tasks.named(contract.generateTaskName) { dependsOn(contract.downloadTaskName) }
project.tasks.withType(KotlinCompile::class.java) { dependsOn(project.tasks.named(contract.downloadTaskName)) }
project.extensions.getByType(KotlinJvmProjectExtension::class.java).sourceSets.getByName("main").kotlin
.srcDir(project.layout.buildDirectory.dir("generated/${contract.path}/src/main/kotlin").get())
}
}
}
...
}
我需要注册两种任务:一种是下载文件,另一种是从下载的文件生成代码。有必要在
kotlinCompile
任务之前运行这些任务。由于"Cannot call Task.dependsOn(Object...) on task ':simpleCodeGenerator' after task has started execution."
,我无法运行它。现在我陷入困境,因为我不知道如何添加此依赖项。 CodeGeneratorTask
在 KotlinCompile
之前运行。
dependsOn
dependsOn
可用于链接任务,但您需要在项目的配置阶段调用它,而不是像您在这里所做的那样在执行阶段调用它。看看 Gradle 项目生命周期的解释。
所以你可以在
build.gradle.kts
中写:
tasks {
val codeGeneratorTask = register<CodeGeneratorTask>("generateCode") {
// configure codeGeneratorTask
}
withType<KotlinCompile>().configureEach {
dependsOn(codeGeneratorTask)
}
}
上述所有代码都在配置阶段运行(就其运行而言)。这是在执行阶段运行的任务的actions,此时告诉 Gradle 哪些任务依赖于哪些任务为时已晚。
这会起作用,但这并不是真正正确的方法。正确的方法是为每个任务提供输入和输出(docs)。
在 Gradle 中,为任务分配输入和输出,然后 Gradle 推导出任务依赖关系,这样,如果任务 A 的输出被任务 B 使用作为输入,则任务 B 就会依赖于任务 A。
如果您足够深入地研究 Kotlin 插件的代码,您会发现 Kotlin 编译任务的输入正如我们所期望的那样,是构成 Kotlin 源代码的文件。因此,实际上,让 Kotlin 编译任务依赖于给定任务的输出的更好方法是将该任务的输出包含在 Kotlin 源代码中。
为此,我们必须为任务提供输出:
open class CodeGeneratorTask: DefaultTask() {
@OutputDirectory
val outputDir: DirectoryProperty = project.objects.directoryProperty().convention(
project.layout.buildDirectory.dir("myGeneratedCode")
)
}
显然要确保
@TaskAction
函数将代码放入此目录中!
现在我们有了一个可以添加到 Kotlin 源代码的目录(假设此处有 JVM 插件):
tasks {
val codeGeneratorTask = register<CodeGeneratorTask>("generateCode") {
// configure codeGeneratorTask
}
// We use the map function to access the directory lazily
kotlin.sourceSets.main.get().kotlin.srcDirs(codeGeneratorTask.map { it.outputDir })
}
要检查此操作是否有效,请运行
./gradlew compileKotlin --dry-run
,它应该显示任务 generateCode
与之前运行的 compileKotlin
一样。
您可以使用
@InputFile
或 @InputFiles
注释定义输入,然后在配置阶段将其他任务的输出分配给它们,从而对自己的输入进行相同的链接。