Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Gradle Goodness: Using the Incremental Task Action

DZone's Guide to

Gradle Goodness: Using the Incremental Task Action

In Gradle, the incremental task action is a great way to deal with transformations and changes, simplifying the work needed to process updates.

· Java Zone
Free Resource

Find your next Integration job at DZone Jobs. See jobs focused on integration, or create your profile and have the employers come to you!

Gradle has incremental build support to speed up our builds. This means Gradle checks inputs and outputs for a task, and if something changed, the task is executed. Otherwise, the task is skipped. In previous posts, we learned how to add incremental build support to our tasks with annotations and the inputs and outputs properties of a task. When we have a task that has an output file for an input file, like with transformations, we can have a more efficient task using an incremental task action. With an incremental task action, we have extra information on the files that are handled by the task. We can have different actions based on whether an input file is out of date or removed. This way, we can handle only the input files that have changed or removed with incremental builds, instead of all the input files.

To create an incremental task action, we must have a task action method (annotated with @TaskAction) that has a single argument of type IncrementalTaskInputs. The IncrementalTaskInputs class has the method outOfDate and removed. These methods take an action, which can be implemented with a closure, with an instance of InputFileDetails as the argument. We can get to the input file via this instance and use that for our task logic. When an input file is out of date, because the file's contents have changed or the output file has been removed, the action we defined for the outOfDate method is invoked. If the input file is removed, the action for the method removed is invoked.

// Create task to convert text to HTML.
task convert(type: HtmlConverter) {
    sourceDir = file('src/docs/text')
    outputDir = file("${buildDir}/html")
}

import groovy.xml.MarkupBuilder
import groovy.transform.CompileStatic
import groovy.transform.CompileDynamic

/**
 * Simple Gradle task that takes an text
 * input file and converts it to a HTML file.
 */
@CompileStatic
class HtmlConverter extends DefaultTask {

    @InputDirectory
    @PathSensitive(PathSensitivity.RELATIVE)
    File sourceDir

    @OutputDirectory
    File outputDir

    /**
     * Task action that will check if a source file is out of date
     * or removed. If out of date the source file is converted
     * to HTML. If source file is removed the generated
     * HTML file is removed.
     *
     * @param inputs Used for incremental task action.
     */
    @TaskAction
    void convert(IncrementalTaskInputs inputs) {
        // If the user for example used --rerun-tasks
        // this task is not incremental. Only
        // inputs.outOfDate is executed, so we must first
        // remove all output files.
        if (!inputs.incremental) {
            project.delete(outputDir.listFiles())
        }

        // Input file has changed, so we convert it.
        inputs.outOfDate { InputFileDetails outOfDate ->
            convertFile(outOfDate.file)
        }

        // Input file is removed, so we remove the
        // output file that was created for the input file.
        inputs.removed { InputFileDetails removed ->
            removeOutputFile(removed.file)
        }
    }

    /**
     * Convert text file to HTML.
     *
     * @param file Text file to convert to HTML.
     */
    private void convertFile(final File file) {
        logger.lifecycle 'Convert file {}', file.name
        final lines = file.readLines()
        final outputWriter = new FileWriter(new File(outputDir, outputFilename(file)))
        writeHtml(lines, outputWriter)
    }

    /**
     * Use first line as title for HTML, rest is body.
     *
     * @param lines Lines to transform to HTML.
     * @param writer Writer to write HTML to.
     */
    @CompileDynamic
    private void writeHtml(final List lines, final Writer writer) {
        final html = new MarkupBuilder(writer)
        html.html {
            head {
                title lines[0]
            }
            body {
                lines[2..-1].each { line ->
                    p line
                }
            }
        }
    }

    /**
     * Remove the output file thas was created for the
     * given input file.
     *
     * @param file Input file to remove output file for.
     */
    private void removeOutputFile(final File file) {
        logger.lifecycle 'Remove HTML for file {}', file.name
        new File(outputDir, outputFilename(file)).delete()
    }

    /**
     * Determine HTML output filename based on base of input filename.
     *
     * @param file Used to create HTML output file name.
     */
    private String outputFilename(final File file) {
        file.name[0..file.name.lastIndexOf('.')] + 'html'
    }

}


In our project, we have three source files in the directory src/docs/text: sample1.txt, sample2.txt and hello.txt. We run the convert task for the first time and see all input files are processed:

$ gradle convert
:convert
Convert file hello.txt
Convert file sample1.txt
Convert file sample2.txt

BUILD SUCCESSFUL

Total time: 0.948 secs


Next, we change hello.txt and, when we re-run the task, we see only our changed file is processed. If we rename it after the change, we can see the hello.html is removed and the new file is processed:

$ echo "Gradle rocks" >> src/docs/text/hello.txt
$ gradle convert
:convert
Convert file hello.txt

BUILD SUCCESSFUL

Total time: 0.793 secs
$ mv src/docs/text/hello.txt src/docs/text/sample.txt
$ gradle convert
:convert
Convert file sample.txt
Remove HTML for file hello.txt

BUILD SUCCESSFUL

Total time: 0.76 secs
$


Written with Gradle 3.5.

Find your next Integration job at DZone Jobs. See jobs focused on integration, or create your profile and have the employers come to you!

Topics:
java ,gradle ,task arguments ,processing ,tutorial

Published at DZone with permission of Hubert Klein Ikkink, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}