Gradle學習筆記 (未完)


在現有的基礎上工作

Gradle資料

Maven和Gradle對比: http://www.importnew.com/18008.html
Gradle官網的與Maven對比: https://gradle.org/maven_vs_gradle/

下載: https://services.gradle.org/distributions/gradle-3.0-all.zip

Gradle官方用戶指南文檔: https://docs.gradle.org/current/userguide/userguide.html
Gradle2用戶指南中文版: https://waylau.gitbooks.io/gradle-2-user-guide/content/

安裝

Gradle3.0后,需要java7或更高版本
Gradle會裝載自己的Groovy庫,所以,不需要安裝Groovy,就算安裝了Groovy也會被忽略掉。

下載

下載完整包后,里面會包含 Gradle、用戶指南、API文檔、示例
https://gradle.org/gradle-download/

配置環境變量

GRADLE_HOME=D:\resource\Gradle\gradle-3.0
path=%GRADLE_HOME%/bin (linux: path=$GRADLE_HOME/bin)
GRADLE_OPTS=-Xms256m -Xmx512m (指定用於啟動JVM命令行參數,選擇配置)

GRADLE_USER_HOME=D:\resource\Gradle\repo (配置本地倉庫的位置)

檢查是否安裝成功

執行命令 gradle -v

Gradle命令

  • 執行多task(列出每個task): gradle dist test
task compile << {
    println 'compiling source'
}

task compileTest(dependsOn: compile) << {
    println 'compiling unit tests'
}

task test(dependsOn: [compile, compileTest]) << {
    println 'running unit tests'
}

task dist(dependsOn: [compile, test]) << {
    println 'building the distribution'
}
  • 排除task(-x): gradle dist -x test -x compile

  • 當task執行失敗時,繼續執行不依賴這個task的其它task gradle --continue dist

  • 任務名稱縮寫(只需提供足夠的可以唯一區分出該 task 的字符): gradle di

  • 選擇需要執行的腳本: C:\>gradle -q -b D:/empty/build.gradle hello
    在多子項目時,應該使用-pgradle -q -p subdir hello

  • 忽略新版本檢查(ignoring any up-to-date checks): gradle --rerun-tasks di

  • 查看構建信息
    gradle -q projects: 列出當前項目及其子項目(一並輸出description)
    gradle -q tasks (gradle -q tasks --all): 列出當前項目的所有task
    gradle help --task task1 task2: 顯示匹配到的task的詳細信息
    gradle -q dependencies api:dependencies webapp:dependencies: 列出指定項目的依賴
    gradle -q api:dependencies --configuration testCompile: 列出指定項目及指定階段的依賴
    gradle buildEnvironment: ?
    gradle -q webapp:dependencyInsight --dependency groovy --configuration compile: ? (對追蹤為何依賴出現的版本很有幫助)
    gradle -q api:properties: 列出當前項目的屬性

  • 生成構建耗時報告 --profile

  • 干跑(不真正執行,用來查看執行了哪些task) gradle -m someTask1 someTask2

Gradle命令列表
https://docs.gradle.org/current/userguide/gradle_command_line.html
包括幾個環境變量的說明:GRADLE_OPTS GRADLE_USER_HOME JAVA_HOME

Gradle Wrapper

  • Wrapper的使用

Gradle Wrapper解決在未安裝Gradle的情況下也能構建項目,並且避免用戶選擇了不正確的Gradle版本
每個Gradle Wrapper都會指定Gradle版本,當首次使用Wrapper時,將下載指定的Gradle版本,並使用它進行構建
Wrapper下載的Gradle保存到目錄$USER_HOME/.gradle/wrapper/dists

  • 為項目添加Wrapper

只需要項目根目錄下執行gradle wrapper --gradle-version 版本號

也可以在構建腳本build.gradle中添加task

task wrapper(type: Wrapper) {
    gradleVersion = '2.0'
}

執行命令后,將生成以下幾個文件

demo/
  gradlew
  gradlew.bat
  gradle/
    wrapper/
      gradle-wrapper.jar
      gradle-wrapper.properties

配置文件gradle-wrapper.properties中的各項配置說明(一般不需要變更):
https://docs.gradle.org/current/dsl/org.gradle.api.tasks.wrapper.Wrapper.html

  • 校驗Wrapper下載的Gradle文件

執行命令shasum -a 256 gradle-3.0-all.zip生成hash碼
windows下可以使用Git Bash來執行

