1. <groovy>

在此,我们描述了一个 Ant 任务,用于在 Ant 构建文件中使用 Groovy。您可能还对 Ant 内置的 script 任务感兴趣,该任务支持 Groovy 和其他语言,或者 AntBuilder,它允许您用 Groovy 而不是 XML 编写 Ant 构建脚本。

Apache Ant 执行一系列 Groovy 语句。语句可以从资源中读取,也可以作为封闭 Groovy 标签之间的直接文本。

2. 必需的 taskdef

假设您需要的所有 Groovy jar 都位于 my.classpath 中(这将是 groovy-VERSION.jargroovy-ant-VERSION.jar 以及您可能正在使用的任何模块和传递依赖项),您需要在 build.xml 中声明此任务,然后在调用 groovy 任务之前。

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

您可以像这样简单地将语句放在 groovy 标签之间

<groovy>
...
</groovy>

或者您可以将 Groovy 源脚本作为资源提供。您可以使用 src 属性指定路径名,如下所示

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

或者作为嵌套的 fileset,如下所示(尽管 fileset 定义预计只选择一个文件)

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

或者作为嵌套的单个元素 资源集合,如下所示

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

您还可以提供一个 过滤器链,如下所示

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

如果您的任何模块通过 classpath 加载服务(例如 groovy-json),您可能需要使用 contextClassLoader 属性(见下文)。

3. <groovy> 属性

属性 描述 必需

src

包含 Groovy 语句的文件。包含该文件的目录将添加到 classpath 中。

是,除非语句包含在标签内

classpath

要使用的 classpath。

classpathref

要使用的 classpath,作为对其他地方定义的 PATH 的引用。

output

设置输出文件;默认为 Ant 日志。

append

如果启用且输出到文件,则附加到现有文件而不是覆盖。默认为 false。

fork

如果启用,脚本将在分叉的 JVM 进程中执行(默认为禁用)。

scriptBaseClass

脚本基类的名称。

parameters

在 JDK 8 及更高版本上为方法参数名称的反射生成元数据。默认为 false。

useGroovyShell

如果启用,将使用新的 GroovyShell 运行脚本。特殊变量将不可用,但您不需要 Ant 在 classpath 中。默认为 false。

includeAntRuntime

如果启用,在分叉时,系统 classpath 将包含在 classpath 中。默认为 true。

stacktrace

如果启用,如果在编译期间发生错误,将报告堆栈跟踪。默认为 false。

configScript

设置 Groovy 编译器配置的配置文件。

contextClassLoader

如果启用,上下文类加载器将设置为用于运行脚本的 shell 的类加载器。如果 fork 为 true,则不使用。

4. 作为嵌套元素指定的参数

4.1. <classpath>

Groovy 的 classpath 属性是一种类似 PATH 的结构,也可以通过嵌套的 classpath 元素设置。

4.2. <arg>

可以使用一个或多个嵌套的 <arg> 元素,使用标准的 Ant 命令行约定 来设置参数。

5. 可用绑定

您的 Groovy 语句中有一些绑定可用。

名称 描述

ant

一个 AntBuilder 实例,它了解当前的 Ant 项目

project

当前的 Ant 项目

properties

一个 Ant 属性的 Map

target

调用此 Groovy 脚本的所属目标

task

包装任务,可以访问 org.apache.tools.ant.Task 中所需的任何内容

args

命令行参数,如果有的话

6. 示例

Hello world,版本 1

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

Hello world,版本 2

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

列出当前目录中的所有 XML 文件

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

列出 jar 中的所有 XML 文件

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

运行脚本

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

在 jar 目录中查找所有具有 org.* 包的 Builder

<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}'/>

这可能会导致类似以下内容

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 版本(收集名称略有不同)

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

从 Ant 脚本调用 Web 服务

<?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 = 'https://w3schools.org.cn/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>

这将输出以下内容(以及一些信息消息)

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

BUILD SUCCESSFUL

设置参数

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

输出

Buildfile: build.xml

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

BUILD SUCCESSFUL