Relentless Coding

A Developer’s Blog

Using Groovy's AntBuilder to Zip and Unzip Files

Need to zip or unzip files? Let’s take a look at how Groovy solves this.

Suppose we need to zip a bunch of Python files (without their compiled counterparts *.pyc). The next (admittedly contrived) example shows how we could go about doing something like this in Groovy:

File srcDir = new File('/home/neftas/Downloads/scripts/')
File destDir = new File(srcDir, 'antexample')
File zippedFile = new File(srcDir, 'antzipped.zip')

def allPythonFilenames = srcDir.list()
    .sort()
    .findAll { it.endsWith('.py') }
assert ['a.py', 'b.py', 'c.py'] == allPythonFilenames

def ant = new AntBuilder()

ant.with {
    echo 'begin zipping and unzipping'
    zip(destfile: zippedFile, basedir: srcDir, includes: '*.py')
    mkdir(dir: destDir)
    unzip(src: zippedFile, dest: destDir)
    echo 'done zipping and unzipping'
}

// zip file is created
assert zippedFile.exists()
// contents of zip file should match content of source directory
def commands = ['bash', '-c', "zipinfo -1 ${zippedFile.name}"]
def process = commands.execute(null, srcDir)
def contentsOfZip = process.text.split(System.lineSeparator)
assert contentsOfZip.sort() == allPythonFilenames

// all files should be unpacked from the zip into the right directory
assert destDir.list().sort() == allPythonFilenames

ant.with {
    echo 'deleting created files'
    // notice nested Ant task
    delete(includeEmptyDirs: true) {
        fileset(dir: destDir)
        fileset(file: zippedFile)
    }
    echo 'deleted created files'
}

We can use all the power of Ant in our Groovy scripts. Ant task names map to Groovy methods (see the zip method above) and the attributes are passed as maps to these methods. What’s even better, there is no need to stringify the arguments of these attributes (as is required in Ant’s XML), but we can directly use the correct datatypes (e.g. in the key-value pair destfile: zippedFile, zippedFile is of type java.util.File). All attributes of Ant tasks are available to use with AntBuilder (see Ant manual for zip task).

To use nested Ant tasks, we create closures, so that Ant’s:

<delete includeEmptyDirs="true">
    <fileset dir="lib">
    <fileset file="file.ext">
</delete>

results in the following Groovy code:

ant.delete(includeEmptyDirs: true) {
    fileset(dir: 'lib')
    fileset(file: 'file.ext')
}

Invoking from Gradle

AntBuilder is also available in Gradle. This will come in handy when you don’t know the “Gradle way” of doing something, but do know how to tackle it in Ant.

Dependencies

Groovy (and Gradle) come with a bundled version of AntBuilder, so you should be good shape when creating a Groovy script, but if you want to use AntBuilder in a project, you should add ant and ant-launcher to your build.gradle:

dependencies {
    compile group: 'ant', name: 'ant',  version: '1.7.0'
    compile group: 'ant', name: 'ant-launcher',  version: '1.6.5'
}