將生成 的hash嗎,配置到gradle-wrapper.properties

distributionSha256Sum=9c8b7564ea6a911b5b9fcadd60f3a6cea4238413c8b1e1dd14400a50954aab99
  • unix權限

在Unix系統中,如果遇到文件權限問題,可以這樣執行sh gradlew

Gradle Daemon

可以通過Gradle Daemon來解決,Gradle啟動會比較慢的問題
Gradle啟動慢是因為,它運行中Java Virtual Machine (JVM)上,並還會依賴幾個比較耗時的支持庫
Gradle Daemon,是一直存活的,避免了JVM的啟動耗時,並且緩存項目結構、文件、tasks等信息

Gradle 3.0中,Gradle Daemon是默認啟動的,不需要作其它的變動
在低版本Gradle中,可以使用--daemon來啟用Gradle Daemon

使用了Gradle Daemon,將會提升15-75%的構建速度
可以通過--profile來生成耗時報告

可以通過命令gradle --status來查看 Gradle Daemon的狀態
如果安裝了JDK,可以使用jps命令來查看
注意:目前,只有相同版本的GradleGradle Daemon才能一起工作

禁用Gradle Daemon
可以通過配置文件,也可以直接使用命令gradle --stop
目前,建議,在持續集成服務器中禁用Gradle Daemon,提高可靠性
https://docs.gradle.org/current/userguide/gradle_daemon.html

Gradle Daemon,若存活時間超過3個小時,將會被回收

依賴管理基礎

  • 聲明依賴
// java插件
apply plugin: 'java'

// 設定使用Maven中心倉庫
repositories {
    mavenCentral()
}

dependencies {
	// 聲明依賴hibernate-core版本為3.6.7.Final,在編譯及運行時依賴它
    compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
	// 聲明從倉庫中獲取版本>=4.0的junit,在test時依賴它
    testCompile group: 'junit', name: 'junit', version: '4.+'
}
  • 依賴配置

java插件中定義了以下幾個標准的依賴配置
compile 編譯時的依賴
runtime 程序運行時的依賴,默認包含compile
testCompile 單元測試編譯時的依賴,默認包含compile
testRuntime 單元測試程序運行時的依賴,默認包含compileruntimetestCompile

  • 依賴的聲明方式

依賴由group、name與version組成,除了上面的聲明方式,還可以寫成下面這樣

dependencies {
    compile 'org.hibernate:hibernate-core:3.6.7.Final'
	testCompile 'junit:junit:4.+'
}
  • 倉庫

默認情況下,Gradle不會定義依賴倉庫,如果構建時需要第三方依賴,必須定義依賴倉庫

如下設置倉庫為Maven中心倉庫

repositories {
    mavenCentral()
}

如下設置倉庫為Maven遠程倉庫

repositories {
    maven {
        url "https://repo1.maven.org/maven2/"
    }
}
  • 發部項目

通過執行命令gradle uploadArchives,Gradle將構建並上傳生成的jar包

apply plugin: 'maven'

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "D:/resource/maven/repo/")
        }
    }
}

多項目構建

共同點

  • 在根項目中都有一個settings.gradle的文件
  • 在根項目中都有一個build.gradle的構建文件
  • 子項目中都有它們自己的*.gradle的構建文件

可以通過命令gradle -q projects查詢項目列表

官方建議,每個項目都在settings.gradle中配置根項目名,示例spring源碼中的rootProject.name = "spring"

不需要每個子項目都要有構建文件,但根項目中必須要有

子項目中構建文件的文件名不一定是build.gradle,只要以.gradle為后綴即可

在根項目中執行命令gradle test,將都在各子項目中執行這個gradle test命令

指定子項目的方法類似於路徑,但不是用/\\,而是使用:
gradle :services:webservice:tasks,首個:表示根項目,其它的:表示路徑分隔

持續構建

至目前3.0版本,這個特性尚未非常完善

通常,當前執行完所有指定的task后,就算是一次構建完畢,當下一次調用gradle命令時,才會進行下一次的構建動作

但持續構建時,Gradle會保持構建的功能,只有接收到停止命令時,才會停止。
如,對於編譯JAVA文件,每當java文件變更時,Gradle自動對這個文件進行再次編譯。
在一些情景下,持續構建能夠發揮很大作用。

  • 啟動:添加參數--continuous-t。示例,gradle build --continuous
  • 停止:如果是啟動是在終端命令中,可以通過CTRL+D之后再接ENTER來結束;否則,需要使用kill命令來結束進程;某些工具或許會提供這個功能

