How do I zip a list of files preserving hierarchy?

I have a list of file paths (say, ‘myFiles’), and I want to create a ‘Zip’ task that will zip them while preserving the directory hierarchy. The naive way (‘from(myFiles)’) dumps all files into the root of the archive - not what I want.

Here’s what I ended up with (this is a simplification of the actual code):

from(projectDir) {
    def myDirectories = new HashSet<RelativePath>()
    myFiles.each {
      def parent = it.parent
      while (parent != null) {
        myDirectories.add(parent)
        parent = parent.parent
      }
    }
      include { fte ->
      myFiles.contains(fte.relativePath) || myDirectories.contains(fte.relativePath)
    }
  }

This works, but it feels wrong. I’m essentially telling Gradle to zip everything and then filter all files except the one I want. Plus, it’s awfully verbose for such a seemingly simple task.

I’ve also thought of perhaps looping over the list of files and calling ‘from’/‘into’ for each of them, but that too feels like a hack.

So is there a simpler way of doing this?

A ‘FileCollection’ is a flat structure. If you want to keep the entire parent directory hierarchy I know no other way then to do a copy from the top and filter the contents. However, there is a simpler way to do the filtering.

from(projectDir) {

include {

myFiles.asFileTree.asPath.contains(it.file.canonicalPath)

}

}

I see, thank you.

Your solution has the disadvantage of potentially including extra files, though. E.g. if ‘myFiles’ contains ‘/a/a/b’, then this method will also admit ‘/a/b’.

I think I’ll go with my second approach after all (adding each file in a loop). It seems the most natural.

You could try.

myFiles.asFileTree.asPath.split(File.separator).contains(it.file.canonicalPath)