Best way to have relative paths in incremental build


(Lapo Luchini) #1

I’m creating a task to gzip all files in a FileTree in a different directory; as I want to mirror the input’s directory structure I need the relative path of input files but IncrementalTaskInputs doesn’t give me that, so I solved it visiting the input FileTree like this:

class CompressTask extends DefaultTask {
    @InputFiles
    FileTree input
    @OutputDirectory
    File output
    def gzip(byte[] input) {
        def os = new java.io.ByteArrayOutputStream()
        def gz = new java.util.zip.GZIPOutputStream(os) { { def.setLevel(java.util.zip.Deflater.BEST_COMPRESSION); } }
        gz.write input
        gz.close()
        return os.toByteArray()
    }
    String getRelativePath(File file) {
        String path = null
        input.visit { FileVisitDetails details ->
            if (details.file == file) {
                path = details.getRelativePath()
                details.stopVisiting()
            }
        }
        if (path == null)
            throw new Exception('File not found in input FileTree: ' + file.getPath());
        return path;
    }
    @TaskAction
    void execute(IncrementalTaskInputs inputs) {
        if (!inputs.incremental)
            project.delete(output.listFiles())
        inputs.outOfDate { change ->
            File file = change.file
            String path = getRelativePath(file)
            File out = new File(output, path + '.gz')
            out.parentFile.mkdirs()
            out.bytes = gzip(file.bytes)
        }
    }
}

I don’t really like visiting the FileTree for each file but I found no other way to do it.
I’m also pretty new to Gradle, is there a better way to solve this kind of (pretty typical, I’d say) task?