Gradle 任务详述


本文整理自网络,侵删。

任务详述

在入门教程构建基础中,你已经学习了如何创建简单的任务。之后您还学习了如何将其他行为添加到这些任务中。并且你已经学会了如何创建任务之间的依赖。这都是简单的任务。但 Gradle 让任务的概念更深远。Gradle 支持增强的任务,也就是,有自己的属性和方法的任务。这是真正的与你所使用的 Ant 目标(target)的不同之处。这种增强的任务可以由你提供,或由 Gradle 提供。

定义任务

在构建基础中我们已经看到如何通过关键字这种风格来定义任务。在某些情况中,你可能需要使用这种关键字风格的几种不同的变式。例如,在表达式中不能用这种关键字风格。

定义任务

build.gradle

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

您还可以使用字符串作为任务名称:

定义任务 — — 使用字符串作为任务名称

build.gradle

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

对于定义任务,有一种替代的语法你可能更愿意使用:

使用替代语法定义任务

build.gradle

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

在这里我们将任务添加到 tasks 集合。关于 create() 方法的更多变化可以看看 TaskContainer。

定位任务

你经常需要在构建文件中查找你所定义的任务,例如,为了去配置或是依赖它们。对这样的情况,有很多种方法。首先,每个任务都可作为项目的一个属性,并且使用任务名称作为这个属性名称:

以属性方式访问任务

build.gradle

task hello
println hello.name
println project.hello.name  

任务也可以通过 tasks 集合来访问。

通过 tasks 集合访问任务

build.gradle

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

您可以从任何项目中,使用 tasks.getByPath() 方法获取任务路径并且通过这个路径来访问任务。你可以用任务名称,相对路径或者是绝对路径作为参数调用 getByPath() 方法。

通过路径访问任务

build.gradle

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  

gradle -q hello的输出结果

> gradle -q hello
:hello
:hello
:projectA:hello
:projectA:hello  

有关查找任务的更多选项,可以看一下 TaskContainer。

配置任务

作为一个例子,让我们看看由 Gradle 提供的 Copy 任务。若要创建 Copy 任务,您可以在构建脚本中声明:

创建一个复制任务

build.gradle

task myCopy(type: Copy)  

上面的代码创建了一个什么都没做的复制任务。可以使用它的 API 来配置这个任务(见 Copy)。下面的示例演示了几种不同的方式来实现相同的配置。

配置任务的几种方式

build.gradle

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

这类似于我们通常在 Java 中配置对象的方式。您必须在每一次的配置语句重复上下文 (myCopy)。这显得很冗余并且很不好读。

还有另一种配置任务的方式。它也保留了上下文,且可以说是可读性最强的。它是我们通常最喜欢的方式。

配置任务-使用闭包

build.gradle

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

这种方式适用于任何任务。该例子的第 3 行只是 tasks.getByName() 方法的简洁写法。特别要注意的是,如果您向 getByName() 方法传入一个闭包,这个闭包的应用是在配置这个任务的时候,而不是任务执行的时候。

您也可以在定义一个任务的时候使用一个配置闭包。

使用闭包定义任务

build.gradle

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

对任务添加依赖

定义任务的依赖关系有几种方法。在依赖管理基础中,已经向你介绍了使用任务名称来定义依赖。任务的名称可以指向同一个项目中的任务,或者其他项目中的任务。要引用另一个项目中的任务,你需要把它所属的项目的路径作为前缀加到它的名字中。下面是一个示例,添加了从 projectA:taskX 到 projectB:taskY 的依赖关系:

从另一个项目的任务上添加依赖

build.gradle

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

gradle -q taskX 的输出结果

> gradle -q taskX
taskY
taskX  

您可以使用一个 Task 对象而不是任务名称来定义依赖,如下:

使用 task 对象添加依赖

build.gradle

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

gradle -q taskX的输出结果

> gradle -q taskX
taskY
taskX  

对于更高级的用法,您可以使用闭包来定义任务依赖。在计算依赖时,闭包会被传入正在计算依赖的任务。这个闭包应该返回一个 Task 对象或是 Task 对象的集合,返回值会被作为这个任务的依赖项。下面的示例是从 taskX 加入了项目中所有名称以 lib 开头的任务的依赖:

使用闭包添加依赖

build.gradle

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 的输出结果

> gradle -q taskX
lib1
lib2
taskX  

有关任务依赖的详细信息,请参阅 Task 的 API。

任务排序

任务排序还是一个孵化中的功能。请注意此功能在以后的 Gradle 版本中可能会改变。

在某些情况下,控制两个任务的执行的顺序,而不引入这些任务之间的显式依赖,是很有用的。任务排序和任务依赖之间的主要区别是,排序规则不会影响那些任务的执行,而仅将执行的顺序。

任务排序在许多情况下可能很有用:

  • 强制任务顺序执行: 如,'build' 永远不会在 'clean' 前面执行。
  • 在构建中尽早进行构建验证:如,验证在开始发布的工作前有一个正确的证书。
  • 通过在长久验证前运行快速验证以得到更快的反馈:如,单元测试应在集成测试之前运行。
  • 一个任务聚合了某一特定类型的所有任务的结果:如,测试报告任务结合了所有执行的测试任务的输出。

有两种排序规则是可用的:"必须在之后运行"和"应该在之后运行"。

通过使用 “ 必须在之后运行”的排序规则,您可以指定 taskB 必须总是运行在 taskA 之后,无论 taskA 和 taskB 这两个任务在什么时候被调度执行。这被表示为 taskB.mustRunAfter(taskA) 。“应该在之后运行”的排序规则与其类似,但没有那么严格,因为它在两种情况下会被忽略。首先是如果使用这一规则引入了一个排序循环。其次,当使用并行执行,并且一个任务的所有依赖项除了任务应该在之后运行之外所有条件已满足,那么这个任务将会运行,不管它的“应该在之后运行”的依赖项是否已经运行了。当倾向于更快的反馈时,会使用“应该在之后运行”的规则,因为这种排序很有帮助但要求不严格。

目前使用这些规则仍有可能出现 taskA 执行而 taskB 没有执行,或者 taskB 执行而 taskA 没有执行。

添加 '必须在之后运行 ' 的任务排序

build.gradle

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

gradle -q taskY taskX 的输出结果

> gradle -q taskY taskX
taskX
taskY  

添加 '应该在之后运行 ' 的任务排序

build.gradle

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

gradle -q taskY taskX 的输出结果

> gradle -q taskY taskX
taskX
taskY  

在上面的例子中,它仍有可能执行 taskY 而不会导致 taskX 也运行:

任务排序并不意味着任务执行

gradle -q taskY 的输出结果

> gradle -q taskY
taskY  

如果想指定两个任务之间的“必须在之后运行”和“应该在之后运行”排序,可以使用 Task.mustRunAfter() 和 Task.shouldRunAfter() 方法。这些方法接受一个任务实例、 任务名称或 Task.dependsOn()所接受的任何其他输入作为参数。

请注意"B.mustRunAfter(A)"或"B.shouldRunAfter(A)"并不意味着这些任务之间的任何执行上的依赖关系:

  • 它是可以独立地执行任务 A 和 B 的。排序规则仅在这两项任务计划执行时起作用。
  • 当--continue 参数运行时,可能会是 A 执行失败后B执行了。

如之前所述,如果“应该在之后运行”的排序规则引入了排序循环,那么它将会被忽略。

当引入循环时,“应该在其之后运行”的任务排序会被忽略

build.gradle

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

gradle -q taskX 的输出结果

> gradle -q taskX
taskZ
taskY
taskX  

向任务添加描述

你可以向你的任务添加描述。例如,当执行 gradle tasks 时显示这个描述。

向任务添加描述

build.gradle

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

替换任务

有时您想要替换一个任务。例如,您想要把通过 Java 插件添加的一个任务与不同类型的一个自定义任务进行交换。你可以这样实现:

阅读剩余部分

相关阅读 >>

Gradle Gradle 守护进程

Gradle ear 插件

Gradle 使用文件

Gradle 问题反馈

Gradle jdepend 插件

Gradle 构建环境

Gradle java 插件

Gradle 教程 - 杂七杂八

Gradle codenarc 插件

Gradle war 插件

更多相关阅读请进入《Gradle》频道 >>



打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...