本章著眼于一些編寫構(gòu)建腳本的詳細信息。
Gradle 提供一種 domain specific language (領(lǐng)域特定語言)或者說是 DSL,來描述構(gòu)建。這種構(gòu)建語言基于 Groovy 中,并進行了一些補充,使其易于描述構(gòu)建。
構(gòu)建腳本可以包含任何 Groovy 語言的元素(除了聲明標(biāo)簽任何語言元素)。Gradle 假定每個構(gòu)建腳本使用 UTF-8 編碼。
在Chapter 07. Java Quickstart 快速開始 Java的教程中,我們使用了 apply() 方法。這方法從何而來?我們之前說在 Gradle 中構(gòu)建腳本定義了一個 project 。在構(gòu)建的每一個 project,Gradle 創(chuàng)建了一個?Project?類型的實例,并在構(gòu)建腳本中關(guān)聯(lián)此 Project 對象。當(dāng)構(gòu)建腳本執(zhí)行時,它會配置此Project 對象:
下面我們來試試這個,試試訪問 Project 對象的 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
這兩個 println 語句打印出相同的屬性。在生成腳本中未定義的屬性,第一次使用時自動委托到P roject 對象。其他語句使用了在任何構(gòu)建腳本中可以訪問的 project 屬性,則返回關(guān)聯(lián)的 Project 對象。只有當(dāng)您定義的屬性或方法 Project 對象的一個成員相同名字時,你才需要使用project 屬性。
獲取有關(guān)編寫構(gòu)建腳本幫助
不要忘記您的構(gòu)建腳本是簡單的 Groovy 代碼,并驅(qū)動著 Gradle API。并且 Project 接口是您在 Gradle API 中訪問一切 的入點。所以,如果你想知道什么 '標(biāo)簽(tag)' 在構(gòu)建腳本中可用,您可以去看項目接口的文檔。
Project 對象提供了一些在構(gòu)建腳本中可用的標(biāo)準(zhǔn)的屬性。下表列出了常用的幾個屬性。
名稱 | 類型 | 默認值 |
---|---|---|
project |
Project |
The?Project實例 |
name |
String |
項目目錄的名稱 |
path |
String |
項目的絕對路徑 |
description |
String |
項目的描述 |
projectDir |
File |
包含生成腳本的目錄 |
buildDir |
File |
* projectDir*/build |
group |
Object |
未指定 |
version |
Object |
未指定 |
ant |
AntBuilder |
An?AntBuilder實例 |
當(dāng) Gradle 執(zhí)行一個腳本時,它將腳本編譯為一個實現(xiàn)了 Script 接口的類。這意味著所有由該 Script 接口聲明的屬性和方法在您的腳本中是可用的。
有兩類可以在生成腳本中聲明的變量: 局部變量和額外屬性。
局部變量是用 def 關(guān)鍵字聲明的。它們只在定義它們的范圍內(nèi)可以被訪問。局部變量是 Groovy 語言底層的一個特征。
Example 13.2. Using local variables
build.gradle
def dest = "dest"
task copy(type: Copy) {
from "source"
into dest
}
Gradle 的域模型中,所有增強的對象都可以容納用戶定義的額外的屬性。這包括但并不限于 project、task 和源碼集。額外的屬性可以通過所屬對象的 ext 屬性進行添加,讀取和設(shè)置?;蛘撸梢允褂?ext塊同時添加多個屬性。
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
在此示例中, 一個 ext 代碼塊將兩個額外屬性添加到 project 對象中。此外,通過將 ext.purpose設(shè)置為 null(null是一個允許的值),一個名為 purpose 的屬性被添加到每個源碼集。一旦屬性被添加,他們就可以像預(yù)定的屬性一樣被讀取和設(shè)置。
通過添加屬性所要求特殊的語法,Gradle 可以在你試圖設(shè)置 (預(yù)定義的或額外的) 的屬性,但該屬性拼寫錯誤或不存在時馬上失敗。額外屬性在任何能夠訪問它們所屬的對象的地方都可以被訪問,這使它們有著比局部變量更廣泛的作用域。父項目上的額外屬性,在子項目中也可以訪問。
有關(guān)額外屬性和它們的 API 的詳細信息,請參閱ExtraPropertiesExtension?類的 API。
Groovy 提供了用于創(chuàng)建 DSL 的大量特點,并且 Gradle 構(gòu)建語言利用了這些特點。了解構(gòu)建語言是如何工作的,將有助于你編寫構(gòu)建腳本,特別是當(dāng)你開始寫自定義插件和 task 的時候。
Groovy 對 Java 的標(biāo)準(zhǔn)類增加了很多有用的方法。例如, Iterable 新增的each方法,會對Iterable 的元素進行遍歷:
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 會自動地把一個屬性的引用轉(zhuǎn)換為對適當(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)用方法時括號是可選的。
Example 13.6. Method call without parentheses
build.gradle
test.systemProperty 'some.prop', 'value'
test.systemProperty('some.prop', 'value')
Groovy 提供了一些定義 List 和 Map 實例的快捷寫法。兩種類型都是簡單的 literal,但 map literal 有一些有趣的曲折。
例如,“apply” 方法(如你通常應(yīng)用插件)需要 map 參數(shù)。然而,當(dāng)你有一個像 “apply plugin:'java'”,你實際上并沒有使用 map literal ,你實際上使用“命名的參數(shù)”,這幾乎是和 map literal 相同的語法(不包包裝器)。命名參數(shù)列表將被轉(zhuǎn)換成一個 map 當(dāng)方法被調(diào)用時,但它沒有在開始作為一個 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)方法的最后一個參數(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" })
每個閉包都有一個委托對象,Groovy 使用它來查找變量和方法的引用,而不是作為閉包的局部變量或參數(shù)。Gradle 在配置閉包中使用到它,把委托對象設(shè)置為被配置的對象。
Example 13.9. Closure delegates
build.gradle
dependencies {
assert delegate == project.dependencies
testCompile('junit:junit:4.11')
delegate.testCompile('junit:junit:4.11')
}
更多建議: