本章著眼于一些編寫(xiě)構(gòu)建腳本的詳細(xì)信息。
Gradle 提供一種 domain specific language (領(lǐng)域特定語(yǔ)言)或者說(shuō)是 DSL,來(lái)描述構(gòu)建。這種構(gòu)建語(yǔ)言基于 Groovy 中,并進(jìn)行了一些補(bǔ)充,使其易于描述構(gòu)建。
構(gòu)建腳本可以包含任何 Groovy 語(yǔ)言的元素(除了聲明標(biāo)簽任何語(yǔ)言元素)。Gradle 假定每個(gè)構(gòu)建腳本使用 UTF-8 編碼。
在快速開(kāi)始 Java的教程中,我們使用了 apply() 方法。這方法從何而來(lái)?我們之前說(shuō)在 Gradle 中構(gòu)建腳本定義了一個(gè) project 。在構(gòu)建的每一個(gè) project,Gradle 創(chuàng)建了一個(gè) Project 類(lèi)型的實(shí)例,并在構(gòu)建腳本中關(guān)聯(lián)此 Project 對(duì)象。當(dāng)構(gòu)建腳本執(zhí)行時(shí),它會(huì)配置此Project 對(duì)象:
下面我們來(lái)試試這個(gè),試試訪問(wèn) Project 對(duì)象的 name 屬性。
Example 13.1. Accessing property of the Project object
build.gradle
println name
println project.name
執(zhí)行 gradle -q check
> gradle -q check
projectApi
projectApi
這兩個(gè) println 語(yǔ)句打印出相同的屬性。在生成腳本中未定義的屬性,第一次使用時(shí)自動(dòng)委托到P roject 對(duì)象。其他語(yǔ)句使用了在任何構(gòu)建腳本中可以訪問(wèn)的 project 屬性,則返回關(guān)聯(lián)的 Project 對(duì)象。只有當(dāng)您定義的屬性或方法 Project 對(duì)象的一個(gè)成員相同名字時(shí),你才需要使用project 屬性。
獲取有關(guān)編寫(xiě)構(gòu)建腳本幫助
不要忘記您的構(gòu)建腳本是簡(jiǎn)單的 Groovy 代碼,并驅(qū)動(dòng)著 Gradle API。并且 Project 接口是您在 Gradle API 中訪問(wèn)一切 的入點(diǎn)。所以,如果你想知道什么 '標(biāo)簽(tag)' 在構(gòu)建腳本中可用,您可以去看項(xiàng)目接口的文檔。
Project 對(duì)象提供了一些在構(gòu)建腳本中可用的標(biāo)準(zhǔn)的屬性。下表列出了常用的幾個(gè)屬性。
| 名稱(chēng) | 類(lèi)型 | 默認(rèn)值 |
project |
Project |
The Project實(shí)例
|
name |
String |
項(xiàng)目目錄的名稱(chēng) |
path |
String |
項(xiàng)目的絕對(duì)路徑 |
description |
String |
項(xiàng)目的描述 |
projectDir |
File |
包含生成腳本的目錄 |
buildDir |
File |
|
group |
Object |
未指定 |
version |
Object |
未指定 |
ant |
AntBuilder |
An AntBuilder實(shí)例
|
當(dāng) Gradle 執(zhí)行一個(gè)腳本時(shí),它將腳本編譯為一個(gè)實(shí)現(xiàn)了 Script 接口的類(lèi)。這意味著所有由該 Script 接口聲明的屬性和方法在您的腳本中是可用的。
有兩類(lèi)可以在生成腳本中聲明的變量: 局部變量和額外屬性。
局部變量是用 def 關(guān)鍵字聲明的。它們只在定義它們的范圍內(nèi)可以被訪問(wèn)。局部變量是 Groovy 語(yǔ)言底層的一個(gè)特征。
Example 13.2. Using local variables
build.gradle
def dest = "dest"
task copy(type: Copy) {
from "source"
into dest
}
Gradle 的域模型中,所有增強(qiáng)的對(duì)象都可以容納用戶(hù)定義的額外的屬性。這包括但并不限于 project、task 和源碼集。額外的屬性可以通過(guò)所屬對(duì)象的 ext 屬性進(jìn)行添加,讀取和設(shè)置?;蛘?,可以使用 ext塊同時(shí)添加多個(gè)屬性。
Example 13.3. Using extra properties
build.gradle
apply plugin: "java"
ext {
springVersion = "3.1.0.RELEASE"
emailNotification = "build@master.org"
}
sourceSets.all { ext.purpose = null }
sourceSets {
main {
purpose = "production"
}
test {
purpose = "test"
}
plugin {
purpose = "production"
}
}
task printProperties << {
println springVersion
println emailNotification
sourceSets.matching { it.purpose == "production" }.each { println it.name }
}
執(zhí)行 gradle -q printProperties
> gradle -q printProperties
3.1.0.RELEASE
build@master.org
main
plugin
在此示例中, 一個(gè) ext 代碼塊將兩個(gè)額外屬性添加到 project 對(duì)象中。此外,通過(guò)將 ext.purpose設(shè)置為 null(null是一個(gè)允許的值),一個(gè)名為 purpose 的屬性被添加到每個(gè)源碼集。一旦屬性被添加,他們就可以像預(yù)定的屬性一樣被讀取和設(shè)置。
通過(guò)添加屬性所要求特殊的語(yǔ)法,Gradle 可以在你試圖設(shè)置 (預(yù)定義的或額外的) 的屬性,但該屬性拼寫(xiě)錯(cuò)誤或不存在時(shí)馬上失敗。額外屬性在任何能夠訪問(wèn)它們所屬的對(duì)象的地方都可以被訪問(wèn),這使它們有著比局部變量更廣泛的作用域。父項(xiàng)目上的額外屬性,在子項(xiàng)目中也可以訪問(wèn)。
有關(guān)額外屬性和它們的 API 的詳細(xì)信息,請(qǐng)參閱ExtraPropertiesExtension 類(lèi)的 API。
Groovy 提供了用于創(chuàng)建 DSL 的大量特點(diǎn),并且 Gradle 構(gòu)建語(yǔ)言利用了這些特點(diǎn)。了解構(gòu)建語(yǔ)言是如何工作的,將有助于你編寫(xiě)構(gòu)建腳本,特別是當(dāng)你開(kāi)始寫(xiě)自定義插件和 task 的時(shí)候。
Groovy 對(duì) Java 的標(biāo)準(zhǔn)類(lèi)增加了很多有用的方法。例如, Iterable 新增的each方法,會(huì)對(duì)Iterable 的元素進(jìn)行遍歷:
Example 13.4. Groovy JDK methods
build.gradle
// Iterable gets an each() method
configurations.runtime.each { File f -> println f }
在 http://groovy.codehaus.org/groovy-jdk/ 查看詳情
Groovy 會(huì)自動(dòng)地把一個(gè)屬性的引用轉(zhuǎn)換為對(duì)適當(dāng)?shù)?getter 或 setter 方法的調(diào)用。
Example 13.5. Property accessors
build.gradle
// Using a getter method
println project.buildDir
println getProject().getBuildDir()
// Using a setter method
project.buildDir = 'target'
getProject().setBuildDir('target')
調(diào)用方法時(shí)括號(hào)是可選的。
Example 13.6. Method call without parentheses
build.gradle
test.systemProperty 'some.prop', 'value'
test.systemProperty('some.prop', 'value')
Groovy 提供了一些定義 List 和 Map 實(shí)例的快捷寫(xiě)法。兩種類(lèi)型都是簡(jiǎn)單的 literal,但 map literal 有一些有趣的曲折。
例如,“apply” 方法(如你通常應(yīng)用插件)需要 map 參數(shù)。然而,當(dāng)你有一個(gè)像 “apply plugin:'java'”,你實(shí)際上并沒(méi)有使用 map literal ,你實(shí)際上使用“命名的參數(shù)”,這幾乎是和 map literal 相同的語(yǔ)法(不包包裝器)。命名參數(shù)列表將被轉(zhuǎn)換成一個(gè) map 當(dāng)方法被調(diào)用時(shí),但它沒(méi)有在開(kāi)始作為一個(gè) map。
Example 13.7. List and map literals
build.gradle
// List literal
test.includes = ['org/gradle/api/**', 'org/gradle/internal/**']
List<String> list = new ArrayList<String>()
list.add('org/gradle/api/**')
list.add('org/gradle/internal/**')
test.includes = list
// Map literal.
Map<String, String> map = [key1:'value1', key2: 'value2']
// Groovy will coerce named arguments
// into a single map argument
apply plugin: 'java'
Gradle DSL 在很多地方使用閉包。你可以在這里查看更多有關(guān)閉包的資料。當(dāng)方法的最后一個(gè)參數(shù)是一個(gè)閉包時(shí),你可以把閉包放在方法調(diào)用之后:
Example 13.8. Closure as method parameter
build.gradle
repositories {
println "in a closure"
}
repositories() { println "in a closure" }
repositories({ println "in a closure" })
每個(gè)閉包都有一個(gè)委托對(duì)象,Groovy 使用它來(lái)查找變量和方法的引用,而不是作為閉包的局部變量或參數(shù)。Gradle 在配置閉包中使用到它,把委托對(duì)象設(shè)置為被配置的對(duì)象。
Example 13.9. Closure delegates
build.gradle
dependencies {
assert delegate == project.dependencies
testCompile('junit:junit:4.11')
delegate.testCompile('junit:junit:4.11')
}