I am developing a plugin that contains a single custom task. The task looks for a command-line argument, say bar
, and uses it to construct an input file name. However, it appears that the task @TaskAction
method (and possibly the @InputFile
-annotated fields?) is running before the plugin’s apply
method. This leads to the bar
property being null when the task tries to construct the input file name. What is the correct way to achieve my goal?
Example code and usage follows.
class FooPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.tasks.register("foo", FooTask) {
if (project.hasProperty("bar") {
def targetFileName = "my${bar}.txt"
}
}
}
}
abstract class FooTask extends DefaultTask {
@Input
String bar
@InputFile
abstract RegularFileProperty getBarFile()
@Option(option = "bar")
void setBar(bar) {
this.bar = bar
}
@TaskAction
void doFoo() {
// task logic using the bar variable
}
}
How I’m attempting to run the task:
./gradlew foo -Pbar=baz
-P
sets the value of a Gradle/project property, not a task option. You want to follow the task name with --<option> <val>
. For example, ./gradlew foo --bar baz
(--bar=baz
also works).
You also need to provide a description
value with @Option
. For example, @Option(option="bar", description="this is the bar")
. This description will appear in the task help, ./gradlew help --task foo
.
Here’s how I might approach what you are trying to do
abstract class FooTask extends DefaultTask {
@InputFile
abstract RegularFileProperty getBarFile()
@Option(option = "bar", description="blah")
abstract Property<String> getBar()
@TaskAction
void doFoo() {
println barFile.get().asFile
}
}
class FooPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.tasks.register("foo", FooTask) {
barFile.convention(bar.map { barVal ->
project.layout.projectDirectory.file("my${barVal}.txt")
})
}
}
}
Ok, good to know about how to pass command-line arguments to tasks, thank you. Also, I did have a description, but thought it was optional so left it out of my example.
I do have some questions about your code. Gradle says “Cannot have abstract method FooTask.getBar()”. Should that be a setter?
Second, my real code has two input files (one that has a hard-coded name and the other that’s constructed from the command-line argument) and outputs to a third file. I tried putting this all into the bar.map
closure, but got a compiler warning:
‘convention’ in ‘org.gradle.api.file.RegularFileProperty’ cannot be applied to ‘(org.gradle.api.provider.Provider<java.lang.Object>)’