# The <groovy> Ant Task

version 6.0.0-beta-1

## 1. `<groovy>`

| Here we describe an Ant task for using Groovy from within an Ant build file. You may also be interested in Ant’s built-in `script` task which supports Groovy and other languages, or `AntBuilder` which lets you write Ant build scripts in Groovy rather than XML.

Executes a series of Groovy statements from Apache Ant. Statements can either be read in from a resource or as direct text between the enclosing Groovy tags.

## 2. Required taskdef

Assuming all the groovy jars you need are in my.classpath (this will be `groovy-VERSION.jar`, `groovy-ant-VERSION.jar` plus any modules and transitive dependencies you might be using) you will need to declare this task at some point in the `build.xml` prior to the `groovy` task being invoked.

    <taskdef name="groovy"
             classname="org.codehaus.groovy.ant.Groovy"
             classpathref="my.classpath"/>

You can simply place statements between the `groovy` tags like this:

    <groovy>
    ...
    </groovy>

Or you can supply the Groovy source script as a resource. You can specify the pathname using the `src` attribute like this:

    <groovy src="/some/path/MyGroovyScript.groovy" otherAttributes="...">

Or as a nested `fileset` like this (though the fileset definition is expected to select just one file):

    <groovy>
        <fileset file="MyGroovyScript.groovy"/>
    </groovy>

Or as a nested single element resource collection which could look like any of these:

    <groovy>
        <file file="MyGroovyScript.groovy"/>
    </groovy>

    <groovy>
        <url url="https://some.domain/some/path/to/MyGroovyScript.groovy"/>
    </groovy>

    <groovy>
        <javaconstant name="some.packagename.SomeClass.MY_CODE_FRAGMENT"/>
    </groovy>

You may also supply a filter chain like this:

    <groovy>
        <fileset file="MyGroovyScript.groovy"/>
        <!-- take 5 lines after skipping 18 lines, just as an example -->
        <filterchain>
            <headfilter lines="5" skip="18"/>
        </filterchain>
    </groovy>

You might need to use the contextClassLoader attribute (see below) if any of your modules load services via the classpath, e.g. `groovy-json`.

## 3. <groovy> attributes

Attribute | Description | Required
--- | --- | ---
src | File containing Groovy statements. The directory containing the file is added to the classpath. | Yes, unless statements enclosed within tags
classpath | The classpath to use. | No
classpathref | The classpath to use, given as reference to a PATH defined elsewhere. | No
output | Set the output file; defaults to the Ant log. | No
append | If enabled and output is to a file, append to existing file rather than overwrite. Defaults to false. | No
fork | If enabled the script will be executed in a forked JVM process (disabled by default). | No
inheritAll | If enabled and `fork` is true, all properties from the parent Ant project are passed to the forked JVM as system properties. For selective passing, use a nested `<syspropertyset>` instead. Defaults to false. | No
scriptBaseClass | The name of the base class for scripts. | No
parameters | Generates metadata for reflection on method parameter names on JDK 8 and above. Defaults to false. | No
useGroovyShell | If enabled a new GroovyShell is used to run the script. Special variables won’t be available but you don’t need Ant in the classpath. Defaults to false. | No
includeAntRuntime | If enabled the system classpath will be included on the classpath when forking. Defaults to true. | No
stacktrace | If enabled a stacktrace will be reported if an error occurs during compilation. Defaults to false. | No
configScript | Sets the configuration script for the groovy compiler configuration. | No
contextClassLoader | If enabled, the contextClassLoader to be set with the classLoader of the shell used to run the script. Not used if fork is true. | No

## 4. Parameters specified as nested elements

### 4.1. <classpath>

Groovy’s classpath attribute is a PATH like structure and can also be set via a nested classpath element.

### 4.2. <arg>

Arguments can be set via one or more nested <arg> elements using the standard Ant command line conventions.

### 4.3. <sysproperty> and <syspropertyset>

Because `<groovy>` extends Ant’s `<java>` task, you can use nested `<sysproperty>` and `<syspropertyset>` elements to pass specific properties into the forked JVM when `fork="true"`. The forked script reads them via `System.getProperty("name")`.

If you want to pass all properties from the parent Ant project, set `inheritAll="true"` instead. Explicit `<sysproperty>` and `<syspropertyset>` entries take precedence on name collision.

| The `properties` binding (see below) reflects only the child JVM’s Ant project when `fork="true"`, not the parent project’s properties. Use system properties (via `<sysproperty>`, `<syspropertyset>`, or `inheritAll`) to communicate values to a forked script.

## 5. Available bindings

A number of bindings are in scope for use within your Groovy statements.

Name | Description
--- | ---
ant | an instance of `AntBuilder` that knows about the current ant project
project | the current ant project
properties | a `Map` of ant properties
target | the owning target that invoked this groovy script
task | the wrapping task, can access anything needed in `org.apache.tools.ant.Task`
args | command line arguments, if any

