/ Gradle Build Tool

Defining optional input files and directories for Gradle tasks

To define a input file for a task you usually use either @InputFile or @InputDirectory depending on if you require a file or directory as input. However, this only works when the directory really exists on the file system, if the file or directory does not exist then this will throw an exception.

So how do we go about defining optional input files?

Turns out there does not exist a built-in solution for this but with a little imagination we can accomplish it with the @Optional annotation and a Closure.

Here is an example:

final Closure<File> inputDir = { new File('/path/to/dir').with { it.exists() ? it : null }

So why does this work?

The @Optional annotation defines that the property is optional in a sense that it either has a value or can be null to define the value is missing and the input should be ignored.

By using @Optional we prevent Gradle from complaining about a missing input value but it still will not solve the problem as we still can define a File which does not exist and Gradle will still complain about an @InputDirecory that does not exist.

To solve the second issue we are going to use a closure with where we mutate the File instance to either be returned if it exists or else we return null to denote it does not exist.

We use the .with{} method to mutate the instance and since we are returning null in the case the File does not exist then @Optional definition is completed and Gradle understands that this input should not be considered.

So why did we use a Closure instead of assigning the File directly to the field?

The reason is that if we would have assigned it directly the existance of the file would have been checked at object construction time. With the Closure in place we have deferred the evaluation until the value is actually needed by Gradle. By doing this we have a possibility to create the directory if it does not exist in a previous task before Gradle evaluates the @InputDirectory value.