How to pass #Input String in a task in buildSrc - gradle

This custom plugin exists in gradle's buildSrc/:
abstract class MyTask : DefaultTask() {
#get:Input
abstract val buildDir: Property<String>
#TaskAction
fun someTask() {
// do stuff
}
}
class DevelopmentPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.tasks.run {
register("myTask", MyTask::class.java) {
inputs.property("buildDir", project.buildDir)
println(inputs.getProperties())
}
}
}
}
and by running the task with e.g. $ ./gradlew myTask fails with:
Could not determine the dependencies of task ':myTask'.
> Cannot query the value of task ':myTask' property 'rootDir' because it has no value available.
Also the prinln outputs {buildDir=null} meaning that the inputs.property("buildDir", project.buildDir) has failed.
How to pass the project.buildDir value from the Plugin in the task?
Using project.buildDir directly from inside the task is not an acceptable answer due to Gradle's incubating build-cache functionality.

Firstly, there is a class type issue which is not visible in Gradle.
buildDir is of type File while the property is String.
So "${project.buildDir}" should be used.
Secondly, since the property is abstract val it can directly be accessed in the closure. Therefore it can be set with:
// instead of:
inputs.property("buildDir", "${project.buildDir}")
// just this:
buildDir.set("${project.buildDir}")

Related

How to incorporate command-line arguments in a custom Gradle Task?

I'm working on building a Gradle plugin that contains a single task which will combine two input files (the filename of one is constructed from command-line input) into one output file. I have followed this DZone article to set up my task and plugin classes. When I run the task, I see the log statement containing the command-line input, but the the plugin code to configure the task gets a null value for the input. How can I fix this? Example code below.
class FooPlugin implements Plugin<Project> {
#Override
void apply(Project project) {
project.tasks.register("foo", FooTask) {
if (it.hasProperty("bar") {
it.baseFile.convention(project.layout.projectDirectory.file("my${bar}.txt")
}
}
}
}
#CompileSTatic
abstract class FooTask extends DefaultTask {
#Input
String bar
#InputFile
abstract RegularFileProperty getBarFile()
#Option(option = "bar", description = "Does bar-ish things")
void setBar(bar) {
println "Setting bar variable from command-line argument $bar"
this.bar = bar
}
#TaskAction
void doFoo() {
// task logic using the bar variable
}
}

How to provide the value of a #Nested property of a gradle task?

The gradle doc describes the #Nested annotation for custom gradle tasks:
https://docs.gradle.org/current/userguide/more_about_tasks.html#sec:task_input_output_annotations
Unfortunately, there is no complete example of this mechanism in terms of how it is used in a build.gradle file. I created a project to demonstrate a strange exception that happens whenever gradle configures the project:
https://github.com/NicolasRouquette/gradle-nested-property-test
The build.gradle has the following:
task T(type: NestedTest) {
tool = file('x')
metadata = {
a = "1"
}
}
The NestedTest custom task is in the buildSrc folder:
class NestedTest extends DefaultTask {
#InputFile
public File tool
#Nested
#Input
public Metadata metadata
#TaskAction
def run() throws IOException {
// do something...
}
}
The important bit is the #Nested property whose type is really basic:
class Mlang-groovyetadata {
String a
}
When I execute the following: ./gradlew tasks, I get this:
Build file '/opt/local/github.me/gradle-nested-property-test/build.gradle' line: 26
* What went wrong:
A problem occurred evaluating root project 'gradle-nested-property-test'.
> Cannot cast object 'build_6wy0cf8fn1e9nrlxf3vmxnl5z$_run_closure4$_closure5#2bde737' with class 'build_6wy0cf8fn1e9nrlxf3vmxnl5z$_run_closure4$_closure5' to class 'Metadata'
Can anyone explain what is happening and how to make this work?
Nicolas
Looking at the unit tests in Gradle's source code, I found that the syntax for #Nested properties requires invoking the type constructor in the build.gradle file.
That is, the following works:
task T(type: NestedTest) {
tool = file('x')
metadata = new Metadata(
a: "1"
)
}

Can a Gradle task return a value?

I'm writting a custom Gradle Task. Assuming the following is valid:
class MyTask extends DefaultTask {
#TaskAction
def doAction() {
return "my task""
}
}
I'm might be missing something obvious, but how do I get the value back when calling the task?

Passing parameter to custom Gradle task

I've written simple custom Gradle task that extends DefaultTask and does some action and I would like to pass it some parameter(s) using command line. At the bottom is code for adding task to list of available tasks and "implementation" of the task.
Now, when I execute: ./gradlew customTask -PcustomParam="value" how can I retrieve customParam value in doAction method?
project.tasks.create("customTask", CustomTask::class.java
open class CustomTask : DefaultTask() {
#TaskAction
fun doAction() {
// retrieve passed parameter
}
}
if (project.hasProperty('customParam')) {
println project.property('customParam')
}
#see project.property(String name)

Gradle Custom Task Configuration

I'm working on a Gradle plugin that has a Custom Task with two member variables that I would like to initialize using an extension class. I am extending the plugin class as follows:
class CustomPlugin implements Plugin<Project> {
#Override void apply(Project project) {
def extension = project.extensions.create("Custom", CustomExtension)
project.task("doTask", type: CustomTask, {
group = "Awesome"
description = "Runs a custom routine"
filePath = extension.filePath
name = extension.name
})
}
}
Is this the proper way to initialize a Task that extends DefaultTask? I'm trying to understand if initialization is done in CustomPlugin or if within the CustomTask one would use:
#TaskAction void removeUnusedResources() {
String filePath = project.Custom.lintXmlFilePath
String name = project.Custom.ignoreResFiles
// Proceed with the task action
}
Only the second approach seems to work for me. One common pattern I am noticing in other plugins is that tasks tend to be defined within the plugin using project.task("taskName") << { // task actions here} instead of creating a separate class that extends DefaultTask. What is the right convention and where can I find more information?

Resources