在 Gradle 中两个顶级概念:project(项目)和 task 任务)
所有 Gradle 都有一个或多个 project 构成。project 的展现取决于 Gradle 所做的工作。举例。 project 可以是一个 JAR 库 或者是 web 应用。它可以是由项目生产 JAR 组成发布的 ZIP。一个 project 不一定 代表一个东西要构建。它可能是一件要做的事,如将应用程序部署到工作台 或生产环境。如果这看起来有点模糊,现在不要担心。Gradle 基于约定的构建支持增加一个 更具体的定义的 project。
每个项目都是由一个或多个 task。一个 task 代表了一个构建生成的原子的作品。这可能是编写一些类,创建一个 JAR ,生成 Javadoc,或发布一些库。
现在,我们将看看在构建一个 project 时定义一些简单的 task 。后面的章节将介绍多个 project 和更多的 task 。
##6.2. Hello world
运行 Gradle 是使用 gradle 命令行。命令行会寻找项目的根目录下 build.gradle 的文件(有关命令行,详见 Appendix D. Gradle Command Line 命令行),这个就是构建的脚本,或者严格说是构建的配置脚本。他定义了project(项目)和 task 任务)。
尝试输出,创建一个 build.gradle
命名的文件:
Example 6.1. Your first build script
build.gradle
task hello {
doLast {
println 'Hello world!'
}
}
命令行切换到包含 build.gradle 文件的目录,执行 gradle -q hello
Example 6.2. Execution of a build script
输出为:
> gradle -q hello
Hello world!
这个脚本定义了一个 名字是hello
的 task,并且添加了动作。当运行 gradle hello
,Gradle 执行这个 hello
task,接着执行里面的动作。这里的动作只是简单的包含了一些可以执行的 Groovy 代码。
看上去很像 Ant ,不错,Gradle task 是相当于 Ant 的 target,但是你将看到,他们更强大。我们使用了跟 Ant 不同的术语,因为 task 比 target 更富表现力。
不幸的是,这一术语与 Ant 有冲突,Ant 调用它的命令行,如 javac 或copy 称之为 task 。所以当我们谈论的 task ,默认说的是 Gradle task ,这是相当 Ant 的 target。如果我们谈论的 Ant 的 task (Ant 命令),我们明确地说的 Ant task。
###命令行加中 -q
的作用
q 是 quiet 的简写,意思是要安静、干净的输出。如果不加 -q
则会输出日志。详见Chapter 18. Logging 日志.下面是对比
##6.3. A shortcut task definition 快捷 task 定义
定义 task 可以使用快捷方式,这样更简明。
Example 6.3. A task definition shortcut
build.gradle
task hello << {
println 'Hello world!'
}
再次执行,得到相同的输出。在下面的文章中,我们都会采用这种定义方式。
##6.4. Build scripts are code 构建的脚本都是代码
工具的构建脚本给你完整的 Groovy 的功能。作为开胃菜,看看这个:
Example 6.4. Using Groovy in Gradle's tasks
build.gradle
task upper << {
String someString = 'mY_nAmE'
println "Original: " + someString
println "Upper case: " + someString.toUpperCase()
}
执行 gradle -q upper
输出
> gradle -q upper
Original: mY_nAmE
Upper case: MY_NAME
或者
Example 6.5. Using Groovy in Gradle's tasks
build.gradle
task count << {
4.times { print "$it " }
}
执行 gradle -q count
输出
> gradle -q count
0 1 2 3
可以声明 task 与 其他 task 的依赖
Example 6.6. Declaration of task that depends on other task
build.gradle
task hello << {
println 'Hello world!'
}
task intro(dependsOn: hello) << {
println "I'm Gradle"
}
执行 gradle -q intro
输出
> gradle -q intro
Hello world!
I'm Gradle
添加一个依赖,相应的 task 不需要存在
Example 6.7. Lazy dependsOn - the other task does not exist (yet)
build.gradle
task taskX(dependsOn: 'taskY') << {
println 'taskX'
}
task taskY << {
println 'taskY'
}
执行 gradle -q taskX
输出
> gradle -q taskX
taskY
taskX
taskX 的依赖 taskY 是在 taskY 定义之前 声明的。这个在多 project 构建时很重要。关于 task 的依赖详见 Chapter 15. More about Tasks 更多关于任务
请注意不要使用快捷符号,当引用的 task 还没有定义的情况下。
##6.6. Dynamic tasks 动态 task
Groovy 的能力不仅仅是定义一个 task。例如,你也可以用它来动态创建的 task。
Example 6.8. Dynamic creation of a task
build.gradle
4.times { counter ->
task "task$counter" << {
println "I'm task number $counter"
}
}
执行 gradle -q task1
输出
> gradle -q task1
I'm task number 1
##6.7. Manipulating existing tasks 利用现有的任务
一旦 task 创建,他们可以通过一个 API 访问。例如,在运行时您可以使用此动态添加依赖到 task 。Ant 不允许这样的事情。
Example 6.9. Accessing a task via API - adding a dependency
build.gradle
4.times { counter ->
task "task$counter" << {
println "I'm task number $counter"
}
}
task0.dependsOn task2, task3
执行 gradle -q task0
输出
> gradle -q task0
I'm task number 2
I'm task number 3
I'm task number 0
或者 可以添加行为到一个已经存在 task 中
Example 6.10. Accessing a task via API - adding behaviour
build.gradle
task hello << {
println 'Hello Earth'
}
hello.doFirst {
println 'Hello Venus'
}
hello.doLast {
println 'Hello Mars'
}
hello << {
println 'Hello Jupiter'
}
执行 gradle -q hello
输出
> gradle -q hello
Hello Venus
Hello Earth
Hello Mars
Hello Jupiter
doFirst 和 doLast 可以多次执行调用。他们在开始或结束的 task 动作清单中添加动作。task 执行时,按动作列表的顺序执行的动作。操作符 <<
仅仅是 doLast 的别名。
##6.8. Shortcut notations 快捷符号
在前面的示例中已经注意到,有一个方便的符号访问现有的 task 。每个 task 可以作为构建脚本的一个属性:
Example 6.11. Accessing task as a property of the build script
build.gradle
task hello << {
println 'Hello world!'
}
hello.doLast {
println "Greetings from the $hello.name task."
}
执行 gradle -q hello
输出
> gradle -q hello
Hello world!
Greetings from the hello task.
这使得代码可读性增强,尤其是当使用的插件提供的 task ,如 compile task
##6.9. Extra task properties 额外 task 属性
可以添加自己属性到 task ,添加 myProperty
属性,设置 、ext.myProperty
初始值,从这一点上,该属性可以读取和设置就像一个预定义的任务属性。
Example 6.12. Adding extra properties to a task
build.gradle
task myTask {
ext.myProperty = "myValue"
}
task printTaskProperties << {
println myTask.myProperty
}
执行 gradle -q printTaskProperties
输出
> gradle -q printTaskProperties
myValue
task 不对额外属性做限制,更多详见Chapter 13. Writing Build Scripts 编写构建脚本 中 13.4.2 节 “Extra properties”.
##6.10. Using Ant Tasks 使用 Ant task
Ant task 是 Gradle 一等公民。 Gradle 给 Ant task 提供了不错的整合通过简单依靠于 Gradle 。Groovy 被奇异的 AntBuilder 装载。从 Gradle 使用 Ant task 比使用 build.xml 文件更方便和更强大。从下面的例子中,你可以学习如何执行 Ant task 和如何访问 Ant 属性:
Example 6.13. Using AntBuilder to execute ant.loadfile target
build.gradle
task loadfile << {
def files = file('antLoadfileResources').listFiles().sort()
files.each { File file ->
if (file.isFile()) {
ant.loadfile(srcFile: file, property: file.name)
println " *** $file.name ***"
println "${ant.properties[file.name]}"
}
}
}
执行 gradle -q loadfile
输出
> gradle -q loadfile
*** agile.manifesto.txt ***
Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration over contract negotiation
Responding to change over following a plan
*** gradle.manifesto.txt ***
Make the impossible possible, make the possible easy and make the easy elegant.
(inspired by Moshe Feldenkrais)
更多关于 构建脚本中使用 Ant ,详见 Chapter 17. Using Ant from Gradle 从 Gradle 使用 Ant
##6.11. Using methods 使用方法
Gradle 延伸取决你如何组织的建造逻辑。上面的例子中的第一级别的组织你的构建逻辑,是提取方法。
Example 6.14. Using methods to organize your build logic
build.gradle
task checksum << {
fileList('../antLoadfileResources').each {File file ->
ant.checksum(file: file, property: "cs_$file.name")
println "$file.name Checksum: ${ant.properties["cs_$file.name"]}"
}
}
task loadfile << {
fileList('../antLoadfileResources').each {File file ->
ant.loadfile(srcFile: file, property: file.name)
println "I'm fond of $file.name"
}
}
File[] fileList(String dir) {
file(dir).listFiles({file -> file.isFile() } as FileFilter).sort()
}
执行 gradle -q loadfile
输出
> gradle -q loadfile
I'm fond of agile.manifesto.txt
I'm fond of gradle.manifesto.txt
以后你会发现这样的方法可以在多 project 构建的子 project 之间共享。如果你建立逻辑变得越来越复杂,Gradle 为您提供其他工具很方便的方式来组织它。我们有专门一章Chapter 60. Organizing Build Logic
##6.12. Default tasks 默认 task
Gradle 允许你定义一个或多个默认 task 给你的构建
Example 6.15. Defining a default tasks
build.gradle
defaultTasks 'clean', 'run'
task clean << {
println 'Default Cleaning!'
}
task run << {
println 'Default Running!'
}
task other << {
println "I'm not a default task!"
}
执行 gradle -q
输出
> gradle -q
Default Cleaning!
Default Running!
这个等于执行了 gradle clean run
,在多 project 中构建所有的子 project 都可以有自己具体的默认 task 。如果 子 project 没有明确的默认 task,则执行父 project 的默认 task(如果定义的话)
##6.13. Configure by DAG 通过 DAG 配置
以后会详细描述(见Chapter 56. The Build Lifecycle 构建生命周期 ),Gradle 有配置阶段和执行阶段。配置阶段后,Gradle 知道所有的 task 应该执行。Gradle 提供给你一个钩子来利用这些信息。这个用例将检查发布 的 task 是否是要执行的 task。基于此,你可以赋予不同的值到一些变量。
在下面的例子中,在不同 version 变量中的 distribution 和 release task 执行结果不同。
Example 6.16. Different outcomes of build depending on chosen tasks
build.gradle
task distribution << {
println "We build the zip with version=$version"
}
task release(dependsOn: 'distribution') << {
println 'We release now'
}
gradle.taskGraph.whenReady {taskGraph ->
if (taskGraph.hasTask(release)) {
version = '1.0'
} else {
version = '1.0-SNAPSHOT'
}
}
执行 gradle -q distribution
输出
> gradle -q distribution
We build the zip with version=1.0-SNAPSHOT
执行 gradle -q release
输出
> gradle -q release
We build the zip with version=1.0
We release now
whenReady
影响了 release task 在 release task 被执行之前。同样适用于 release task 不是 主 task 的情况(比如,task 被 gradle 命令通过了)
##6.14. Where to next? 下一步工作
本章,我们大概浏览了下 task ,但这不是 task 的全部,可以详见Chapter 15. More about Tasks 更多关于任务
另外,继续教程 Chapter 7. Java Quickstart 快速开始 Java 和 Chapter 8. Dependency Management Basics 依赖管理的基础知识.md