Refer to
https://dongchuan.gitbooks.io/gradle-user-guide-/content/index.html
Tip: 文档翻译工作WIP, Git托管中
一个构建系统
- 像 Ant 一样的非常灵活的通用构建工具
- 可切换的, 像 maven 一样的基于合约构建的框架
- 支持强大的多工程构建
- 支持强大的依赖管理(基于 ApacheIvy )
- 支持已有的 maven 和 ivy 仓库
- 支持传递性依赖管理, 而不需要远程仓库或者 pom.xml 或者 ivy 配置文件
- 优先支持 Ant 式的任务和构建
- 基于 groovy 的构建脚本
- 有丰富的领域模型来描述你的构建
此指南就像 Gradle 一样还在开发当中;
通过这本指南, 将会看到一些代表 Gradle 任务之间依赖关系的图表. 类似于 UML 依赖关系的表示方法, 从一个任务 A 指向另一个任务 B 的箭头代表A依赖于B.
2 基于依赖的编程语言
声明式语言位于通用任务图(general purpose task graph)的顶端, 可以在构建中被被充分利用; 强大的灵活性, 可以满足使用者对Gradle的特别需求;
3 让构建结构化
Gradle的易适应性和丰富性可让你在构建中直接套用通用设计原则; e.g. 很容易地使用一些可重用的组件来组成构建, 但不必要的间接内联内容是不合适的; 不要强行拆分已经结合在一起的部分(e.g. 在自定义的项目层次结构中); 避免使构建难以维护;
可以创建一个结构良好,易于维护和易于理解的构建;
4 API深化
Gradle允许管理和定制它的配置和执行行为;
5 Gradle扩展
Gradle扩展得很好, 不管是简单的独立项目还是大型的多项目构建, 它都能显著提高效率; 这是真正的结构构建, 顶尖水平的构建功能, 还可以解决大公司遇到的构建性能低下的问题;
6 多项目构建
Gradle对多项目的支持是很出色的; 项目依赖是很重要的部分; 它允许模拟在多项目构建中项目的关系, 这正是所要关注的地方; 它遵从你的布局;
Gradle提供了局部构建功能; 如果构建一个单独的子项目, Gradle会构建这个子项目依赖的所有子项目; 额可以选择依赖于另一个特别的子项目来重新构建这些子项目; 这样在一些大型项目里可以节省很多时间;
7 多种方式来管理依赖
不同团队由不同的管理外部依赖的方法; Gradle 对于任何管理策略都提供了合适的支持; 从远程 Maven和 Ivy库到本地文件系统的 jars或 dirs;
8 Gradle是第一个构建整合工具
Ant的 tasks是 Gradle中重要部分, Ant的 projects也是重要的部分; Gradle可以直接引入 Ant项目, 在运行时直接将 Ant targets转换为 Gradle tasks; 可以从 Gradle中依赖它们, 增强功能, 甚至可以在 build.xml中声明 Gradle tasks的依赖; 并且 properties, paths等也可以通过同样的方法集成进来;
Gradle完全支持已有的 Maven或 Ivy仓库来构造发布或提取依赖; Gradle提供一个转化器, 用来将 maven的 pom.xml文件转换为 Gradle脚本; 在运行时引入 Maven项目也会推出;
9 易于迁移
Gradle可以兼容任何结构; 可以直接在产品构建的分支上开发 Gradle构建, 并且二者可以并行; 通常建议编写一些测试代码确保它们的功能时相同的; 通过这种方式, 在迁移的时候就不会显得混乱和不可靠, 通过婴儿学步的方式获得最佳实践;
10 Groovy
Gradle的构建脚本通过 Groovy编写而非 XML; 但不像其他方式, 这并不是为了简单的展示用动态语言编写的原始脚本的强大; 否则只会导致维护构建变得非常困难;
Gradle的设计时朝着一种语言的方向开发的, 并非一种死板框架; Groovy就像胶水, 把想要实现的构想和抽象的 Gradle粘在一起; Gradle提供了一些标准的构想, 但并不享有任何形式的特权; 相比其他声明式构建系统, 这是个比较突出的特点;
11 Gradle包装器
Gradle包装器允许在没有安装 Gradle的机器上运行 Gradle构建; 在一些持续集成的服务器上, 这个功能非常有用; 它同样能降低食欲一个开源项目的门槛, 构建将会很简单;
这个包装器对于公司来说也是很有吸引力的, 它无需Wie客户机提供相应的管理方案; 这种方式同样能强制某个版本Gradle的使用从而最小化某些支持问题;
12 免费和开源
Gradle是个开源项目, 遵循 ASL许可;
在脚本构建时, 一个内部的 DSL(动态语言)相对于 XML的优势是巨大的; why Groovy? 答案在于 Gradle的运行环境; 虽然 Gradle以一个通用构建工具为核心, 但它的重点是 Java项目; 这样的项目中, 显然团队成员都对 Java熟悉; 构建应尽可能对所有团队成员都是透明的, 所以选择了 Groovy;
为什么不直接用 Java作为构建脚本的语言? 对于团队, 它要有最高透明度和最低的学习曲线, 即容易掌握; 由于 Java的限制, 这样的构建语言不会那么完美和强大; 而像 Python, Groovy, Ruby语言, 作为构建语言会更高; 选择 Groovy是因为它给 Java开发人员提供了最大的透明度; 其基本符合和类型与Java一致, 其封装结构和许多其他地方都是;
Groovy在这些基础上提供了更多的功能, 和 Java共享基础;
对于那些同时是或即将是 Python或 Ruby开发的 Java开发来说, 上述讨论不适用; Gradle的设计适合在 JRuby和 Jython中创建另一个构建脚本引擎;
Gradle需要运行在一个 Java 环境里
- 安装JDK或JRE, 版本在6以上
- Gradle自带 Groovy库, 任何已安装的 Groovy会被 Gradle忽略
Gradle使用任何现存在路径中的 JDK(通过 java -version检查, 如果有说明系统已经安装了Java环境); 或者可以设置 JAVA_HOME环境参数来指定希望使用的 JDK的安装目录;
Gradle web site.
解压缩
发布的版本为 **ZIP 格式, 文件包含:
- Gradle 的二进制文件.
- 用户指南 (HTML 和 PDF).
- DSL参考指南.
- API文档 (Javadoc和 Groovydoc).
- 扩展的例子, 包括用户指南中引用的实例, 以及一些更复杂的实例来帮助用户构建自己的build.
- 二进制源码. 仅供参考.
设置环境变量
1. 添加一个 GRADLE_HOME 环境变量来指明 Gradle 的安装路径
2. 添加 GRADLE_HOME/bin 到您的 PATH 环境变量中.
Max OX:
假设 Gradle 文件在 /Users/UFreedom/gradle 目录
1.vim ~/.bash_profile
2.添加下面内容:
export GRADLE_HOME = /Users/UFreedom/gradle
export export PATH=$PATH:$GRADLE_HOME/bin
3.source ~/.brash_profile
运行并测试安装
在控制台输入 gradle 命令来运行Gradle. gradle -v 命令检测Gradle是否已经正确安装.
如果正确安装,会输出Gradle版本信息以及本地的配置环境 ( groovy 和 JVM 版本等). 显示的版本信息应该与下载的 gradle 版本信息相匹配.
通过设置环境变量来更改: 使用 GRADLE_OPTS 或者 JAVA_OPTS
- JAVA_OPTS 是一个用于 JAVA 应用的环境变量. 一个典型的用例是在 JAVA_OPTS 里设置HTTP代理服务器(proxy)
- GRADLE_OPTS 是内存选项. 这些变量可以在 gradle 的一开始就设置或者通过 gradlew 脚本来设置.
解决遇到的问题
首先要确定你使用的是最新版本的 Gradle;
如果使用 Gradle Daemon, 先暂时关闭 daemon switch –no-daemon 命令). 第19章–更多关于 daemon 的信息.
获得帮助 http://forums.gradle.org
Gradle 里的任何东西都是基于两个基础概念
- projects ( 项目 )
- tasks ( 任务 )
每一个构建都是由一个或多个 projects 构成的. 一个 project 到底代表什么依赖于你想用 Gradle 做什么. e.g. 一个 project 可以代表一个 JAR 或者一个网页应用. 它也可能代表一个发布的 ZIP 压缩包, 这个 ZIP 可能是由许多其他项目的 JARs 构成的.
但是一个 project 不一定非要代表被构建的某个东西. 它可以代表一件要做的事, 比如部署应用.
Gradle 的合约构建可以让你来具体定义一个 project 到底该做什么.
每一个 project 是由一个或多个 tasks 构成的. 一个 task 代表一些更加细化的构建. 可能是编译一些 classes, 创建一个 JAR, 生成 javadoc, 或者生成某个目录的压缩文件.
先来看看定义构建里的一些简单的 tasks. 以后的章节讲解多项目构建以及如何通过 projects 和 tasks 工作.
可以通过 gradle 命令运行一个 Gradle 构建.
gradle 命令会在当前目录中查找一个叫 build.gradle 的文件. 称这个 build.gradle 文件为一个构建脚本 (build script), 但是严格来说它是一个构建配置脚本 (build configuration script). 这个脚本定义了一个 project 和它的 tasks.
e.g. 创建一个名为build.gradle的构建脚本
6-1 第一个构建脚本
build.gradle
task hello {
doLast {
println 'Hello world!'
}
}
在命令行里, 进入脚本所在的文件夹然后输入 gradle -q hello 来执行构建脚本: gradle -q hello
gradle -q hello
Hello world!
构建脚本定义了一个独立的 task, 叫做 hello, 并且加入了一个 action. 当运行 gradle hello, Gradle 执行叫做 hello 的 task, 执行了所提供的 action. 这个 action 是一个包含了一些 Groovy 代码的闭包(closure).
这些看上去和 Ant 的 targets 很相像. Gradle tasks 和 Ant 的 targets 是对等的. 但是, Gradle tasks 更加强大. 我们使用一个不同于 Ant 的术语 task, 看上去比 target 更加直白.
不幸的是这带来了一个术语冲突, 因为 Ant 称它的命令, 比如 javac 或者 copy, 叫 tasks. 所以当谈论 tasks, 是指 Gradle 的 tasks. 如果我们讨论 Ant 的 tasks (Ant 命令), 会直接称呼 ant task.
命令里的 -q 是干什么的?
指南里绝大多说的例子会在命令里加入 -q. 代表 quiet 模式. 它不会生成 Gradle 的日志信息 (log messages), 所以用户只能看到 tasks 的输出. 使得的输出更加清晰. 你并不一定需要加入这个选项. 第 18 章–日志的 Gradle 影响输出的详细信息.
更简明的方法
6-3 快捷的任务定义
build.gradle
task hello << {
println 'Hello world!'
}
定义了一个叫做 hello 的任务, 这个任务是一个可以执行的闭包. 我们将使用这种方式来定义这本指南里所有的任务;
补充
与前面的例子比较, doLast 被替换成了 <<. 它们有一样的功能, 但看上去更加简洁, 章节 (6.7) 详细讲解它们的功能.
Gradle 的构建脚本展示了 Groovy 的所有能力
6-4 在 Gradle 任务里使用 Groovy
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
6-5 在 Gradle 任务里使用 Groovy
build.gradle
task count << {
4.times { print "$it " }
}
gradle -q count
gradle -q count
0 1 2 3
可以声明任务之间的依赖关系
6-6 申明任务之间的依赖关系
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
intro 依赖于 hello, 所以执行 intro 的时候 hello 命令会被优先执行来作为启动 intro 任务的条件.
在加入一个依赖之前, 这个依赖的任务不需要提前定义
6-7 Lazy dependsOn - 其他的任务还没有存在
build.gradle
task taskX(dependsOn: 'taskY') << {
println 'taskX'
}
task taskY << {
println 'taskY'
}
gradle -q taskX 命令的输出
gradle -q taskX
taskY
taskX
taskX 到 taskY 的依赖在 taskY 被定义之前就已经声明了. 这一点对于之后讲到的多任务构建是非常重要的. 任务依赖–14.4.
请注意当所关联的任务还没有被定义时, 不能使用快捷注释 (参考6.8“快捷注释”)
Groovy 不仅仅被用来定义一个任务可以做什么. e.g. 可以使用它来动态的创建任务.
6-8 动态创建一个任务
build.gradle
4.times { counter ->
task "task$counter" << {
println "I'm task number $counter"
}
}
动态创建了 task0, task1, task2, task3
gradle -q task1 命令的输出
gradle -q task1
I’m task number 1
当任务创建之后, 它可以通过API来访问. 这个和 Ant 不一样. e.g.可以创建额外的依赖.
6-9 通过API访问一个任务 - 加入一个依赖
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
或者你可以给一个已经存在的任务加入行为.
6-10 通过API访问一个任务 - 加入行为
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 可以被执行许多次. 他们分别可以在任务动作列表的开始和结束加入动作. 当任务执行的时候, 在动作列表里的动作将被按顺序执行. 这里第四个行为中 << 操作符是 doLast 的简单别称.
有一个短标记 $ 可以访问一个存在的任务. 也就是说每个任务都可以作为构建脚本的属性:
6-11 当成构建脚本的属性来访问一个任务
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.
这里的 name 是任务的默认属性, 代表当前任务的名称 – hello.
代码易于读取, 特别是当使用了由插件(如编译)提供的任务时尤其如此.
可以给任务加入自定义的属性. 列如加入一个叫做 myProperty 属性, 设置一个初始值给 ext.myProperty. 然后, 该属性就可以像一个预定义的任务属性那样被读取和设置了.
6-12 给任务加入自定义属性
build.gradle
task myTask {
ext.myProperty = "myValue"
}
task printTaskProperties << {
println myTask.myProperty
}
gradle -q printTaskProperties 命令的输出
gradle -q printTaskProperties
myValue
给任务加自定义属性是没有限制的. 13.4.2“自定义属性”
Ant 任务是 Gradle 的一等公民. Gradle 通过 Groovy 出色的集成了 Ant 任务. Groovy 自带了一个 AntBuilder. 相比于从一个 build.xml 文件中使用 Ant 任务, 在 Gradle 里使用 Ant 任务更为方便和强大.
e.g. 学习如何执行 Ant 任务以及如何访问 ant 属性:
6-13 使用 AntBuilder 来执行 ant.loadfile 任务
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 ***
使用方法
Gradle 能很好地衡量你编写脚本的逻辑能力. 首先要做的是如何提取一个方法.
6-14 使用方法组织脚本逻辑
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()
}
adle -q loadfile 命令的输出
gradle -q loadfile
I’m fond of agile.manifesto.txt
I’m fond of gradle.manifesto.txt
稍后会看到, 这种方法可以在多项目构建的子项目之间共享. 如果构建逻辑变得更加复杂, Gradle 提供了其他非常方便的方法. 参见第59章–组织构建逻辑。
Gradle 允许在脚本中定义一个或多个默认任务.
6-15 定义默认任务
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 -q clean run.
在一个多项目构建中, 每一个子项目都可以有它特别的默认任务. 如果一个子项目没有特别的默认任务, 父项目的默认任务将会被执行.
正如之后的详细描述 (第55章–构建的生命周期), Gradle 有一个配置阶段和执行阶段. 在配置阶段后, Gradle 将会知道应执行的所有任务.
Gradle 提供一个”钩子”, 以便利用这些信息. e.g. 判断发布的任务是否在要被执行的任务当中. 根据这一点, 可以给一些变量指定不同的值.
e.g. distribution 任务和 release 任务将根据变量的版本产生不同的值.
6-16 根据选择的任务产生不同的输出
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
Output of gradle -q release
gradle -q release
We build the zip with version=1.0
We release now
最重要的是 whenReady 在 release 任务执行之前就已经影响了 release 任务. 甚至 release 任务不是首要任务 (i.e., 首要任务是指通过 gradle 命令的任务).
—TBC—
—YCR—