Gradle 編寫構(gòu)建腳本

2022-08-03 11:51 更新

這一章著眼于一些編寫構(gòu)建腳本的詳細(xì)信息。

Gradle 構(gòu)建語言

Gradle 提供一種領(lǐng)域特定語言或者說是 DSL,來描述構(gòu)建。這種構(gòu)建語言基于 Groovy 中,并進(jìn)行了一些補(bǔ)充,使其易于描述構(gòu)建。

Project API

Java 構(gòu)建入門的教程中,我們使用了 apply ()方法。這方法從何而來?我們之前說在 Gradle 中構(gòu)建腳本定義了一個項目(project)。在構(gòu)建的每一個項目中,Gradle 創(chuàng)建了一個 Project 類型的實例,并在構(gòu)建腳本中關(guān)聯(lián)此 Project 對象。當(dāng)構(gòu)建腳本執(zhí)行時,它會配置此 Project 對象:

  • 在構(gòu)建腳本中,你所調(diào)用的任何一個方法,如果在構(gòu)建腳本中未定義,它將被委托給 Project 對象。
  • 在構(gòu)建腳本中,你所訪問的任何一個屬性,如果在構(gòu)建腳本里未定義,它也會被委托給 Project 對象。

下面我們來試試這個,試試訪問 Project 對象的 name 屬性。

訪問 Project 對象的屬性

build.gradle

println name
println project.name  

gradle -q check 的輸出結(jié)果

> gradle -q check
projectApi
projectApi  

這兩個 println 語句打印出相同的屬性。在生成腳本中未定義的屬性,第一次使用時自動委托到 Project 對象。其他語句使用了在任何構(gòu)建腳本中可以訪問的 project 屬性,則返回關(guān)聯(lián)的 Project 對象。只有當(dāng)您定義的屬性或方法 Project 對象的一個成員相同名字時,你才需要使用 project 屬性。

標(biāo)準(zhǔn) project 屬性

Project對象提供了一些在構(gòu)建腳本中可用的標(biāo)準(zhǔn)的屬性。下表列出了常用的幾個屬性。

表 13.1. Project 屬性

名稱 類型 默認(rèn)值
project Project Project實例
name String 項目目錄的名稱。
path String 項目的絕對路徑。
description String 項目的描述。
projectDir File 包含生成腳本的目錄。
buildDir File projectDir/build
group Object 未指定
version Object 未指定
ant AntBuilder AntBuilder實例

Script API

當(dāng) Gradle 執(zhí)行一個腳本時,它將腳本編譯為一個實現(xiàn)了 Script 接口的類。這意味著所有由該Script 接口聲明的屬性和方法在您的腳本中是可用的。

聲明變量

有兩類可以在生成腳本中聲明的變量: 局部變量和額外屬性。

局部變量局部

局部變量是用 def 關(guān)鍵字聲明的。它們只在定義它們的范圍內(nèi)可以被訪問。局部變量是 Groovy 語言底層的一個特征。

示例 13.2. 使用局部變量

build.gradle

def dest = "dest"
task copy(type: Copy) {
    from "source"
    into dest
}  

額外屬性

Gradle 的域模型中,所有增強(qiáng)的對象都可以容納用戶定義的額外的屬性。這包括但并不限于項目(project)、任務(wù)(task)和源碼集(source set)。額外的屬性可以通過所屬對象的 ext 屬性進(jìn)行添加,讀取和設(shè)置。或者,可以使用 ext 塊同時添加多個屬性。

13.3 例子. 使用額外屬性

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 }
}   

gradle -q printProperties的輸出結(jié)果

> gradle -q printProperties
3.1.0.RELEASE
build@master.org
main
plugin  

在此示例中, 一個 ext 代碼塊將兩個額外屬性添加到 project 對象中。此外,通過將ext.purpose 設(shè)置為 null(null是一個允許的值),一個名為 purpose 的屬性被添加到每個源碼集(source set)。一旦屬性被添加,他們就可以像預(yù)定的屬性一樣被讀取和設(shè)置。

通過添加屬性所要求特殊的語法,Gradle 可以在你試圖設(shè)置 (預(yù)定義的或額外的) 的屬性,但該屬性拼寫錯誤或不存在時 fail fast。[5]額外屬性在任何能夠訪問它們所屬的對象的地方都可以被訪問,這使它們有著比局部變量更廣泛的作用域。父項目上的額外屬性,在子項目中也可以訪問。

有關(guān)額外屬性和它們的 API 的詳細(xì)信息,請參閱 ExtraPropertiesExtension。

一些 Groovy 的基礎(chǔ)知識

Groovy 提供了用于創(chuàng)建 DSL 的大量特點,并且 Gradle 構(gòu)建語言利用了這些特點。了解構(gòu)建語言是如何工作的,將有助于你編寫構(gòu)建腳本,特別是當(dāng)你開始寫自定義插件和任務(wù)的時候。

Groovy JDK

Groovy 對 JVM 的類增加了很多有用的方法。例如, iterable 新增的 each 方法,會對iterable 的元素進(jìn)行遍歷:

Groovy JDK 的方法

build.gradle

// Iterable gets an each() method
configurations.runtime.each { File f -> println f }  

屬性訪問器

Groovy 會自動地把一個屬性的引用轉(zhuǎn)換為對適當(dāng)?shù)?getter 或 setter 方法的調(diào)用。

屬性訪問器

build.gradle

// Using a getter method
println project.buildDir
println getProject().getBuildDir()
// Using a setter method
project.buildDir = 'target'
getProject().setBuildDir('target')   

括號可選的方法調(diào)用

調(diào)用方法時括號是可選的。

不帶括號的方法調(diào)用

build.gradle

test.systemProperty 'some.prop', 'value'
test.systemProperty('some.prop', 'value')  

List 和 Map

Groovy 提供了一些定義 List 和 Map 實例的快捷寫法。

List and map

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
apply plugin: 'java'
Map<String, String> map = new HashMap<String, String>()
map.put('plugin', 'java')
apply(map)  

作為方法最后一個參數(shù)的閉包

Gradle DSL 在很多地方使用閉包。你可以在這里查看更多有關(guān)閉包的資料。當(dāng)方法的最后一個參數(shù)是一個閉包時,你可以把閉包放在方法調(diào)用之后:

作為方法參數(shù)的閉包

build.gradle

repositories {
    println "in a closure"
}
repositories() { println "in a closure" }
repositories({ println "in a closure" })   

閉包委托(delegate)

每個閉包都有一個委托對象,Groovy 使用它來查找變量和方法的引用,而不是作為閉包的局部變量或參數(shù)。Gradle 在配置閉包中使用到它,把委托對象設(shè)置為被配置的對象。

閉包委托

build.gradle

dependencies {
    assert delegate == project.dependencies
    compile('junit:junit:4.11')
    delegate.compile('junit:junit:4.11')
}  


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號