gradle學習之旅(六) 使用task(下)


增量式構建

  • gradle判斷task是否改變過的依據是:這個task的inputs和outputs屬性組成的集合。當一個task鏈被執行時,如果其中某一個task的inputs和outputs沒有發生改變,則認為該task是最新的,該task將被跳過,在執行鏈輸出中可以看到該task被標為UP-TO-DATE,下圖為Task中的imputs和outputs屬性
  • inputs 屬性應該被賦值為 一個目錄、一個或多個文件、或是一個任意屬性
  • outputs 應該被賦值為一個或多個目錄或者一個或多個文件

那么增量式構建使用場景是怎樣的呢?下面是一個例子:

  • 例子
    假設一個task,makeReleaseVersion,在項目發布部署之前要修改項目版本的release值為true:
task makeReleaseVersion(group: 'versioning' , description: 'Makes Project a release version.') << {
	version.release = true
	ant.propertyfile(file: versionFile){
		entry(key: 'release', type: 'string',operation: '=',value:'true')//利用ant task的propertyfile提供的便利方式來修改屬性文件
	}
}

但是意外發生了,在自動化發布的過程中無法連上服務器,在修復故障后,重新運行自動化發布的任務,因為部署任務依賴於修改版本號任務,所以makeReleaseVersion任務會再次被運行,即使版本號已經在上次運行過程中被修改。
為解決這一問題,需要采用gradle提供的增量式構建特性,為該task的inputs和outputs賦值:

task makeReleaseVersion(group: 'versioning' , description: 'Makes Project a release version.')  {
	inputs.property ('release',version.release)  
	outputs.file versionFile //由於該任務會修改版本文件,所以它被聲明為outputs
	doLast{
		version.release = true
		ant.propertyfile(file: versionFile){
			entry(key: 'release', type: 'string',operation: '=',value:'true')//利用ant task的propertyfile提供的便利方式來修改屬性文件
		}
	}
}

這樣就實現了增量式構建

  • task的inputs和outputs的執行
    確保inputs和outputs的值在配置階段是可訪問的,因為它們在配置階段被執行。如果要通過編程獲得輸出,則可以通過upToDateWhen(Closure var1)方法來實現,與常規的inputs和outputs的set方法比,這個方法是在執行階段執行的,如果閉包返回true,則這個task被認為是最新的。

自定義task

在gradle中,默認Task的實現類為DefaultTask,而DefaultTask中空無一物,全部繼承自AbstractTask。當構建task的動作邏輯變得相當復雜時,必然會產生結構化task代碼的需求,這時就可以實現自定義的Task實現類。
下面將makeReleaseVersion封裝為ReleaseVersionTask的自定義Task

class ReleaseVersionTask extends DefaultTask {
	@Input Boolean release //通過org.gradle.api.tasks包下的注解來聲明輸入輸出
	@OutputFile File destFile
	ReleaseVersionTask(){
		group = 'versioning'
		description = 'Makes Project a release version.'
	}
	@TaskAction //使用注解聲明執行代碼,
	void start(){
		project.version.release = true
		ant.propertyfile(file: destFile){
			entry(key: 'release', type: 'string',operation: '=',value:'true')//利用ant task的propertyfile提供的便利方式來修改屬性文件
		}
	}
}

注意:@Input注解會在配置期間驗證屬性值,如果為null,gradle會拋出TaskValidationException異常。為了允許輸入null,需要給它添加@Optional注解。

  • 使用方法
task makeReleaseVersion(type: ReleaseVersionTask) {
	release = version.release
	destFile = versionFile
}

Gradle的內置task類型

在Gradle DSL指南中可以找到完整的task參考
下面用一個使用類型為內置的task類型Zip的task

task createDistribution(type: Zip, dependsOn: makeReleaseVersion){
	from war.outputs.files //依賴推斷
	
	from(sourceSets*.allSource){
		into 'src'
	}
	
	from(rootDir){
		include versionFile.name
	}
}
  • task依賴推斷
    在上面的createDistribution task中聲明了依賴的task,但是一些task並不直接依賴其他task,比如createDistribution對於war。通過使用一個task的輸出作為另一個task的輸入,Gradle就可以推斷出依賴關系,所依賴的task會自動運行。

task規則

Gradle引入task規則的概念,就是根據task名稱模式執行特定的邏輯。

  • task規則命名模式
    task名稱的靜態部分和一個占位符組成一個task規則名字,例如increment<Classifier>Version。java插件的clean任務便利用了task規則,clean<TaskName>用來刪除指定task的輸出。
  • 聲明task規則
    • 首先,獲得對TaskContainer的引用,該引用為tasks
    • 然后,調用addRule(String,Closure)方法,第一個參數提供了描述信息(比如,task命名模式),第二個參數聲明了要執行的閉包來應用規則。
    • 例如這樣:
    tasks.addRule("Pattern: increment<Classifier>Version - Increments the project version classifier."){
    	String taskName ->
    	if(taskName.startsWith('increment') && taskName.endWith('Version')){
    		task(taskName)<<{
    			String classifier = (taskName - 'increment'- 'Version').toLowerCase()
    			//接下來便是分支判斷代碼
    		}
    	}
    }
    
  • task規則不能像處理任何其它簡單的task或增強的task一樣被獨立分組,task規則會顯示在Rules組下。

構建源代碼目錄buildSrc

事實上在build.gradle文件中不適合寫面向對象的代碼,所以應該把之前的POJO類和自定義task類像項目源代碼一樣組織起來,類似於java源代碼放在src/main/java目錄下、Groovy代碼放在src/main/groovy目錄下,buildSrc用於組織構建代碼源文件。構建代碼包可以放在buildSrc/src/main/groovy或buildSrc/src/main/java下,這樣還方便寫構建代碼的單元測試代碼。


免責聲明!

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



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