//////////////////////////////////////////

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing,
  software distributed under the License is distributed on an
  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  KIND, either express or implied.  See the License for the
  specific language governing permissions and limitations
  under the License.

//////////////////////////////////////////
ifndef::core-domain-specific-languages[]
:core-domain-specific-languages: core-domain-specific-languages.adoc
endif::[]

= The <groovy> Ant Task

[[groovy-ant-task-using]]
== `<groovy>`

[NOTE]
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 https://ant.apache.org/manual/Tasks/script.html[`script`] task
which supports Groovy and other languages, or
<<{core-domain-specific-languages}#antbuilder,`AntBuilder`>> which lets you write Ant build scripts
in Groovy rather than XML.

Executes a series of Groovy statements from https://ant.apache.org/[Apache Ant].
Statements can either be read in from a resource or as direct text between the enclosing Groovy tags.

== 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.

[source,xml]
----
<taskdef name="groovy"
         classname="org.codehaus.groovy.ant.Groovy"
         classpathref="my.classpath"/>
----

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

[source,xml]
----
<groovy>
...
</groovy>
----

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

[source,xml]
----
<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):

[source,xml]
----
<groovy>
    <fileset file="MyGroovyScript.groovy"/>
</groovy>
----

Or as a nested single element https://ant.apache.org/manual/Types/resources.html#collection[resource collection] which could look like any of these:

[source,xml]
----
<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 https://ant.apache.org/manual/Types/filterchain.html[filter chain] like this:

[source,xml]
----
<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`.

== <groovy> attributes

[cols="<1,<2,<1",options="header,footer"]
|============================================
|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
|============================================

== Parameters specified as nested elements
=== <classpath>

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

=== <arg>

Arguments can be set via one or more nested <arg> elements using the standard Ant https://ant.apache.org/manual/using.html#arg[command line conventions].

=== <sysproperty> and <syspropertyset>

Because `<groovy>` extends Ant's https://ant.apache.org/manual/Tasks/java.html[`<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.

[NOTE]
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.

== Available bindings

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

[cols="<1,<5",options="header,footer"]
|============================================
|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
|============================================

== Examples

Hello world, version 1:

[source,xml]
---------------------------------------------------------------------------------
<groovy>
println "Hello World"
</groovy>
---------------------------------------------------------------------------------

Hello world, version 2:

[source,xml]
---------------------------------------------------------------------------------
<groovy>
ant.echo "Hello World"
</groovy>
---------------------------------------------------------------------------------

List all xml files in the current directory:

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

List all xml files within a jar:

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

Run a script:

[source,xml]
---------------------------------------------------------------------------------
<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:

[source,xml]
---------------------------------------------------------------------------------
<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:
[source]
---------------------------------------------------------------------------------
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):

[source,xml]
---------------------------------------------------------------------------------
<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:

[source,xml]
---------------------------------------------------------------------------------
<?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):

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

BUILD SUCCESSFUL
---------------------------------------------------------------------------------

Setting arguments:

[source,xml]
---------------------------------------------------------------------------------
<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>`:

[source,xml]
---------------------------------------------------------------------------------
<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`:

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

Output:

[source]
---------------------------------------------------------------------------------
Buildfile: build.xml

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

BUILD SUCCESSFUL
---------------------------------------------------------------------------------