tasks是org.gradle.api.internal.tasks.DefaultTaskContainer的一种实例,新版本一般建议通过register 来配置和创建task的:
// DefaultTaskContainer 的register的方法 TaskProviderregister(String name, Action super Task> configurationAction)
register 方法通过TaskCreatingProvider来创建task,其返回类型也是TaskCreatingProvider。TaskContainer提供了findByPath来获取创建的task的对象,可以看到默认的task是DefaultTask的一种实现:
def sayHello = tasks.register('sayHello') { doLast { println 'sayHello' + " hai" } } println sayHello println "Class:"+sayHello.getClass().getName() println "Superclass:"+sayHello.getClass().getSuperclass().getName() println "-"*30 def t = tasks.findByPath("sayHello") println t.getClass() println t.getClass().getSuperclass().getName()
输出结果:
> Configure project : provider(task 'sayHello', class org.gradle.api.DefaultTask) Class:org.gradle.api.internal.tasks.DefaultTaskContainer$TaskCreatingProvider_Decorated Superclass:org.gradle.api.internal.tasks.DefaultTaskContainer$TaskCreatingProvider ------------------------------ class org.gradle.api.DefaultTask_Decorated org.gradle.api.DefaultTask
TaskContainer 的register 有一些重载方法,可以指定task的类型, 比如:
TaskProvider register(String name, Class type) TaskProvider register(String name, Class type, Object... constructorArgs) TaskProvider register(String name, Class type, Action super T> configurationAction)
指定的类型必须是Task一种具体实现,而且Gradle提供了一些具备特定功能的Task具体类型,比如:
例如,可以定义一个复制文件的task,需要做的主要内容是配置task,具体的动作Copy 已经实现了:
tasks.register("copyTxt", Copy){ from "origin" into "desc" }task的执行结果(outcomes)
task的执行结果可以被标记以下几种:
- (no label) or EXECUTED: task执行了其动作
- UP-TO-DATE:task的outputs 和inputs没有变化,动作不会被执行
- FROM-CACHE:启用缓存,task也支持缓存,task的outputs 可以从以前的执行中找到
- SKIPPED:task没有执行其动作
- NO-SOURCE:没有sources,task不需要执行其动作(Task has inputs and outputs, but no sources. For example, source files are .java files for JavaCompile.)
还是以Copy task举例,通过-i 参数显示更多日志,执行task来观察其标记标签:
- 第一次执行 gradle -i copyTxt
> Task :copyTxt Caching disabled for task ':copyTxt' because: Build cache is disabled Task ':copyTxt' is not up-to-date because: No history is available. :copyTxt (Thread[Execution worker for ':' Thread 2,5,main]) completed. Took 0.007 secs.
没有看到标签,task执行过了 - 再次执行gradle -i copyTxt
> Task :copyTxt UP-TO-DATE Caching disabled for task ':copyTxt' because: Build cache is disabled Skipping task ':copyTxt' as it is up-to-date. :copyTxt (Thread[Execution worker for ':',5,main]) completed. Took 0.002 secs.
可以看到被标记UP-TO-DATE,task被跳过了。修改源目录下文件的文本内容,再次执行:> Task :copyTxt Caching disabled for task ':copyTxt' because: Build cache is disabled Task ':copyTxt' is not up-to-date because: Input property 'rootSpec$1' file E:learn_gradletestoriginhello.txt has changed. :copyTxt (Thread[Execution worker for ':',5,main]) completed. Took 0.005 secs.
没有标签,因为源文件内容发生了变化,所以task将会被执行;同样如果目标文件内容发生了变化,task同样会被执行。:> Task :copyTxt Caching disabled for task ':copyTxt' because: Build cache is disabled Task ':copyTxt' is not up-to-date because: Output property 'destinationDir' file E:learn_gradletestdeschello.txt has changed. :copyTxt (Thread[Execution worker for ':',5,main]) completed. Took 0.004 secs.
- 如果要启用缓存的话,可以在执行任务的时候加上参数--build-cache 或者在gradle.properties文件中指定org.gradle.caching=true, 但是并不是所有的task都支持缓存,gradle提供一些内建的支持缓存的任务,比如JavaCompile、Javadoc、Test,copy不在此列。
# 在控制台执行:gradle -i --build-cache copyTxt > Task :copyTxt UP-TO-DATE Caching disabled for task ':copyTxt' because: Caching has not been enabled for the task Skipping task ':copyTxt' as it is up-to-date. :copyTxt (Thread[Execution worker for ':',5,main]) completed. Took 0.002 secs.
可以看到Caching has not been enabled for the task。支持缓存的task需要可以使用注解@CacheableTask,此注解不可以被继承,默认task是不使用缓存的。 - 当不满足执行条件,task被跳过时,会被标记为SKIPPED
def hello = tasks.register('hello') { doLast { println 'hello world' } } hello.configure { onlyIf { !project.hasProperty('skipHello') } }
# 命令行执行:gradle hello -PskipHello -i > Task :hello SKIPPED Skipping task ':hello' as task onlyIf is false. :hello (Thread[Execution worker for ':',5,main]) completed. Took 0.001 secs.
task会不会被标记为UP-TO-DATE,与inputs和outputs息息相关。一种简单地配置inputs和outputs的方式可以通过Task的属性inputs和outputs:
@Internal TaskInputs getInputs(); @Internal TaskOutputs getOutputs();
通过TaskInputs 和TaskOutputs 提供的接口,可以在配置任务的定义其输入和输出:
tasks.register('task_one') { inputs.file("origin/hello.txt") outputs.file("desc/test.txt") doLast { println "执行任务$name" } }
# 命令行:gradle task_one -i > Task :task_one Watching 1 directory hierarchies to track changes Caching disabled for task ':task_one' because: Build cache is disabled Task ':task_one' is not up-to-date because: No history is available. 执行任务task_one :task_one (Thread[Execution worker for ':' Thread 2,5,main]) completed. Took 0.007 secs.
在不改变文件内容的情况下,再次执行:
# 命令行:gradle task_one -i > Task :task_one UP-TO-DATE Caching disabled for task ':task_one' because: Build cache is disabled Skipping task ':task_one' as it is up-to-date. :task_one (Thread[Execution worker for ':' Thread 2,5,main]) completed. Took 0.002 secs.
如果修改了outputs包含的文件,那么会再次执行task:
# 命令行:gradle task_one -i > Task :task_one Watching 1 directory hierarchies to track changes Caching disabled for task ':task_one' because: Build cache is disabled Task ':task_one' is not up-to-date because: Output property '$1' file E:learn_gradletestdesctest.txt has changed. 执行任务task_one :task_one (Thread[Execution worker for ':' Thread 2,5,main]) completed. Took 0.002 secs.TaskInputs 接口
task的依赖必须先执行,这个之前已经了解了
mustRunAftertasks.register('task_one') { println "配置任务$name" doLast { println "执行任务$name" } } tasks.register('task_two') { mustRunAfter tasks.task_one println "配置任务$name" doLast { println "执行任务$name" } }
# gradle task_two task_one 配置任务task_one 配置任务task_two > Task :task_one 执行任务task_one > Task :task_two 执行任务task_two
# gradle task_two 配置任务task_one 配置任务task_two > Task :task_two 执行任务task_two
mustRunAfter 跟dependsOn 很大的不同就是,task不是必须要执行mustRunAfter指定的任务,而是当指定顺序的task都存在的时候,需要按照先后顺序来执行;dependsOn 则是无论有没有在命令行指明要执行依赖的task,任务的依赖都会先执行;
另外一点需要注意的,task的配置阶段执行顺序并不是当前的task一定在mustRunAfter之后。例如通过以下方式定义顺序,task_two将会先配置,所以尽量不要依赖配置阶段的执行顺序:
def task_one = tasks.register('task_one') { println "配置任务$name" doLast { println "执行任务$name" } } def task_two = tasks.register('task_two') { println "配置任务$name" doLast { println "执行任务$name" } } task_two.configure { mustRunAfter task_one }
# gradle task_two task_one 配置任务task_two 配置任务task_one > Task :task_one 执行任务task_one > Task :task_two 执行任务task_twoshouldRunAfter
跟mustRunAfter相似,但是并不严格,两种情况下shouldRunAfter 不做保证:
- 通过shouldRunAfter 导致了循环的情况;mustRunAfter对于循环的情况会报错。
- 当并行执行时,除了 “should run after” 类型依赖之外,其他类型的依赖都满足的情况下,当前任务就会执行。可以认为并行的时候并不会考虑shouldRunAfter。
指定当前任务的终结任务,可以用来指定在其后执行什么任务
tasks.register('task_one') { finalizedBy tasks.task_two println "配置任务$name" doLast { println "执行任务$name" } } tasks.register('task_two') { println "配置任务$name" doLast { println "执行任务$name" } }
# gradle task_one 配置任务task_two 配置任务task_one > Task :task_one 执行任务task_one > Task :task_two 执行任务task_two
finalizedBy 更重要的作用体现在出现异常的情况, 即便出现异常,其Finalizer 也会执行:
tasks.register('task_one') { finalizedBy tasks.task_two println "配置任务$name" doLast { println "执行任务$name" throw new RuntimeException() } } tasks.register('task_two') { println "配置任务$name" doLast { println "执行任务$name" } }
# gradle task_one 配置任务task_two 配置任务task_one > Task :task_one FAILED 执行任务task_one > Task :task_two 执行任务task_two FAILURE: Build failed with an exception.超时配置
超过配置的时间,任务失败并终止
tasks.register('task_one') { timeout = Duration.ofSeconds(3) println "配置任务$name" doLast { println "开始执行任务$name" Thread.sleep(5000) println "结束执行任务$name" } }
# gradle task_one 配置任务task_one > Task :task_one 开始执行任务task_one Requesting stop of task ':task_one' as it has exceeded its configured timeout of 3s. > Task :task_one FAILED FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':task_one'. > Timeout has been exceededTask rules
可以通过定义Rule 在运行的时候来定义、配置并执行任务:
tasks.addRule("自定义一个Rule") { String taskName -> if (taskName.startsWith("say_")) { task(taskName) { println "rule task $name" doLast { println "执行$name" } } } } tasks.register("task_one") { dependsOn("say_hi","say_hello") println "配置任务$name" doLast { println "执行任务$name" } }
# gradle say_bye rule task say_bye > Task :say_bye 执行say_bye
# gradle task_one 配置任务task_one rule task say_hi rule task say_hello > Task :say_hello 执行say_hello > Task :say_hi 执行say_hi > Task :task_one 执行任务task_one
通过Rule来定义的task最开始不会出现tasks任务列表中,通过gradle tasks --all 查不到, 只能看到rule的描述,所以如果定义Rule最好将描述写的更好一点。
# gradle tasks --all 结果的一部分 Rules ----- 自定义一个Rule
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)