只有在當前持續構建中,命令所涉及到的文件(構建腳本不算),被更改時,才會觸發再次構建
當前構建腳本變更時,只有手動重啟持續構建后,新的構建方案才會生效

注意事項:

  • 循環構建:在構建的過程中,構建腳本更改了被Gradle監視着的文件,就會形成循環構建
  • java9的限制:在Mac OS X中,Gradle為每10秒檢測一遍文件的變更,而不是2秒;在Windows在,大項目可能運行不了持續構建
  • 性能與穩定性:在Mac OS X中,由於依賴於它低效率的系統輪詢,所以對文件變更的感知會延遲;此外,在Mac OS X中,重負載情況下,可能會導致死鎖;在linux中,如使用的是OpenJDK,有可能會錯過文件變更的事件通知
  • 刪除目標目錄,不會引起新的構建

復合構建

至目前3.0版本,這個特性也尚未非常完善

復合構建與多項目構建有許多類似的地方

gradle 圖形界面

使用命令gradle --gui就可以彈出圖形界面

構建環境

通過gradle.properties配置編譯環境
通過本地環境變量的配置,如GRADLE_OPTSJAVA_OPTS等,會作用於所有項目構建
如果某個項目需要特殊配置時,可以使用gradle.properties的配置來覆蓋環境變更的配置

在下面三個地方中,如果存在相同的配置,后一個覆蓋前一個

  • 項目構建目錄中的gradle.properties
  • Gradle用戶目錄下的gradle.properties
  • 系統屬性,如,命令行輸入的-Dsome.property

這個功能需要jdk7或以上版本

下面列出用於配置Gradle構建環境的配置

  • org.gradle.daemon 當設置為true時,將使用Gradle daemon去構建。本地是默認使用的,在CI持續構建時,建議為false
  • org.gradle.java.home 指定Gradle構建程序使用的Java路徑
  • org.gradle.jvmargs 指定daemon程序的jvm參數,這個設置是非常有用的,因為默認分配的daemon內存是比較大的
  • org.gradle.configureondemand 按需配置,只配置關聯項目,使用大型項目能夠快速構建 Configuration on demand
  • org.gradle.parallel 當配置了這個設置后,Gradle將以parallel模式執行
  • org.gradle.workers.max 配置並發執行的最大數
  • org.gradle.debug 當設置為true時,以遠程(監聽端口5005)debug模式運行,相當於在jvm命令行中添加-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005
  • org.gradle.daemon.performance.enable-monitoring 當設置為false時,Gradle將不監控daemons運行時的內存使用情況

可以在gradle.properties配置文件中,配置http/https的訪問代理

systemProp.http.proxyHost=www.somehost.org
systemProp.http.proxyPort=8080
systemProp.http.proxyUser=userid
systemProp.http.proxyPassword=password
systemProp.http.nonProxyHosts=*.nonproxyrepos.com|localhost

gradle的嵌入式編程

Gradle提供Tooling API,使用者可以自行調用。主要使用者是IDE、CI server等,但,API是開放的,任何人都可以在項目中使用

  • Gradle TestKit
  • Eclipse Buildship
  • IntelliJ IDEA

API有如下特性

  • 查詢構建明細,包括項目結構與依賴
  • 執行構建,並監聽輸出日志
  • 執行指定的測試類或測試方法
  • 接收構建過程的事件,如項目配置,執行的task或test
  • 取消正在執行的構建
  • 將多個單獨構建,組合與復合構建
  • 下載合適的Gradle版本
  • 輕量級的實現,可以非常方便的嵌入到應用中

samples/toolingApi中有示例

編寫Gradle構建腳本

構建腳本基礎

1). Projects and tasks

Projectstasks 是Gradle最頂部的兩個基本概念
每個構建包含一個或多個Projects,一個Project由一個或多個tasks組成

2). Hello world

當執行gradle命令時,將會在當前目錄中查找一個叫build.gradle的構建腳本

第一個構建腳本:執行gradle -q hello-q的作用是不輸出gradle的日志)

task hello {
    doLast {
        println 'Hello world!'
    }
}

Gradle的task,與Ant的target很類似,但比target強大

3). 更簡捷的書寫方式

task hello << {
    println 'Hello world!'
}

