Linking @OutputDirectory to @InputFiles for incremental build

I understand the basics of incremental build, but there’s one particular case I can’t get my head round: what if the output of one task is a directory and the input of another is a set of files? How do I link them?

As an example, imagine I have this trivial task with a set of input files and an output:

class DoIt extends DefaultTask {
    @InputFiles FileCollection files
    @OutputFile File outputFile

    @TaskAction
    void doIt() {
        outputFile.setText(files.sum { it.size() }.toString(), "UTF-8")
    }
}

I want to create an instance of this task that takes the output files of a Java compilation:

task doIt(type: DoIt) {
    files = fileTree(compileJava.destinationDir) {
        builtBy compileJava
    }
    outputFile = file("$buildDir/classSize.txt")
}

As you can see, I use the fileTree() method to turn the destination directory into a file collection, but this breaks the link to the compileJava task, hence a bit of duplication with the builtBy.

I noticed that if I use a simple Copy task instead, I can use from compileJava and the incremental build works fine. I don’t need to use a builtBy. Is there a way to replicate this behaviour?

In this case you could simply assign the task’s output files. TaskOutputs.getFiles() provides a return value of type FileCollection. Using the output of a task as the input for another task indicates to Gradle that the task dependency should be inferred.

task doIt(type: DoIt) {
    files = compileJava.outputs.files
}

Thanks. Does that work even if there’s only an @OutputDirectory annotation declared? I just want to check that this isn’t something specific to the JavaCompile task.

Yes, that works as well. TaskOutputs.getFiles() also returns output directories.