groovygradle

Flatten first directory of a FileTree in Gradle


I'm writing a task to extract a tarball into a directory. I don't control this tarball's contents.

The tarball contains a single directory which contains all the files I actually care about. I want to pull everything out of that directory and copy that into my destination.

Example:

/root/subdir
/root/subdir/file1
/root/file2

Desired:

/subdir
/subdir/file1
/file2

Here's what I tried so far, but this seems like a really goofy way of doing it:

copy {
    eachFile {
        def segments = it.getRelativePath().getSegments() as List
        it.setPath(segments.tail().join("/"))
        return it
    }
    from tarTree(resources.gzip('mytarfile.tar.gz'))
    into destinationDir
}

For each file, I get the elements of its path, remove the first, join that with /, then set that as the file's path. And this works...sort of. The problem is that this creates the following structure as a result:

/root/subdir
/root/subdir/file1
/root/file2
/subdir
/subdir/file1
/file2

I'm fine with just removing the root directory myself as a final action of the task, but I feel like there should be a much simpler way of doing this.


Solution

  • AFAIK, the only way is to unpack the zip, tar, tgz file :(

    There is an open issue here Please go vote for it!

    Until then, the solution isn't very pretty, but not that hard either. In the example below, I am assuming that you want to remove the 'apache-tomcat-XYZ' root-level directory from a 'tomcat' configuration that only includes the apache-tomcat zip file.

    def unpackDir = "$buildDir/tmp/apache.tomcat.unpack"
    task unpack(type: Copy) {
        from configurations.tomcat.collect {
            zipTree(it).matching {
                // these would be global items I might want to exclude
                exclude '**/EMPTY.txt'
                exclude '**/examples/**', '**/work/**'
            }
        }
        into unpackDir
    }
    
    def mainFiles = copySpec {
        from {
            // use of a closure here defers evaluation until execution time
            // It might not be clear, but this next line "moves down" 
            // one directory and makes everything work
            "${unpackDir}/apache-tomcat-7.0.59"
        }
        // these excludes are only made up for an example
        // you would only use/need these here if you were going to have
        // multiple such copySpec's. Otherwise, define everything in the
        // global unpack above.
        exclude '**/webapps/**'
        exclude '**/lib/**'
    }
    
    task createBetterPackage(type: Zip) {
        baseName 'apache-tomcat'
        with mainFiles
    }
    createBetterPackage.dependsOn(unpack)