4). 構建腳本,本身就是編程

通過強大的Groovy進行編寫Gradle構建腳本

下面為在Task中使用Groovy的示例

task upper << {
    String someString = 'mY_nAmE'
    println "Original: " + someString 
    println "Upper case: " + someString.toUpperCase()
}

示例2

task count << {
    4.times { print "$it " }
}

5). Task之間的依賴

示例1:

task hello << {
    println 'Hello world!'
}
task intro(dependsOn: hello) << {
    println "I'm Gradle"
}

在示例1中,執行gradle -q intro,將輸出如下:

D:\Learning\gradle\hello>gradle -q intro
Hello world!
I'm Gradle

示例2:延遲依賴,所依賴task,在當前task之后

task taskX(dependsOn: 'taskY') << {
    println 'taskX'
}
task taskY << {
    println 'taskY'
}

示例2將輸出:

D:\Learning\gradle\hello>gradle -q taskX
taskY
taskX

6). 動態tasks

利用功能強大的Groovy,可以動態的創建tasks
示例:

4.times { counter ->
    task "task$counter" << {
        println "I'm task number $counter"
    }
}

在示例中,執行task0task1task2task3都是正常的

7). 調整已存在的tasks

當tasks被創建后,就可以通過一此API進行訪問。通過這個特性,可以動態的實現task之間的依賴。Ant是不允許這么做的

示例1:

4.times { counter ->
    task "task$counter" << {
        println "I'm task number $counter"
    }
}
task0.dependsOn task2, task3

輸出如下:

D:\Learning\gradle\hello>gradle -q task0
I'm task number 2
I'm task number 3
I'm task number 0

示例2:添加behaviour

task hello << {
    println 'Hello Earth'
}
hello.doFirst {
    println 'Hello Venus'
}
hello.doLast {
    println 'Hello Mars'
}
hello << {
    println 'Hello Jupiter'
}

輸出如下:

D:\Learning\gradle\hello>gradle -q hello
Hello Venus
Hello Earth
Hello Mars
Hello Jupiter

doFirstdoLast可以被調用多次,表示在一個action之前或之后執行。
他們是依賴執行,操作符<<就類似於doLast的別名

8). 快捷符號

像在之前的示例中,可以通過一個快捷符號來訪問已經存在的任務

task hello << {
    println 'Hello world!'
}
hello.doLast {
    println "Greetings from the $hello.name task."
}

這使用得代碼更具可讀性,特別是其它插件提供的tasks,比如compile

9). task的全局屬性

在task中,可在屬性中添加ext.前綴,並賦值,這樣在其它的task中,就可讀取到這個屬性值了

示例:

task myTask {
    ext.myProperty = "myValue"
}

task printTaskProperties << {
    println myTask.myProperty
}

Extra properties

10). 編寫Ant Tasks

Ant tasks are first-class citizens in Gradle.
Using Ant tasks from Gradle is as convenient and more powerful than using Ant tasks from a build.xml file.

下面示例如何訪問Ant tasks及訪問Ant properties

task loadfile << {
    def files = file('../antLoadfileResources').listFiles().sort()
    files.each { File file ->
        if (file.isFile()) {
            ant.loadfile(srcFile: file, property: file.name)
            println " *** $file.name ***"
            println "${ant.properties[file.name]}"
        }
    }
}

執行這個腳本,需要在當前腳本父目錄中,創建文件夾antLoadfileResources,並在其下創建幾個文件
更多關於Gradle中使用Ant的教程:Using Ant from Gradle

11). 使用公共方法

Gradle是有考慮如何組織腳本邏輯的。通過提取公共方法,可更好的組織腳本代碼

示例:

task checksum << {
    fileList('../antLoadfileResources').each {File file ->
        ant.checksum(file: file, property: "cs_$file.name")
        println "$file.name Checksum: ${ant.properties["cs_$file.name"]}"
    }
}

task loadfile << {
    fileList('../antLoadfileResources').each {File file ->
        ant.loadfile(srcFile: file, property: file.name)
        println "I'm fond of $file.name"
    }
}

File[] fileList(String dir) {
    file(dir).listFiles({file -> file.isFile() } as FileFilter).sort()
}

在后面將有章節,專門說明如果組織腳本代碼的 Organizing Build Logic

12). 定義默認tasks

如果沒有指定tasks,將執行默認的tasks

定義默認tasks示例:

