## 1.任務覆蓋
所謂任務覆蓋就是,就是2個任務名稱相同,但是卻還可以同時存在。這是為啥,因為有overwrite,類似于java中重寫。
~~~
task copy << {
println "this is a first"
}
task copy(overwrite:true)<<{
println "this is a second"
}
~~~
執行命令
~~~
D:\GRADLE~2\0112>gradle -q copy
this is a second
~~~
如果不在第二個copy中寫overwrite的話,就會報錯,提示任務已經存在。
~~~
D:\GRADLE~2\0112>gradle -q copy
FAILURE: Build failed with an exception.
* Where:
Build file 'D:\gradle_product\0112\build.gradle' line: 5
* What went wrong:
A problem occurred evaluating root project '0112'.
> Cannot add task ':copy' as a task with that name already exists.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug
option to get more log output.
~~~
## 2.跳過任務
gradle有很多種方式達到跳過任務執行的方式,下面一一列舉:
#### 使用斷言
~~~
task hello <<{
println 'hello world'
}
hello.onlyIf{!project.hasProperty('skipHello')}
~~~
如果執行gradle -q hello命令
~~~
D:\GRADLE~2\0112>gradle -q hello
hello world
~~~
但是在該命令后面加上一些-P參數,來添加屬性,命令的執行結果就不一樣了:
~~~
D:\GRADLE~2\0112>gradle -q hello -P skipHello
D:\GRADLE~2\0112>
~~~
沒有打印任何信息,說明任務hello被跳過了。
#### 拋出StopExecutionException
和java類似,可以通過拋出異常,來跳過某個任務的執行
~~~
task compile <<{
println "We are doing the compile"
}
compile.doFirst{
if(true){throw new StopExecutionException()}
}
task myTask(dependsOn:'compile')<<{
println 'I am not affected'
}
~~~
執行結果如下:
~~~
D:\GRADLE~2\0112>gradle -q myTask
I am not affected
~~~
#### 任務的enabled屬性
每一次任何都有一個enabled屬性,默認情況下該屬性是true的。但是你也可以根據自己的需要將該屬性設置為false,來達到跳過任務的作用的。
~~~
task disableMe <<{
println 'ni dou bu hui zhi xing ,ni hai shuo zhe me duo hua'
}
disableMe.enabled = false
~~~
執行命令后的是沒有任何輸出的:
~~~
D:\GRADLE~2\0112>gradle disableMe
:disableMe SKIPPED
BUILD SUCCESSFUL
Total time: 2.216 secs
~~~
## 3.跳過up-to-date式的任務
~~~
task transform{
ext.srcFile = file('mountains.xml')
ext.destDir = new File(buildDir,'generated')
doLast{
println "Transforming source file"
destDir.mkdirs()
def mountains = new XmlParser().parse(srcFile)
mountains.mountain.each{
mountain ->
def name = mountain.name[0].text()
def height = mountain.height[0].text()
def destFile = new File(destDir,"${name}.txt")
destFile.text = "$name -> ${height}\n"
}
}
}
~~~
這個時候執行任務是會報錯的:
~~~
D:\GRADLE~2\0112>gradle -q transform
Transforming source file
FAILURE: Build failed with an exception.
* Where:
Build file 'D:\gradle_product\0112\build.gradle' line: 7
* What went wrong:
Execution failed for task ':transform'.
> D:\gradle_product\0112\mountains.xml (系統找不到指定的文件。)
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug
option to get more log output.
~~~
因為需要添加一個mountains.xml文件。

