I have an incremental custom task that takes an arbitrary number of input files and converts them 1:1 to output files. The task implementation is pretty much boilerplate:
public abstract class MyCustomTask extends DefaultTask {
@InputFiles
@SkipWhenEmpty
@IgnoreEmptyDirectories
@PathSensitive(PathSensitivity.RELATIVE)
public abstract ConfigurableFileCollection getSources();
@OutputDirectory
public abstract DirectoryProperty getOutputDirectory();
@TaskAction
public void execute(InputChanges inputChanges) {
for (FileChange change : inputChanges.getFileChanges(getSources())) {
if (change.getFileType() == FileType.FILE) {
// Handle each added/modified/removed file here
}
}
}
}
Everything works fine until I put something like this in the build script:
task.sources.from zipTree("some-file.zip")
To my surprise, InputChanges
reports the zip file itself as added or modified, rather than its contents (while the file collection contains the contents of it, as expected). Is this the intended behavior? The problem is that the task has no clue what to do with such an entry in InputChanges
. Not only it is unprepared to deal with zip files, but it has no (easy) way of knowing that the particular file is a zip to begin with. What is the task supposed to do in such a situation?
The only way I have been able to find for the task to detect a container file (such as zip) among its inputs is by using FileCollectionInternal.visitStructure(...)
to inspect the input file collection and match each entry in InputChanges
to the results of that inspection. That feels a bit cumbersome, but it can be done. However, I’m not very fond of the idea to use internal API, for obvious reasons. Is there a better way to achieve the same by using only public API?
Even if the task is able to detect an input zip file reliably, that solves only a part of the problem. The remaining part is that when the zip file has changed, the task only knows which files it currently contains, not which files it contained during the previous invocation. So the task has no way of knowing which output files it should remove because of their corresponding sources no longer being present in the zip file. I can’t think of a way to solve this problem, other that by having the task implement its own tracking of modifications of the contents of zip files (which I imagine would not be a trivial thing to do).
Now I’m puzzled as to what to do next. Is the scenario I am describing supported by Gradle at all? If not, I would like to at least have a way for the task to detect it and fail with a meaningful message. Any suggestions are greatly appreciated.