1. <groovy>

本节介绍如何在 Ant 构建文件中使用 Groovy 的 Ant 任务。您可能还对 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>

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

3. <groovy> 属性

属性 描述 必需

src

包含 Groovy 语句的文件。包含该文件的目录将被添加到类路径中。

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

classpath

要使用的类路径。

classpathref

要使用的类路径,作为对在其他地方定义的 PATH 的引用给出。

output

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

append

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

fork

如果启用,则脚本将在一个分叉的 JVM 进程中执行(默认情况下禁用)。

scriptBaseClass

脚本基类的名称。

parameters

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

useGroovyShell

如果启用,则使用一个新的 GroovyShell 来运行脚本。特殊变量将不可用,但您不需要将 Ant 放在类路径中。默认为 false。

includeAntRuntime

如果启用,则在分叉时将系统类路径包含在类路径中。默认为 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

了解当前 ant 项目的 AntBuilder 实例

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