## 6. Examples

Hello world, version 1:

    <groovy>
    println "Hello World"
    </groovy>

Hello world, version 2:

    <groovy>
    ant.echo "Hello World"
    </groovy>

List all xml files in the current directory:

    <groovy>
    xmlfiles = new File(".").listFiles().findAll{ it =~ "\.xml$" }
    xmlfiles.sort().each { println it.toString() }
    </groovy>

List all xml files within a jar:

    <zipfileset id="found" src="foobar.jar"
                includes="**/*.xml"/>
    <groovy>
        project.references.found.each {
            println it.name
        }
    </groovy>

Run a script:

    <groovy src="/some/directory/some/file.groovy">
      <classpath>
        <pathelement location="/my/groovy/classes/directory"/>
      </classpath>
    </groovy>

Find all `Builder` classes having an `org.*` package within a directory of jars:

    <property name="local.target" value="C:/Projects/GroovyExamples"/>
    <groovy>
    import java.util.jar.JarFile
    def classes = []
    def resourceNamePattern = /org\/.*\/.*Builder.class/
    def jarNamePattern = /.*(beta|commons).*jar$/

    def libdir = new File("${properties['local.target']}/lib")
    libdir.listFiles().grep(~jarNamePattern).each { candidate ->
        new JarFile(candidate).entries().each { entry ->
            if (entry.name ==~ resourceNamePattern) classes += entry.name
        }
    }
    properties["builder-classes"] = classes.join(' ')
    </groovy>
    <echo message='${builder-classes}'/>

Which might result in something like:

    org/apache/commons/cli/PatternOptionBuilder.class org/apache/commons/cli/OptionBuilder.class org/codehaus/groovy/tools/groovydoc/GroovyRootDocBuilder.class org/custommonkey/xmlunit/HTMLDocumentBuilder.class org/custommonkey/xmlunit/TolerantSaxDocumentBuilder.class

FileScanner version of above (with a slight variation on collecting the names):

    <groovy>
    import java.util.jar.JarFile
    def resourceNamePattern = /org\/.*\/.*Builder.class/
    def candidates = ant.fileScanner {
        fileset(dir: '${local.target}/lib') {
            include(name: '*beta*.jar')
            include(name: '*commons*.jar')
        }
    }
    def classes = candidates.collect {
        new JarFile(it).entries().collect { it.name }.findAll {
            it ==~ resourceNamePattern
        }
    }.flatten()
    properties["builder-classes"] = classes.join(' ')
    </groovy>

Calling out to a web service from your Ant script:

    <?xml version="1.0" encoding="UTF-8"?>
    <project name="SOAP example" default="main" basedir=".">
        <property environment="env"/>
        <property name="celsius" value="0"/>
        <target name="main">
            <taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy">
                <classpath>
                    <fileset dir="${env.GROOVY_HOME}" includes="lib/groovy-*.jar,lib/ivy*.jar"/>
                </classpath>
            </taskdef>
            <groovy>
                @Grab('org.codehaus.groovy.modules:groovyws:0.5.1')
                import groovyx.net.ws.WSClient
                def url = 'http://www.w3schools.com/webservices/tempconvert.asmx?WSDL'
                def proxy = new WSClient(url, this.class.classLoader)
                proxy.initialize()
                ant.echo "I'm freezing at ${properties.celsius} degrees Celsius"
                properties.result = proxy.CelsiusToFahrenheit(properties.celsius)
            </groovy>
            <antcall target="results"/>
        </target>
        <target name="results">
            <echo message="I'm freezing at ${result} degrees Fahrenheit"/>
        </target>
    </project>

Which will output the following (along with some informational messages):

    main:
         ...
         [echo] I'm freezing at 0 degrees Celsius
    results:
         [echo] I'm freezing at 32 degrees Fahrenheit

    BUILD SUCCESSFUL

Setting arguments:

    <target name="run">
        <groovy>
            <arg line="1 2 3"/>
            <arg value="4 5"/>
            println args.size()
            println args[2]
            args.each{ ant.echo(message:it) }
        </groovy>
    </target>

Passing Ant properties into a forked JVM selectively via `<syspropertyset>`:

    <property name="myapp.url" value="https://example.com"/>
    <property name="myapp.timeout" value="30"/>
    <groovy fork="true">
        <syspropertyset>
            <propertyref prefix="myapp."/>
        </syspropertyset>
        println "Calling ${System.getProperty('myapp.url')} with timeout ${System.getProperty('myapp.timeout')}"
    </groovy>

Or pass every parent property at once with `inheritAll`:

    <property name="target.env" value="staging"/>
    <groovy fork="true" inheritAll="true">
        println "Deploying to ${System.getProperty('target.env')}"
    </groovy>

Output:

    Buildfile: build.xml

    run:
       [groovy] 4
       [groovy] 3
         [echo] 1
         [echo] 2
         [echo] 3
         [echo] 4 5

    BUILD SUCCESSFUL