Мне нужно создать плагин, который бы предоставлял интерактивную задачу, вызываемую так:
> ./gradlew analyzeSomething --configuration compileClasspath
Здесь аргумент --configuration
должен быть именем конфигурации в проекте, который используется для анализа.
Однако этот анализ требует некоторых данных, вычисленных из конфигурации, что может быть дорогостоящим. Поэтому я хотел бы кэшировать эти данные, но, естественно, таким образом, что это приведет к аннулированию кэша в случае изменения содержимого конфигурации (например, добавление зависимости пользователем). В идеале я бы воспользовался встроенными механизмами зависимостей задач Gradle, которые бы отслеживали зависимости задач и позволяли не запускать вычисления, если их входные данные не изменились.
Это решение, которое я придумал, но это не работает. Во-первых, объявите два свойства в классе AnalyzeSomething
:
abstract class AnalyzeSomethingTask : DefaultTask() {
@get:Internal
@get:Option(option = "configuration", description = "Configuration")
abstract val configuration: Property<String>
@get:Internal
abstract val dataCacheFile: RegularFileProperty
}
Во-вторых, создайте правило задачи для создания экземпляров задач, выполняющих дорогостоящие вычисления:
abstract class PrecomputeTask : DefaultTask() {
@get:InputFiles
abstract val classpath: ConfigurableFileCollection
@get:OutputFile
abstract val outputFile: RegularFileProperty
}
project.tasks.addRule("Pattern precompute<Configuration>") {
val taskName = this
if (taskName.startsWith("precompute")) {
val configurationName = taskName.removePrefix("precompute").decapitalize()
val configuration = project.configurations.getByName(configurationName)
project.tasks.register<PrecomputeTask>(taskName) {
classpath.from(configuration)
outputFile.set(temporaryDir.resolve("data.txt"))
}
}
}
Наконец, создайте analyzeSomething
task и в блоке project.afterEvalute
(поэтому все свойства задачи уже заданы, в том числе в командной строке) задайте зависимость между analyzeSomething
и одной из задач, созданных правилом:
val analyzeSomething = project.tasks.register<AnalyzeSomethingTask>("analyzeSomething")
project.afterEvaluate {
analyzeSomething.configure {
val precomputeTaskName = "precompute" + configuration.get().capitalize()
dataCacheFile.set(
project.tasks.named<PrecomputeTask>(precomputeTaskName)
.flatMap { it.outputFile }
)
}
}
Этот подход, однако, не работает, потому что, очевидно, register()
и любые другие методы конфигурации коллекции не могут быть вызваны в любой точке, в которой они вызываются при такой настройке:
> ./gradlew analyzeSomething --configuration runtimeClasspath
Caused by: org.gradle.api.internal.tasks.DefaultTaskContainer$TaskCreationException: Could not create task ':analyzeSomething'.
...
Caused by: org.gradle.api.internal.AbstractMutationGuard$IllegalMutationException: DefaultTaskContainer#create(String, Class, Action) on task set cannot be executed in the current context.
Так что мой вопрос есть ли способ установить зависимости задачи на основе имени свойства, и если нет, то какой будет лучший способ сделать то, что я хочу?