How can I expand only a particular subdirectory of a zip(Tree)?


(Luis Trigueiros) #1

How can I expand contents from a zipTree in a way that only the contents of a given sub directory gets extracted


(Peter Niederwieser) #2

Use an include filter:

task unzip(type: Copy) {
  from zipTree(zipFile)
  into "unzipped"
  include "dir/to/unzip/**"
}

(Luis Trigueiros) #3

Hi Peter thank you this has but this does unzip’s but it extracts the all directory tree and not the contents from that given subdirectory. Say if the contents of the zip where: /A—+

|

B—C

|

D----E

|-----F If the include is “A/D”, I was expecting to have only E F In the output


(Peter Niederwieser) #4

If the include is “A/D”, I was expecting to have only E F In the output

That’s not how include works. Ideally, you could achieve your goal with rename. However, rename currently operates on file names rather than file paths. What you can do is to add another copy task/action that copies everything below A/D to a new place. Or, code a solution based on zipTree(zipFile).visit { … }.


(Luis Trigueiros) #5

Thank you, Peter


(Mike Meessen) #6

Vote++ for a “rename” variant that can operate on full file paths :wink:


(Luke Daley) #7

You can use the ‘eachFile {}’ hook to do this.

task unzip(type: Copy) {
  from zipTree(zipFile)
  into "unzipped"
  eachFile { FileCopyDetails fcp ->
    if (fcp.relativePath.pathString.startsWith("dir/to/unzip/")) {
      // remap the file to the root
      fcp.relativePath = new RelativePath(fcp.file, fcp.relativePath.segments[3..-1])
    } else {
      fcp.exclude()
    }
  }
}

That’s untested, but it should be pretty close.

docs:

http://www.gradle.org/docs/current/javadoc/org/gradle/api/file/RelativePath.html http://gradle.org/docs/current/dsl/org.gradle.api.tasks.Copy.html#org.gradle.api.tasks.Copy:eachFile(groovy.lang.Closure)


(clankow) #8

@Luke it is necessary to coerce the segments back into a String Array after removing elements. The code below works but has the unintended side effect of also copying the original directory structure with no files in it. Any thoughts?

eachFile { FileCopyDetails fcp ->
            if (fcp.relativePath.pathString.startsWith(appName)) {
              // remap the file to the root
              def segments = fcp.relativePath.segments
              def pathsegments =segments[1..-1] as String[]
              fcp.relativePath = new RelativePath(!fcp.file.isDirectory(), pathsegments)
            }
            else {
              fcp.exclude()
            }
        }

How to rename a new directory created as result of unzip?
(Luke Daley) #9

You need to specify to ignore empty dirs:

task unzip(type: Copy) {
  …
  includeEmptyDirs = false
}

(clankow) #10

We actually do have directories in the structure that are empty that we would like to unzip. Any Ideas?


(Luke Daley) #11

This is a limitation of the API. You could keep track of what all the directories will be in the eachFile, and use a ‘doLast { project.delete “remapped dir” }’.


(Ryan Gustafson) #12

I’m hitting this same issue. Utility could be improved if the zipTree method took argument for a directory within the archive from which to root the tree. For example:

task unzip(type: Copy) {
   from zipTree(zipFile, root: 'directory/in/the/zip/to/consider/as/root')
   into destDir
   include 'paths/relative/to/root'
}

(Peter Niederwieser) #13

@Ryan, that seems like a good solution to a common problem. Raised GRADLE-3025 to track it.


(opticyclic) #14

Ant to the rescue! https://ant.apache.org/manual/Tasks/unzip.html

task unzip(){
  ant.unzip(src: 'temp/test.war', dest:'lib', overwrite:"true") {
    patternset( ) {
      include( name: 'WEB-INF/lib/*.jar' )
    }
    mapper(type:"flatten")
  }
}

Although the Copy task with the zipTree sort of makes sense, it isn’t the first place you look when trying to unzip something. Why isn’t there a wrapper task called Unzip?


(Mike Meessen) #15

+1 for GRADLE-3025.

I’m trying to combine the output of several subprojects with ‘application’ plugin into one “master” ‘distZip’. Not being able to select the content in the subdirectories of the child distZips direclty is making me put a lot of effort into it…