defaultTasks 'clean', 'run'

task clean << {
    println 'Default Cleaning!'
}

task run << {
    println 'Default Running!'
}

task other << {
    println "I'm not a default task!"
}

如果只執行命令gradle -q,由於沒有指定tasks,就會執行默認的cleanrun,相當於gradle -q clean run
如果子項目中沒有指定默認tasks,則將執行父項目中的默認tasks

13). 通過DAG配置

在后面的構建生命周期中將有講到,Gradle有一個配置階段與一個執行階段
配置階段之后,Gradle就知道了所有需要被執行的tasks。此時,Gradle提供了一個可以利用的切入點,在這里,可以為變量設定不同的值

示例:

task distribution << {
    println "We build the zip with version=$version"
}

task release(dependsOn: 'distribution') << {
    println 'We release now'
}

gradle.taskGraph.whenReady {taskGraph ->
    if (taskGraph.hasTask(release)) {
        version = '1.0'
    } else {
        version = '1.0-SNAPSHOT'
    }
}

當執行gradle -q distribution命令時,將輸出:

D:\Learning\gradle\hello>gradle -q distribution
We build the zip with version=1.0-SNAPSHOT

當執行gradle -q release命令時,將輸出:

D:\Learning\gradle\hello>gradle -q release
We build the zip with version=1.0
We release now

非常重要的whenReady,它是在relese這個task執行之前起使用。

構建初始化插件

這個構建初始化插件正在不斷完善中,在以后的版本中,DSL及其他配置可能會改變

這個構建初始化插件可以引導Gradle項目的創建。支持創建各種類型的Gradle項目,同時支持將其它構建方式轉化為Gradle項目。

通常,Gradle插件是應用中項目。這個構建初始化插件是會自動應用於項目的,所以不需要特別配置。只需要在准備創建Gradle項目的地方,執行init這個task。
當使用這個構建初始化插件時,Gradle Wrapper也會自動被安裝到當前項目中。

1). 插件包含的tasks

Task name depends on Type Description
init wrapper InitBuild Generates a Gradle project.
wrapper - Wrapper Generates Gradle wrapper files.

2). 初始設定

可以通過--type參數,指定構建的項目類型
如:創建一個java項目 gradle init --type java-library

若沒有設定type參數,則Gradle將根據當前環境做出適當的判斷,比如,當發現有pom.xml文件時,就會將type設定為pom,即將maven項目轉換為gradle項目
如果沒有指定或判斷出type值,則將使用默認的basic

3). 初始化的項目類型

由於這個功能還在孵化中,所以只提供幾種類型,更多的類型將在后續的版本中提供。

  • pom 在當前路徑中查找文件pom.xml,並將其轉化為gradle項目
  • java-library 創建java項目
  • scala-library
  • groovy-library
  • basic

編寫Gradle構建腳本

Gradle構建腳本語言

Gradle為構建腳本提供了一個領域特定語言(DSL)。基於Groovy,並添加了一些更易於描述腳本的語法。

Gradle構建腳本可以包含任何Groovy語言標識。默認UTF-8編碼。

API: Project

  • 調用當前腳本中沒有的任何方法,都將委托給Project這個對象。
  • 調用當前腳本中沒有的任何屬性,都將委托給Project這個對象。
println name
println project.name

第一行,是由於當前腳本未定義name屬性,則委托給project這個對象,所以第一行與第二行輸出是一樣的

標准的項目屬性

Project這個對象,提供了幾個標准的屬性,可以構建腳本中直接使用,下面列出常用的幾個

Name Type Default Value
project Project The Project instance
name String The name of the project directory.
path String The absolute path of the project.
description String A description for the project.
projectDir File The directory containing the build script.
buildDir File projectDir/build
group Object unspecified
version Object unspecified
ant AntBuilder An AntBuilder instance

API: Script

當Gradle執行構建腳本時,會將這個腳本編譯成實現接口Script的類。也就是說,接口Script中的所有屬性和方法,在構建腳本中都可以調用。
Script的官方文檔: https://docs.gradle.org/current/dsl/org.gradle.api.Script.html

聲明變更

在構建腳本中,有兩種方式聲明變更。本地變更(Local variables)和全局變量(Extra properties)

使用關鍵字def來進行聲明本地變量(只在所聲明范圍有效)。這是Groovy的語法。
def示例:

def dest = "dest"

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

