I’m trying to author my first small Gradle plugin. I got the logic working as a task in build.gradle
, and now I’d like to move it to a Groovy class. It looks like I want to implement Plugin<Project>
, according to the documentation. I also want to specify an @OutputFile
, but I don’t know how to do that correctly. I’ve tried:
@OutputFile
abstract RegularFile outputFile = project.layout.projectDirectory.file("output.txt")
since project.layout.projectDirectory.file()
worked in build.gradle
. However, it looks like project
is not defined at the class level (makes sense since it’s an argument to apply
). I couldn’t find anything in the documentation that addresses this. How should this be done?
If you haven’t already, I suggest reading the other topics under Developing Gradle Plugins as well. I think Implementing Plugins might be most applicable to your scenario.
In general, you want to create re-usable task classes that the plugin uses to register instances of based on some convention/pattern/model. For a basic example, I want a plugin that supplies a task for joining two text files. I’m going to assume the latest version of Gradle is used, so if you need to support older versions this code may not work.
First we need a task class to do the actual join.
abstract class FileJoinTask extends DefaultTask {
@InputFile
abstract RegularFileProperty getFirstFile()
@InputFile
abstract RegularFileProperty getSecondFile()
@OutputFile
abstract RegularFileProperty getOutputFile()
@TaskAction
void joinFiles() {
File outFile = outputFile.get().asFile
outFile.parentFile.mkdirs()
outFile.text = firstFile.get().asFile.text + secondFile.get().asFile.text
}
}
Now the plugin needs to register an instance of the FileJoinTask
class. By convention I’ve decided that the plugin will join 2 files named one.txt
and two.txt
in the project directory and output the results to joined.txt
in the project’s build directory. Modelling a plugin is usually more complex and involves adding project extensions, but I’ll leave that out just to focus on what you’re doing.
class FileJoinPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.tasks.register("joinFiles", FileJoinTask) { jt ->
jt.group = "file joiner"
jt.firstFile.convention(project.layout.projectDirectory.file("one.txt"))
jt.secondFile.convention(project.layout.projectDirectory.file("two.txt"))
jt.outputFile.convention(project.layout.buildDirectory.file("joined.txt"))
}
}
}
Ahhh, I didn’t realize a task needs to be in its own class; I thought the plugin class could contain all the logic. I’ll work to separate these concerns and see how that goes.
I have read through (at least at a high level) all the pages in Implementing Gradle Plugins, but it’s often confusing or seems to leave things out to a naive reader.