Copy from paths within an archive

Gradle allows easy extraction of archive content through using ‘Project’'s ‘tarTree()’(or ‘zipTree()’) method as source for a copy operation. With ‘include’/‘exclude’ it is also easy to limit the extraction to partial archive content with full paths within the archive.

What is currently not easily possible is extracting subtrees within the archive. I have use case examples for that in my current project, which bundles tomcat, with a custom web app dir. A tomcat download looks like this (shortened):

  apache-tomcat-7.0.27.tar.gz  |-- apache-tomcat-7.0.27  |

|-- bin  |

|-- conf  |

|-- webapps  |

|

|-- ROOT  |

|

'-- manager  

Use case 1 Copy the full archive content (with a few excludes) into the directory “tomcat” within the target, stripping/renaming the base directory apache-tomcat-7.0.27 to “tomcat”.

Use case 2 Copy the “manager” web app subdirectory to a separate directory “webapps/manager” in the target, on the same level as above “tomcat” directory.

Current situation Renaming the destination path is only possible with a call to ‘eachFile {}’ that manipulates the destination path, eg.

from(tarTree("apache-tomcat-7.0.27.tar.gz"))
into("tomcat")
eachFile {FileCopyDetails details ->
 details.path = (details.path - "apache-tomcat-7.0.27")
}

IMO that is to much programmatic logic and not enough semantic expressiveness for a build script. (Additionally it doesn’t fully work because of GRADLE-2255 and similar, causing the need for extra code to remove the unwanted directory tree in the target). For that first use case, a ‘rename()’ method that operates on the full path instead of the file name only would help, but for the second use case, it would still not fully express what is happening.

Proposal Especially for the second use case, I therefore propose to provide a way to specify a path within a an archive as input for a file tree creation (or copy operation at least). This could look s.th. like this:

from(tarTree("apache-tomcat-7.0.27.tar.gz", "apache-tomcat-7.0.27/webapps/manager"))

or

from(tarTree("apache-tomcat-7.0.27.tar.gz@apache-tomcat-7.0.27/webapps/manager"))

or even

from(tarTree("apache-tomcat-7.0.27.tar.gz/apache-tomcat-7.0.27/webapps/manager"))

A slightly different approach, that would perhaps be even better:

from(tarTree("apache-tomcat-7.0.27.tar.gz").subtree("apache-tomcat-7.0.27/webapps/manager"))

In that case ‘subtree()’ would be a general capability of ‘FileTree’.

I came across exactly this problem just today and was wondering if there ever has been any kind of update that makes this kind of task a little more groovy. Worked around it with a second copy-task and I’m not very happy withit. It works though, but I’m still searching for a better implementation.