Contents
- Projects,plugins and tasks
- Hello world
- Build script are code
- Task dependencies
- Flexible task registration
- Manipulating existing tasks
- Using Ant Tasks
- Using methods
- Default tasks
- External dependencies for the build script
- Futher Reading
如何编写Gradle 构建脚本,这里使用了基本的例子解释Gradle 基本的功能 …
它能够帮助你理解基础概念 ..
特别是如果你从其他构建工具迁移到Gradle(例如Ant) 并且你想理解它们的不同以及优势 …
然而,为了从一个标准的项目构建开始,你不需要完全详细的理解这些概念 … 相反你能够进行快速的认识,可以从它开始 step-by-step samples .
Project,plugins and tasks
每一个Gradle 由一个或者多个项目组成 … 什么样的项目取决于你想要Gradle 用来干什么 … 举个例子,一个项目可能是库 或者 web 应用 ..
它可能呈现了为zip 发行文件(根据由其他项目生产的Jar 进行打包而成) … .
一个项目并没有必要一定要构建东西 .. 它可能代表一件可以完成的事情,例如部署你的应用到 阶段或者 生产环境 …
如果你现在看的有一点小小的模糊,混乱,请不要担心 ..
Gradle 的通过约定的构建支持 增加了更多具体的定义 - 决定一个项目到底是什么 …
Gradle 的工作能够在项目上是通过定义一个或者多个任务完成的 ..
一个任务呈现了构建执行的某一个工作的原子块 …
它可能编译某些类 或者创建一个JAR ,生成Javadoc 或者发布某些归档文件到Maven 仓库 ..
通常来说,任务通过应用插件的形式进行提供, 因此你不需要自己去定义它们 .. 仍然,为了给你一个思考,任务到底是什么? 我们将尝试在构建中的一个项目中定义某些简单的任务 ..
Hello world
你能够使用gradle 命令运行Gradle 构建 … gradle 命令在当前的目录中寻找一个叫做build.gradle 的文件 …
我们叫它为构建脚本,尽管严格的说法它是叫做 构建配置脚本,这个构建脚本将会定义一个项目以及它的任务 ..
首先创建一个build.gradle,并创建一个任务 …
tasks.register('hello') {
doLast {
println 'Hello world!'
}
}
在命令行环境下,迁移到包含这个脚本的目录并执行构建脚本 去执行任务 …
> gradle -q hello
-q 到底在做什么 ? 在我们的大多数示例中我们都使用了-q 命令行选项 .. 这压制了Gradle 的日志消息 .. 因此仅仅任务的消息将会展示 .. 让我们的输出更加的清晰 .. 你可以不使用此选项 … 查看 Logging 了解更多详情, 关于如何通过命令行选项影响Gradle 的输出 ..
Output of gradle -q hello
> gradle -q hello
Hello world!
这里我们定义了一个任务并执行它 .. 通过gradle hello 命令,那么Gradle 将会执行hello 任务, 这将会执行我们提供的action … 这个action 是一个简单的闭包(其中包含了需要执行的代码) …
如果你任务这看起来类似于 Ant的 targets,你的感觉是正确的 … Gradle 的任务等价于 Ant 的 targets .. 但是正如你所见,它们是更好的 … 我们使用不同的技术 并认为 task 一词比target 表达的含义更加清楚 … 因此我们引入了和Ant的一些技术冲击 .. 因为Ant 调用任务将他们视为命令,例如 javac / copy ,任务 …
因此当我们在谈论任务时,我们总是描述的是Gradle 的任务,它们等价于Ant的Targets .
如果我们谈论Ant 任务(Ant commands),我们会显式的说明这是Ant 任务 …
Build scripts are code
Gradle 的构建脚本让你能够完全得到Groovy 和Kotlin 的支持 … 作为一个开胃菜,我们可以先看一看:
使用Groovy define Gradle 的 任务
tasks.register('upper') {
doLast {
String someString = 'mY_nAmE'
println "Original: $someString"
println "Upper case: ${someString.toUpperCase()}"
}
}
Output of gradle -q upper
> gradle -q upper
Original: mY_nAmE
Upper case: MY_NAME
或者
tasks.register('count') {
doLast {
4.times { print "$it " }
}
}
Output of gradle -q count
> gradle -q count
0 1 2 3
任务依赖
你可能会想到,你能够定义任务依赖于那些任务
tasks.register('hello') {
doLast {
println 'Hello world!'
}
}
tasks.register('intro') {
dependsOn tasks.hello
doLast {
println "I'm Gradle"
}
}
Output of gradle -q intro
> gradle -q intro
Hello world!
I'm Gradle
懒依赖,其他任务可以不存在
tasks.register('taskX') {
dependsOn 'taskY'
doLast {
println 'taskX'
}
}
tasks.register('taskY') {
doLast {
println 'taskY'
}
}
Output of gradle -q taskX
> gradle -q taskX
taskY
taskX
例如taskX的依赖是taskY,它们声明是随意的,任务依赖详情在这里 .
Flexible task registration
Groovy / kotlin 的能力不仅仅被用来定义任务做什么 .. 例如,你能够使用它去注册相同类型的多个任务(在循环中) …
4.times { counter ->
tasks.register("task$counter") {
doLast {
println "I'm task number $counter"
}
}
}
或者 kotlin
repeat(4) { counter ->
tasks.register("task$counter") {
doLast {
println("I'm task number $counter")
}
}
}
管理 / 操作存在的任务
4.times { counter ->
tasks.register("task$counter") {
doLast {
println "I'm task number $counter"
}
}
}
tasks.named('task0') { dependsOn('task2', 'task3') }
一旦任务注册,它们能够通过API 进行访问,例如 你能够动态的增加依赖给任务 ..
在运行时,Ant 不允许类似这样的事情 …
Output of gradle -q task0
> gradle -q task0
I'm task number 2
I'm task number 3
I'm task number 0
或者你能够为存在的任务增加行为
tasks.register('hello') {
doLast {
println 'Hello Earth'
}
}
tasks.named('hello') {
doFirst {
println 'Hello Venus'
}
}
tasks.named('hello') {
doLast {
println 'Hello Mars'
}
}
tasks.named('hello') {
doLast {
println 'Hello Jupiter'
}
}
> gradle -q hello
Hello Venus
Hello Earth
Hello Mars
Hello Jupiter
那么这个任务具有4个动作 …
doFirst / doLast 能够执行多次 … 它们增加动作到任务动作列表的前面或者结束 …
动作列表中的所有动作依次执行 …
使用Ant 任务
Ant 任务是Gradle中的一等公民 .. Gradle 提供了对Ant 任务优秀的集成(通过简单的依赖于Groovy) …
Groovy 附带了出色的 AntBuilder .
从Gradle 中使用Ant 任务是非常便利的并且比使用build.xml中的Ant 任务更强大 ..
Ant 也可以通过kotlin 进行使用, 例如学习如何执行Ant 任务并如何访问Ant 属性 …
Using AntBuilder to execute ant.loadfile target
tasks.register('loadfile') {
doLast {
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
*** 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)
关于在gradle 构建脚本中大量使用 Ant,可以从这里查看 ..
Using methods
Gradle 可扩展您如何组织构建逻辑。
例如为刚才的例子抓取一个方法:
tasks.register('checksum') {
doLast {
fileList('./antLoadfileResources').each { File file ->
ant.checksum(file: file, property: "cs_$file.name")
println "$file.name Checksum: ${ant.properties["cs_$file.name"]}"
}
}
}
tasks.register('loadfile') {
doLast {
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 提供了你其他非常方便的方式去组织它 …
查看另一篇文章了解 … Organizing Gradle Projects
默认任务
Gradle 允许你 定义一个或者多个默认任务(如果在构建时没有指定运行任务) …
defaultTasks 'clean' , 'run'
tasks.register('celan') {
doLast {
println Cleaning!'
}
}
tasks.register('run') {
doLast {
println 'Default Running!'
}
}
tasks.register("other") {
doLast {
println "I'm not a default task!"
}
}
如果执行 gradle -q
那么将输出:
> gradle -q
Default Cleaning!
Default Running!
这完全等价于 gradle clean run , 在多项目构建中子项目能够有自己的指定的默认任务 ..
如果子项目没有指定默认任务, 那么将会使用父项目的默认任务(如果定义) ….
构建脚本的外部依赖
处理直接操作脚本类路径之外,建议应用自带类路径的插件 .. 对于自定义构建逻辑, 推荐使用自定义插件 …
如果你的构建脚本需要使用外部库,你能够将他们增加到脚本的类路径上 (在构建脚本中) …
通过buildscript() 方法配置构建脚本,传递一个闭包用来声明构建脚本类路径 …
声明构建脚本的类路径
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath group: 'commons-codec', name: 'commons-codec', version: '1.2'
}
}
这个方法将会配置一个代理对象,类型为 ScriptHandler, 你能够通过 classpath 配置增加类路径依赖 ..
这等价于在Java 编译类路径上声明的依赖相同方式 …
你能够使用任何依赖类型,除了项目依赖 …(因为类路径不一致) ..
当你在构建类路径上声明了依赖,你能够使用这些类到构建脚本中 …
例如:
import org.apache.commons.codec.binary.Base64
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath group: 'commons-codec', name: 'commons-codec', version: '1.2'
}
}
tasks.register('encode') {
doLast {
def byte[] encodedString = new Base64().encode('hello world\n'.getBytes())
println new String(encodedString)
}
}
导入apache的计算库进行使用 …
Output of gradle -q encode
> gradle -q encode
aGVsbG8gd29ybGQK
对于多项目构建,单个项目的buildscript项目上声明的依赖 .. 同样对它的所有子项目的buildscript 脚本有效 …
构建脚本依赖也可以抽象为一个Gradle plugins …
请考虑 Using Gradle Plugins[TODO] 了解gradle 的插件信息 …
每一个项目会自动包含一个 BuildEnvironmentReportTask 类型的 buildEnvironment 任务 … 它能够执行去报告构建脚本依赖解析情况 ..