Gradle 提供強大的機制,可根據目前的環境自訂建置。
此機制也支援希望與 Gradle 整合的工具。
基本用法
初始化指令碼(又稱「init 指令碼」)類似於 Gradle 中的其他指令碼。不過,這些指令碼會在建置開始前執行。
以下是幾個可能的用途
-
設定企業範圍的組態,例如自訂外掛的尋找位置。
-
根據目前的環境設定屬性,例如開發人員的機器與持續整合伺服器。
-
提供建置所需的使用者個人資訊,例如儲存庫或資料庫驗證憑證。
-
定義特定於機器資訊,例如 JDK 安裝的位置。
-
註冊建置監聽器。希望監聽 Gradle 事件的外部工具可能會覺得這很有用。
-
註冊建置記錄器。您可以自訂 Gradle 記錄其所產生事件的方式。
初始化指令碼的一個主要限制是它們無法存取 buildSrc
專案中的類別。
使用初始化指令碼
有幾種方式可以使用初始化指令碼
-
在命令列上指定檔案。命令列選項為
-I
或--init-script
,後面接著指令碼的路徑。命令列選項可以出現多次,每次都新增另一個初始化指令碼。如果命令列上指定的任何檔案不存在,建置將會失敗。
-
在
$GRADLE_USER_HOME/
目錄中放置一個名為init.gradle
(或 Kotlin 的init.gradle.kts
)的檔案。 -
在
$GRADLE_USER_HOME/init.d/
目錄中放置一個以.gradle
結尾的檔案(或 Kotlin 的.init.gradle.kts
)。 -
在 Gradle 發行版的
$GRADLE_HOME/init.d/
目錄中放置一個以.gradle
結尾的檔案(或 Kotlin 的.init.gradle.kts
)。這讓您可以封裝一個自訂的 Gradle 發行版,其中包含自訂的建置邏輯和外掛程式。您可以將此與 Gradle wrapper 結合使用,讓自訂邏輯可供企業中的所有建置使用。
如果找到多個 init 腳本,它們將全部按照上述指定的順序執行。
特定目錄中的腳本會按照字母順序執行。例如,工具可以在命令列中指定一個 init 腳本,並在主目錄中指定另一個 init 腳本以定義環境。當執行 Gradle 時,這兩個腳本都會執行。
撰寫 init 腳本
與 Gradle 建置腳本類似,init 腳本是 Groovy 或 Kotlin 腳本。每個 init 腳本都有與之關聯的 Gradle 執行個體。init 腳本中的任何屬性參照和方法呼叫都會委派給這個 Gradle
執行個體。
每個 init 腳本也實作 Script 介面。
撰寫 init 腳本時,請注意您嘗試存取的參照範圍。例如,從 |
從 init 腳本設定專案
您可以使用 init 腳本設定建置中的專案。這與在多專案建置中設定專案類似。
以下範例顯示如何在專案評估之前從 init 腳本執行額外的設定
repositories {
mavenCentral()
}
tasks.register("showRepos") {
val repositoryNames = repositories.map { it.name }
doLast {
println("All repos:")
println(repositoryNames)
}
}
allprojects {
repositories {
mavenLocal()
}
}
repositories {
mavenCentral()
}
tasks.register('showRepos') {
def repositoryNames = repositories.collect { it.name }
doLast {
println "All repos:"
println repositoryNames
}
}
allprojects {
repositories {
mavenLocal()
}
}
此範例使用此功能設定額外的儲存庫,僅供特定環境使用。
套用 init 腳本時的輸出
> gradle --init-script init.gradle.kts -q showRepos
All repos:
[MavenLocal, MavenRepo]
> gradle --init-script init.gradle -q showRepos
All repos:
[MavenLocal, MavenRepo]
init 腳本的外部相依性
init 腳本也可以使用 initscript()
方法宣告相依性,傳入一個宣告 init 腳本類別路徑的閉包。
宣告 init 腳本的外部相依性
initscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.apache.commons:commons-math:2.0")
}
}
initscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.apache.commons:commons-math:2.0'
}
}
傳遞給 initscript()
方法的閉包會設定 ScriptHandler 執行個體。您可以透過將相依性新增到 classpath
設定,來宣告 init 腳本類別路徑。
這與宣告 Java 編譯類別路徑的方式相同。你可以使用 宣告相依性 中所述的任何相依類型,專案相依性除外。
宣告 init 程式碼類別路徑後,你可以像使用類別路徑上的任何其他類別一樣,在 init 程式碼中使用類別。下列範例新增至前一個範例,並使用 init 程式碼類別路徑中的類別。
具有外部相依性的 init 程式碼
import org.apache.commons.math.fraction.Fraction
initscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.apache.commons:commons-math:2.0")
}
}
println(Fraction.ONE_FIFTH.multiply(2))
tasks.register("doNothing")
import org.apache.commons.math.fraction.Fraction
initscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.apache.commons:commons-math:2.0'
}
}
println Fraction.ONE_FIFTH.multiply(2)
tasks.register('doNothing')
套用 init 程式碼時的輸出
> gradle --init-script init.gradle.kts -q doNothing
2 / 5
> gradle --init-script init.gradle -q doNothing
2 / 5
Init 程式碼外掛
與 Gradle 建置程式碼或 Gradle 設定檔類似,外掛可套用至 init 程式碼。
在 init 程式碼中使用外掛
apply<EnterpriseRepositoryPlugin>()
class EnterpriseRepositoryPlugin : Plugin<Gradle> {
companion object {
const val ENTERPRISE_REPOSITORY_URL = "https://repo.gradle.org/gradle/repo"
}
override fun apply(gradle: Gradle) {
// ONLY USE ENTERPRISE REPO FOR DEPENDENCIES
gradle.allprojects {
repositories {
// Remove all repositories not pointing to the enterprise repository url
all {
if (this !is MavenArtifactRepository || url.toString() != ENTERPRISE_REPOSITORY_URL) {
project.logger.lifecycle("Repository ${(this as? MavenArtifactRepository)?.url ?: name} removed. Only $ENTERPRISE_REPOSITORY_URL is allowed")
remove(this)
}
}
// add the enterprise repository
add(maven {
name = "STANDARD_ENTERPRISE_REPO"
url = uri(ENTERPRISE_REPOSITORY_URL)
})
}
}
}
}
repositories{
mavenCentral()
}
data class RepositoryData(val name: String, val url: URI)
tasks.register("showRepositories") {
val repositoryData = repositories.withType<MavenArtifactRepository>().map { RepositoryData(it.name, it.url) }
doLast {
repositoryData.forEach {
println("repository: ${it.name} ('${it.url}')")
}
}
}
apply plugin: EnterpriseRepositoryPlugin
class EnterpriseRepositoryPlugin implements Plugin<Gradle> {
private static String ENTERPRISE_REPOSITORY_URL = "https://repo.gradle.org/gradle/repo"
void apply(Gradle gradle) {
// ONLY USE ENTERPRISE REPO FOR DEPENDENCIES
gradle.allprojects { project ->
project.repositories {
// Remove all repositories not pointing to the enterprise repository url
all { ArtifactRepository repo ->
if (!(repo instanceof MavenArtifactRepository) ||
repo.url.toString() != ENTERPRISE_REPOSITORY_URL) {
project.logger.lifecycle "Repository ${repo.url} removed. Only $ENTERPRISE_REPOSITORY_URL is allowed"
remove repo
}
}
// add the enterprise repository
maven {
name "STANDARD_ENTERPRISE_REPO"
url ENTERPRISE_REPOSITORY_URL
}
}
}
}
}
repositories{
mavenCentral()
}
@Immutable
class RepositoryData {
String name
URI url
}
tasks.register('showRepositories') {
def repositoryData = repositories.collect { new RepositoryData(it.name, it.url) }
doLast {
repositoryData.each {
println "repository: ${it.name} ('${it.url}')"
}
}
}
套用 init 程式碼時的輸出
> gradle --init-script init.gradle.kts -q showRepositories
repository: STANDARD_ENTERPRISE_REPO ('https://repo.gradle.org/gradle/repo')
> gradle --init-script init.gradle -q showRepositories
repository: STANDARD_ENTERPRISE_REPO ('https://repo.gradle.org/gradle/repo')
init 程式碼中的外掛可確保在執行建置時,只使用指定的儲存庫。
在 init 程式碼中套用外掛時,Gradle 會實例化外掛,並呼叫外掛實例的 Plugin.apply(T) 方法。
gradle
物件會傳遞為參數,可用於設定建置的所有面向。當然,套用的外掛可以如 init 程式碼的外部相依性 中所述,解析為外部相依性。