那么這個xml文件里寫啥呢?不能說定義一個空的xml文件吧。那就要從任務的定義來看了,因為build.gradle中要讀的屬性有mountain,name,height。mountain又包含name和height。那么我的xml應該定義如下:
~~~
<?xml version='1.0' encoding='UTF-8' standalone='no' ?>
<mountain>
<name>doctorq</name>
<height>111</height>
</mountain>
~~~
這個時候執行命令:
~~~
D:\GRADLE~2\0112>gradle transform
:transform
Transforming source file
BUILD SUCCESSFUL
Total time: 3.416 secs
D:\GRADLE~2\0112>gradle transform
:transform
Transforming source file
BUILD SUCCESSFUL
Total time: 2.309 secs
~~~
從上面可以看出2次執行的結果輸出的結果是一樣的,沒有什么差異。那么如果能讓任務是一個up-to-date式呢。
我們修改一下build.gradle中transform任務的定義,添加2個屬性inputs和outputs:
~~~
task transform{
ext.srcFile = file('mountains.xml')
ext.destDir = new File(buildDir,'generated')
inputs.file srcFile
outputs.file destDir
doLast{
println "Transforming source file"
destDir.mkdirs()
def mountains = new XmlParser().parse(srcFile)
mountains.mountain.each{mountain ->
def name = mountain.name[0].text()
def height = mountain.height[0].text()
def destFile = new File(destDir,"${name}.txt")
destFile.text = "$name -> ${height}\n"
}
}
}
~~~
這個時候我們再執行任務的時候就會發現,第一次執行的時候是沒有任何差異的,但是以后執行的時候,任務后面就會多了一個up-to-date的標識:
~~~
D:\GRADLE~2\0112>gradle transform
:transform
Transforming source file
BUILD SUCCESSFUL
Total time: 2.496 secs
D:\GRADLE~2\0112>gradle transform
:transform UP-TO-DATE
BUILD SUCCESSFUL
Total time: 2.34 secs
D:\GRADLE~2\0112>gradle transform
:transform UP-TO-DATE
BUILD SUCCESSFUL
Total time: 2.325 secs
~~~
當你把build/generated目錄刪除掉以后,重新執行gradle transform任務的時候,是沒有UP-TO-DATE標識的。但是一旦有build/generated目錄就會顯示UP-TO-DATE目錄,提示你是最新生成的。
上面的2兩個屬性分別所屬類別如下:
inputs屬于TaskInputs類型下的
outputs屬于TaskOutputs類型下的
需要注意的是,如果一個任務沒有定義outputs屬性,就永遠都不會出現UP-TO-DATE的。對于下面情形,task任務仍然被看作UP-TO-DATE。
1.outputs定位的不是文件
2.TaskOutpusts.upToDateWhen方法被調用
#### 原理
上面說了那么多,那么我們讓任務出現UP-TO-DATE到底有什么用呢?
gradle在任務第一次被執行的時候,會記住任務的輸入文件以及里面的內容。執行成功后,會記住任務的輸出文件以及里面的內容。在下次執行任務的時候,同樣會記住這些內容,我們稱這些為記憶。
在新的一次任務執行來了以后,在該任務執行前,gradle會生成新的記憶。然后將該新的記憶和之前的記憶來比對,如果輸出的文件和文件中的內容沒有任何變化,就標記為UP-TO-DATE且跳過該任務,只有不同的時候,才會執行該任務。這樣的話可以使任務的執行更快。
## 4.任務規則
任務的行為依賴傳入的參數,這個時候需要提供任務的規則。
~~~
tasks.addRule("Pattern:ping<ID>"){
String taskName ->
if(taskName.startsWith("ping")){
task(taskName)<<{
println taskName
println "Pinging: " + (taskName-'ping')
}
}
}
~~~
輸出:
~~~
D:\GRADLE~2\0112>gradle -q pingServer1
pingServer1
Pinging: Server1
~~~
build.gradle文件中,addRule中的參數是一個字符串,它其實是該rule的描述信息。可以通過gradle tasks查看:
~~~
Rules
-----
Pattern:ping<ID>
To see all tasks and more detail, run with --all.
BUILD SUCCESSFUL
~~~
上面我們是通過命令行來傳入,下面來看看通過依賴的方式,調用。
~~~
tasks.addRule("Pattern:ping<ID>"){
String taskName ->
if(taskName.startsWith("ping")){
task(taskName)<<{
println "Pinging: " + (taskName-'ping')
}
}
}
task groupPing{
dependsOn pingServer1,pingServer2
}
~~~
~~~
D:\GRADLE~2\0112>gradle -q groupPing
Pinging: Server1
Pinging: Server2
~~~
## 5.Finalizer任務
這讓我想起了java中Object類中的finalize方法。需要注意的是,該特性目前還不完善,以后可能發生改變。
在這個里面我們要理解2個概念,一個是終止的任務finalizer task,一個是被終止的任務finalized? task。
finalizer task是我們這節要講的task,finalized task是被finalizer修飾的task。看下面的例子:
~~~
task taskX << {
println 'taskX'
}
task taskY << {
println 'taskY'
}
taskX.finalizedBy taskY
~~~
~~~
D:\GRADLE~2\0112>gradle -q taskX
taskX
taskY
~~~
上面的任務taskX ,taskY哪一個是finalizer,哪個是finalized呢?
被修飾的是taskX,所以taskX是finalized,taskY是finalizer,知道這兩個概念是很重要的。
下面再來研究一下finalizer任務的特性:
#### 被修飾任務失敗,finalizer任務也會照常執行
~~~
task taskX << {
throw new RuntimeException()
println 'taskX'
}
task taskY << {
println 'taskY'
}
taskX.finalizedBy taskY
~~~
執行命令后輸出:
~~~
D:\GRADLE~2\0112>gradle -q taskX
taskY
FAILURE: Build failed with an exception.
* Where:
Build file 'D:\gradle_product\0112\build.gradle' line: 2
* What went wrong:
Execution failed for task ':taskX'.
> java.lang.RuntimeException (no error message)
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug
option to get more log output.
~~~
這個時候你會發現在taskX執行失敗的情況下,taskY卻正常執行。finalizer任務是依賴于taskX的,如果taskX不執行,那么taskY也不執行,那么至于taskX執行的成不成功,不是finalizer任務所關系的。
- 前言
- gradle學習(1)-helloworld
- gradle學習(2)-基礎語法
- gradle學習(3)-基礎認識
- gradle學習(4)-構建java項目
- gradle學習(5)-創建eclipse項目
- gradle學習(6)-依賴管理
- gradle學習(7)-groovy
- gradle學習(8)-gradle的命令行
- gradle學習(9)-獲取build相關信息
- gradle學習(10)-gui
- gradle學習(11)-編寫構建腳本
- gradle學習(12)-groovy一些基礎語法
- gradle學習(13)-有的沒的
- gradle學習(14)-任務
- gradle學習(15)-任務
- gradle學習(16)-操作文件
- gradle學習(17)-被合并的ant
- gradle學習(18)-ant的屬性
- gradle學習(19)-log系統
- gradle學習(20)-詳解java插件
- gradle學習(21)-在eclipse中構建java項目
- gradle復習(1)-2種定義任務方式的區別
- gradle復習(2)-eclipse中添加依賴jar包
- gradle復習(3)-在gradle項目中使用TestNG
- gradle復習(4)-Cannot find System Java Compiler
- gradle復習(5)-Test remote debug
- gradle復習(6)-深入Jacoco
- gradle復習(7)-深入Jacoco
- gradle復習(8)-Task中行為
- gradle學習(22)-Sonar
- gradle學習(23)-Sonar runner