Gradle 提供了与 Ant 的集成。
Gradle 与 Ant 集成,允许你在 Gradle 构建中使用单个 Ant 任务或整个 Ant 构建。在 Gradle 构建脚本中使用 Ant 任务通常比使用 Ant 的 XML 格式更容易且更强大。Gradle 也可以用作强大的 Ant 任务脚本工具。
Ant 可以分为两个层
-
第 1 层:Ant 语言。它为
build.xml
文件、目标处理、宏定义等特殊结构提供了语法。换句话说,这一层包括除 Ant 任务和类型之外的所有内容。Gradle 理解这种语言,并允许你将 Antbuild.xml
直接导入到 Gradle 项目中。然后,你可以像使用 Gradle 任务一样使用 Ant 构建的目标。 -
第 2 层:Ant 任务和类型,例如
javac
、copy
或jar
。对于这一层,Gradle 使用 Groovy 和AntBuilder
提供集成。
由于构建脚本是 Kotlin 或 Groovy 脚本,你可以将 Ant 构建作为外部进程执行。你的构建脚本可能包含如下语句:"ant clean compile".execute()
。[1]
Gradle 的 Ant 集成允许你从 Ant 平滑地迁移到 Gradle
-
首先导入你现有的 Ant 构建。
-
然后,将你的依赖声明从 Ant 脚本过渡到你的构建文件。
-
最后,将你的任务移动到你的构建文件或用 Gradle 的插件替换它们。
这个迁移过程可以增量执行,并且你可以在整个过渡过程中维护一个功能性的 Gradle 构建。
Ant 集成由AntBuilder API提供。
使用 Ant 任务和类型
Gradle 在你的构建脚本中提供了一个名为 ant
的属性。这是对 AntBuilder 实例的引用。
AntBuilder
用于从你的构建脚本访问 Ant 任务、类型和属性。
你可以通过调用 AntBuilder
实例上的方法来执行 Ant 任务。你使用任务名称作为方法名称
ant.mkdir(dir: "$STAGE")
ant.copy(todir: "$STAGE/bin") {
ant.fileset(dir: 'bin', includes: "**")
}
ant.gzip(destfile:"build/file-${VERSION}.tar.gz", src: "build/file-${VERSION}.tar")
例如,你可以使用 ant.echo()
方法执行 Ant echo
任务。
Ant 任务的属性作为 Map 参数传递给该方法。下面是 echo
任务的示例
tasks.register("hello") {
doLast {
val greeting = "hello from Ant"
ant.withGroovyBuilder {
"echo"("message" to greeting)
}
}
}
tasks.register('hello') {
doLast {
String greeting = 'hello from Ant'
ant.echo(message: greeting)
}
}
$ gradle hello > Task :hello [ant:echo] hello from Ant BUILD SUCCESSFUL in 0s 1 actionable task: 1 executed
你可以混合 Groovy/Kotlin 代码和 Ant 任务标记。这可能非常强大。 |
你可以将嵌套文本作为任务方法调用的参数传递给 Ant 任务。在这个例子中,我们将 echo
任务的消息作为嵌套文本传递
tasks.register("hello") {
doLast {
ant.withGroovyBuilder {
"echo"("message" to "hello from Ant")
}
}
}
tasks.register('hello') {
doLast {
ant.echo('hello from Ant')
}
}
$ gradle hello > Task :hello [ant:echo] hello from Ant BUILD SUCCESSFUL in 0s 1 actionable task: 1 executed
你可以将嵌套元素在闭包内传递给 Ant 任务。嵌套元素的定义方式与任务相同,通过调用与我们要定义的元素同名的方法
tasks.register("zip") {
doLast {
ant.withGroovyBuilder {
"zip"("destfile" to "archive.zip") {
"fileset"("dir" to "src") {
"include"("name" to "**.xml")
"exclude"("name" to "**.java")
}
}
}
}
}
tasks.register('zip') {
doLast {
ant.zip(destfile: 'archive.zip') {
fileset(dir: 'src') {
include(name: '**.xml')
exclude(name: '**.java')
}
}
}
}
你可以使用访问任务的相同方式访问 Ant 类型,使用类型名称作为方法名称。方法调用返回 Ant 数据类型,你可以在构建脚本中直接使用它。在下面的例子中,我们创建了一个 Ant path
对象,然后遍历其内容
import org.apache.tools.ant.types.Path
tasks.register("list") {
doLast {
val path = ant.withGroovyBuilder {
"path" {
"fileset"("dir" to "libs", "includes" to "*.jar")
}
} as Path
path.list().forEach {
println(it)
}
}
}
tasks.register('list') {
doLast {
def path = ant.path {
fileset(dir: 'libs', includes: '*.jar')
}
path.list().each {
println it
}
}
}
使用自定义 Ant 任务
要使自定义任务在你的构建中可用,请使用 taskdef
(通常更容易)或 typedef
Ant 任务,就像你在 build.xml
文件中所做的那样。然后,你可以像引用内置 Ant 任务一样引用自定义 Ant 任务
tasks.register("check") {
val checkstyleConfig = file("checkstyle.xml")
doLast {
ant.withGroovyBuilder {
"taskdef"("resource" to "com/puppycrawl/tools/checkstyle/ant/checkstyle-ant-task.properties") {
"classpath" {
"fileset"("dir" to "libs", "includes" to "*.jar")
}
}
"checkstyle"("config" to checkstyleConfig) {
"fileset"("dir" to "src")
}
}
}
}
tasks.register('check') {
def checkstyleConfig = file('checkstyle.xml')
doLast {
ant.taskdef(resource: 'com/puppycrawl/tools/checkstyle/ant/checkstyle-ant-task.properties') {
classpath {
fileset(dir: 'libs', includes: '*.jar')
}
}
ant.checkstyle(config: checkstyleConfig) {
fileset(dir: 'src')
}
}
}
你可以使用 Gradle 的依赖管理来组装自定义任务的类路径。为此,你需要为类路径定义一个自定义配置,并向其添加一些依赖项。在声明依赖中对此进行了更详细的描述
val pmd = configurations.create("pmd")
dependencies {
pmd(group = "pmd", name = "pmd", version = "4.2.5")
}
configurations {
pmd
}
dependencies {
pmd group: 'pmd', name: 'pmd', version: '4.2.5'
}
要使用类路径配置,请使用自定义配置的 asPath
属性
tasks.register("check") {
doLast {
ant.withGroovyBuilder {
"taskdef"("name" to "pmd",
"classname" to "net.sourceforge.pmd.ant.PMDTask",
"classpath" to pmd.asPath)
"pmd"("shortFilenames" to true,
"failonruleviolation" to true,
"rulesetfiles" to file("pmd-rules.xml").toURI().toString()) {
"formatter"("type" to "text", "toConsole" to "true")
"fileset"("dir" to "src")
}
}
}
}
tasks.register('check') {
doLast {
ant.taskdef(name: 'pmd',
classname: 'net.sourceforge.pmd.ant.PMDTask',
classpath: configurations.pmd.asPath)
ant.pmd(shortFilenames: 'true',
failonruleviolation: 'true',
rulesetfiles: file('pmd-rules.xml').toURI().toString()) {
formatter(type: 'text', toConsole: 'true')
fileset(dir: 'src')
}
}
}
导入 Ant 构建
你可以使用 ant.importBuild()
方法将 Ant 构建导入到你的 Gradle 项目中。
当你导入 Ant 构建时,每个 Ant 目标都被视为一个 Gradle 任务。这意味着你可以像操作 Gradle 任务一样操作和执行 Ant 目标
ant.importBuild("build.xml")
ant.importBuild 'build.xml'
<project>
<target name="hello">
<echo>Hello, from Ant</echo>
</target>
</project>
$ gradle hello > Task :hello [ant:echo] Hello, from Ant BUILD SUCCESSFUL in 0s 1 actionable task: 1 executed
你可以添加一个依赖于 Ant 目标的任务
ant.importBuild("build.xml")
tasks.register("intro") {
dependsOn("hello")
doLast {
println("Hello, from Gradle")
}
}
ant.importBuild 'build.xml'
tasks.register('intro') {
dependsOn("hello")
doLast {
println 'Hello, from Gradle'
}
}
$ gradle intro > Task :hello [ant:echo] Hello, from Ant > Task :intro Hello, from Gradle BUILD SUCCESSFUL in 0s 2 actionable tasks: 2 executed
或者,你可以向 Ant 目标添加行为
ant.importBuild("build.xml")
tasks.named("hello") {
doLast {
println("Hello, from Gradle")
}
}
ant.importBuild 'build.xml'
hello {
doLast {
println 'Hello, from Gradle'
}
}
$ gradle hello > Task :hello [ant:echo] Hello, from Ant Hello, from Gradle BUILD SUCCESSFUL in 0s 1 actionable task: 1 executed
Ant 目标也可以依赖于 Gradle 任务
ant.importBuild("build.xml")
tasks.register("intro") {
doLast {
println("Hello, from Gradle")
}
}
ant.importBuild 'build.xml'
tasks.register('intro') {
doLast {
println 'Hello, from Gradle'
}
}
<project>
<target name="hello" depends="intro">
<echo>Hello, from Ant</echo>
</target>
</project>
$ gradle hello > Task :intro Hello, from Gradle > Task :hello [ant:echo] Hello, from Ant BUILD SUCCESSFUL in 0s 2 actionable tasks: 2 executed
有时,可能需要“重命名”为 Ant 目标生成的任务,以避免与现有 Gradle 任务命名冲突。为此,请使用 AntBuilder.importBuild(java.lang.Object, org.gradle.api.Transformer) 方法
ant.importBuild("build.xml") { antTargetName ->
"a-" + antTargetName
}
ant.importBuild('build.xml') { antTargetName ->
'a-' + antTargetName
}
<project>
<target name="hello">
<echo>Hello, from Ant</echo>
</target>
</project>
$ gradle a-hello > Task :a-hello [ant:echo] Hello, from Ant BUILD SUCCESSFUL in 0s 1 actionable task: 1 executed
虽然此方法的第二个参数应该是 Transformer,但在 Groovy 中编程时,由于 Groovy 对自动将闭包强制转换为单抽象方法类型的支持,你可以使用闭包而不是匿名内部类(或类似)。 |
使用 Ant 属性和引用
有几种方法可以设置 Ant 属性,以便 Ant 任务可以使用该属性。
你可以直接在 AntBuilder
实例上设置属性。Ant 属性也可以作为 Map 使用,你可以更改它。
你也可以使用 Ant property
任务
ant.setProperty("buildDir", buildDir)
ant.properties.set("buildDir", buildDir)
ant.properties["buildDir"] = buildDir
ant.withGroovyBuilder {
"property"("name" to "buildDir", "location" to "buildDir")
}
ant.buildDir = buildDir
ant.properties.buildDir = buildDir
ant.properties['buildDir'] = buildDir
ant.property(name: 'buildDir', location: buildDir)
许多 Ant 任务在执行时会设置属性。有几种方法可以获取这些属性的值。你可以直接从 AntBuilder
实例获取属性。Ant 属性也可以作为 Map 使用
<property name="antProp" value="a property defined in an Ant build"/>
println(ant.getProperty("antProp"))
println(ant.properties.get("antProp"))
println(ant.properties["antProp"])
println ant.antProp
println ant.properties.antProp
println ant.properties['antProp']
有几种方法可以设置 Ant 引用
ant.withGroovyBuilder { "path"("id" to "classpath", "location" to "libs") }
ant.references.set("classpath", ant.withGroovyBuilder { "path"("location" to "libs") })
ant.references["classpath"] = ant.withGroovyBuilder { "path"("location" to "libs") }
ant.path(id: 'classpath', location: 'libs')
ant.references.classpath = ant.path(location: 'libs')
ant.references['classpath'] = ant.path(location: 'libs')
<path refid="classpath"/>
有几种方法可以获取 Ant 引用
<path id="antPath" location="libs"/>
println(ant.references.get("antPath"))
println(ant.references["antPath"])
println ant.references.antPath
println ant.references['antPath']
使用 Ant 日志记录
Gradle 将 Ant 消息优先级映射到 Gradle 日志级别,以便从 Ant 记录的消息出现在 Gradle 输出中。默认情况下,这些映射如下
Ant 消息优先级 | Gradle 日志级别 |
---|---|
VERBOSE |
|
DEBUG |
|
INFO |
|
WARN |
|
ERROR |
|
微调 Ant 日志记录
Ant 消息优先级到 Gradle 日志级别的默认映射有时可能会有问题。例如,没有消息优先级直接映射到 LIFECYCLE
日志级别,这是 Gradle 的默认级别。许多 Ant 任务在 INFO 优先级记录消息,这意味着要从 Gradle 公开这些消息,构建必须以日志级别设置为 INFO
运行,这可能会记录比预期更多的输出。
相反,如果 Ant 任务以过高的级别记录消息,则抑制这些消息将需要构建以更高的日志级别(例如 QUIET
)运行。但是,这可能会导致其他需要的输出被抑制。
为了帮助解决这个问题,Gradle 允许用户微调 Ant 日志记录并控制消息优先级到 Gradle 日志级别的映射。这可以通过使用 AntBuilder.setLifecycleLogLevel(java.lang.String) 方法设置应映射到默认 Gradle LIFECYCLE
日志级别的优先级来完成。当设置此值时,以配置的优先级或更高级别记录的任何 Ant 消息都将至少以 LIFECYCLE
级别记录。以低于此优先级记录的任何 Ant 消息最多将以 INFO
级别记录。
例如,以下更改了映射,使得 Ant INFO 优先级消息在 LIFECYCLE
日志级别公开
ant.lifecycleLogLevel = AntBuilder.AntMessagePriority.INFO
tasks.register("hello") {
doLast {
ant.withGroovyBuilder {
"echo"("level" to "info", "message" to "hello from info priority!")
}
}
}
ant.lifecycleLogLevel = "INFO"
tasks.register('hello') {
doLast {
ant.echo(level: "info", message: "hello from info priority!")
}
}
$ gradle hello > Task :hello [ant:echo] hello from info priority! BUILD SUCCESSFUL in 0s 1 actionable task: 1 executed
另一方面,如果 lifecycleLogLevel
设置为 ERROR,则以 WARN 优先级记录的 Ant 消息将不再以 WARN
日志级别记录。它们现在将以 INFO
级别记录,并在默认情况下被抑制。