使用關鍵字ext.作為前綴來聲明全局變量。 這種變量,在子項目中,也是可見的。
包括但不限於,projectstaskssource都可以定義、改變及使用這種全局變量
ext.示例:

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,將輸出:

D:\Learning\gradle\Extra properties>gradle -q printProperties
3.1.0.RELEASE
build@master.org
main
plugin

關於ext.的更多用法,參考: https://docs.gradle.org/current/dsl/org.gradle.api.plugins.ExtraPropertiesExtension.html

配置對象

可以使用如下示例的方式,配置任意對象,這樣的腳本具有非常高的可讀性。

task configure << {
    def pos = configure(new java.text.FieldPosition(10)) {
        beginIndex = 1
        endIndex = 5
    }
    println pos.beginIndex
    println pos.endIndex
}

執行命令gradle -q configure,將輸出:

D:\Learning\gradle\Configuring arbitrary objects>gradle -q configure
1
5

使用外部腳本配置對象

示例,使用外部的other.gradle來對build.gradle的pos對象進行配置
build.gradle

task configure << {
    def pos = new java.text.FieldPosition(10)
    // Apply the script
    apply from: 'other.gradle', to: pos
    println pos.beginIndex
    println pos.endIndex
}

other.gradle

// Set properties.
beginIndex = 1
endIndex = 5

Groovy簡單入門

Groovy提供了非常的DSL特性,而Gradle也繼承了這些特性。懂得構建語言對編寫腳本,特別是自定義插件和tasks時,是非常有用的。

1). Groovy JDK

在java的基礎上,groovy添加了許多有用的方法。如,迭代(Iterable),在Groovy中,可以直接使用each方法。

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

http://groovy-lang.org/gdk.html 在詳細的說明。

2). Property accessors

Groovy會自動將對屬性的調用,轉換為getter或setter方法。

// Using a getter method
println project.buildDir
println getProject().getBuildDir()

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

3). 方法調用可省略圓括號

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

4). List與map集合

Groovy提供了簡捷的List與map的實例化方式。

// 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'

5). 閉包作為方法的最后參數

Gradle DSL 在很多地方都使用了閉包。
參考: http://docs.groovy-lang.org/latest/html/documentation/index.html#_closures

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

6). 閉包委派

每個閉包,都會委派一個用於查找變量及方法的對象。

示例: 閉包委派

dependencies {
    assert delegate == project.dependencies
    testCompile('junit:junit:4.12')
    delegate.testCompile('junit:junit:4.12')
}

默認導入

為了使用腳本更簡捷,Gradle自動導入一系列重要的聲明。
主要是import org.gradle.*及這個包下的子包

深入tasks

區別於Ant的target,Gradle支持增強的tasks,它可以有自己的屬性和方法。

定義task

示例1: 定義task

task(hello) << {
    println "hello"
}

task(copy, type: Copy) {
    from(file('srcDir'))
    into(buildDir)
}

示例2:使用strings作為task名字

task('hello') <<
{
    println "hello"
}

task('copy', type: Copy) {
    from(file('srcDir'))
    into(buildDir)
}

示例3:對示例2的替代語法

tasks.create(name: 'hello') << {
    println "hello"
}

tasks.create(name: 'copy', type: Copy) {
    from(file('srcDir'))
    into(buildDir)
}

對於task的create方法,參考: https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/TaskContainer.html

定位tasks

示例1:通過tasks的屬性訪問task

task hello

println hello.name
println project.hello.name

示例2:通過tasks集合訪問task

task hello

println tasks.hello.name
println tasks['hello'].name

示例3:通過路徑訪問task

project(':projectA') {
    task hello
}

task hello

println tasks.getByPath('hello').path
println tasks.getByPath(':hello').path
println tasks.getByPath('projectA:hello').path
println tasks.getByPath(':projectA:hello').path

對於示例3,需要在當前路徑中,添加名為projectA的文件夾,並在配置文件settings.gradle中添加include 'projectA'
示例3的輸出如下:

D:\Learning\gradle\Locating tasks>gradle -q hello
:hello
:hello
:projectA:hello
:projectA:hello

對於更多的定位tasks的介紹,訪問 https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/TaskContainer.html

配置tasks

首先來看一下Gradle提供的Copy task。可以如下定義一個Copy task

task myCopy(type: Copy)

