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下,这样还方便写构建代码的单元测试代码。

原文地址:https://www.cnblogs.com/Theshy/p/7891485.html