Gradle 提供與 Ant 的整合。
Gradle 與 Ant 整合,讓您可以在 Gradle 建置中使用個別的 Ant 任務或整個 Ant 建置。在 Gradle 建置腳本中使用 Ant 任務通常比使用 Ant 的 XML 格式更簡單且更強大。Gradle 也可以作為強大的 Ant 任務腳本工具使用。
Ant 可以分為兩個層次
-
層次 1:Ant 語言。它提供了
build.xml
檔案的語法、目標的處理、特殊結構(如 macrodefs)等等。換句話說,這個層次包含除了 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
層級記錄,並且預設情況下會被抑制。