這個myCopy並沒有定義默認的操作,但它可以使用Copy的API了。下面會舉幾個例子,有不同的方式達到同樣的目的。
Copy API: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Copy.html
當然,這個myCopy只是一個Copy類型的task,同樣還可以定義更多的Copy類型的task。

示例1: 使用不同的方式配置task

Copy myCopy = task(myCopy, type: Copy)
myCopy.from 'resources'
myCopy.into 'target'
myCopy.include('**/*.txt', '**/*.xml', '**/*.properties')

對於示例1的方式,很類似於java。但這種方式比較冗余,而且代碼可讀性不強。

下面示例比較常用的方式。
示例2: 使用閉包配置task

task myCopy(type: Copy)

myCopy {
   from 'resources'
   into 'target'
   include('**/*.txt', '**/*.xml', '**/*.properties')
}

也可以直接使用如下方式:

task myCopy(type: Copy) {
   from 'resources'
   into 'target'
   include('**/*.txt', '**/*.xml', '**/*.properties')
}

為task添加依賴

示例1: 直接使用task名字關聯

project('projectA') {
    task taskX(dependsOn: ':projectB:taskY') << {
        println 'taskX'
    }
}

project('projectB') {
    task taskY << {
        println 'taskY'
    }
}

執行gradle -q taskX,將輸出:

D:\Learning\gradle\Adding dependencies to a task>gradle -q taskX
taskY
taskX

示例2: 使用對應task對象關聯

task taskX << {
    println 'taskX'
}

task taskY << {
    println 'taskY'
}

taskX.dependsOn taskY

執行gradle -q taskX,也將輸出:

D:\Learning\gradle\Adding dependencies to a task>gradle -q taskX
taskY
taskX

示例3: 使用閉包添加依賴

task taskX << {
    println 'taskX'
}

taskX.dependsOn {
    tasks.findAll { task -> task.name.startsWith('lib') }
}

task lib1 << {
    println 'lib1'
}

task lib2 << {
    println 'lib2'
}

task notALib << {
    println 'notALib'
}

執行gradle -q taskX,將輸出:

D:\Learning\gradle\Adding dependencies to a task>gradle -q taskX
lib1
lib2
taskX

關於task的更多用法,參考: https://docs.gradle.org/current/dsl/org.gradle.api.Task.html

tasks排序

這是一個還在孵化中的特性,在以后的Gradle版本中可能變更。

排序與依賴的區別在於,排序並不會影響到task的執行,只是設定tasks的執行順序。

排序,在下面情況下會很有用處:

  • 有強制順序的tasks排序:如build永遠不會在clean之前執行
  • build之前執行構建校驗:如校驗是否有權限執行build
  • 在耗時長的驗證task之前,通過執行一個快速驗證獲得反饋:如在集成測試之前,應該先執行單元測試
  • 一個收集所有特定類型task執行結果的task:如,測試報告task,它會收集所有測試task的運行結果。

只支持兩排序方式: must run aftershould run after

示例1

task taskX << {
    println 'taskX'
}
task taskY << {
    println 'taskY'
}
taskY.mustRunAfter taskX

執行gradle -q taskY taskX輸出:

D:\Learning\gradle\Ordering tasks>gradle -q taskY taskX
taskX
taskY

示例2

task taskX << {
    println 'taskX'
}
task taskY << {
    println 'taskY'
}
taskY.shouldRunAfter taskX

執行gradle -q taskY taskX輸出:

D:\Learning\gradle\Ordering tasks>gradle -q taskY taskX
taskX
taskY

示例3

task taskX << {
    println 'taskX'
}
task taskY << {
    println 'taskY'
}
task taskZ << {
    println 'taskZ'
}
taskX.dependsOn taskY
taskY.dependsOn taskZ
taskZ.shouldRunAfter taskX

執行gradle -q taskX輸出:

D:\Learning\gradle\Ordering tasks>gradle -q taskY taskX
taskZ
taskY
taskX

為task添加掃描信息

示例:

task copy(type: Copy) {
   description 'Copies the resource directory to the target directory.'
   from 'resources'
   into 'target'
   include('**/*.txt', '**/*.xml', '**/*.properties')
}

tasks覆蓋

使用overwrite,示例:

task copy(type: Copy)

task copy(overwrite: true) << {
    println('I am the new one.')
}

執行 gradle -q copy,將輸出

> gradle -q copy
I am the new one.

跳過task的執行

1). 使用斷言

可以使用方式onlyIf()為task添加斷言。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM