这一章我们将要深入的学习如何编写构建脚本.
Gradle 是以 Groovy 语言为基础, 基于DSL (领域特定语言) 语法的自动化构建工具,但是它增加了一些额外的特性,这使得Gradle更加的容易去阐释构建.
一个构建脚本能够包含任何Groovy语言的元素 ( Any language element except for statement labels ), 每个构建脚本都使用UTF-8编码.
在第七章 Java构建入门那部分我们使用了 apply() 方法,这个方法是从哪里来的呢? 我们之前说过Gradle在构建脚本中定义了一个项目. 对于构建脚本中每个项目,Gradle 都创建了一个 Project 类型的对象用来关联此项目. 当构建脚本执行时,它会去配置所关联的工程对象.
构建脚本中每个被调用的方法(这些方法并未在构建脚本中定义)都被委托给当前工程对象(使用工程对象引用方法)。
构建脚本中每个被操作的属性(这些属性并未在构建脚本中定义)都被委托给当前工程对象(使用工程对象引用属性).
让我们尝试下如何操作工程对象的属性.
例子:13.1 操作工程对象的属性
build.gradle
println name
println project.name
使用 gradle -q check 命令输出结果:
> gradle -q check
projectApi
projectApi
如您所见,两个 println 语句都输出了相同的属性,第一个输出使用的是自动委托 ( auto-delegation ), 因为当前属性并没有在构建脚本中定义. 另一个语句使用了项目一个属性,这个属性在任何构建脚本中都可用,它的返回值是被关联的工程对象. 只有当您定义了一个属性或者一个方法, 它的名字和工程对象的某个成员的名字相同时, 你应该使用项目属性.
Project 对象提供了一些标准的属性,您可以在构建脚本中很方便的使用他们. 下面列出了常用的属性:
Name | Type | Default Value |
---|---|---|
project | Project | Project 实例对象 |
name | String | 项目目录的名称 |
path | String | 项目的绝对路径 |
description | String | 项目描述 |
projectDir | File | 包含构建脚本的目录 |
build | File | projectDir/build |
group | Object | 未具体说明 |
version | Object | 未具体说明 |
ant | AntBuilder | Ant实例对象 |
建议:
不要忘记我们的构建脚本只是个很简单的 Groovy 代码 ,不过它会再调用 Gradle API,Project 接口通过调用 Gradle API 让我们可以操作任何事情,因此如果你想知道哪个标签('tags') 可以在构建脚本种使用,您可以翻阅 Project 接口的的说明文档.
当 Gradle 执行一个脚本时,它会将这个脚本编译为实现了 Script 的类. 也就是说所有的属性和方法都是在 Script 接口中声明的,由于你的脚本实现了 Script 接口,所以你可以在自己的脚本中使用它们.
在 Gradle 构建脚本中有两种类型的变量可以声明:局部变量 ( local ) 和 扩展属性 ( extra ) .
局部变量使用关键字 def 来声明,其只在声明它的地方可见 . 局部变量是 Groovy 语言的一个基本特性.
例子 13.2 . 使用局部变量
def dest = "dest"
task copy(type: Copy) {
form "source"
into dest
}
在 Gradle 领域模型中所有被增强的对象能够拥有自己定义的属性. 这包括,但不仅限于 projects , tasks , 还有 source sets . Project 对象可以添加,读取,更改扩展的属性. 另外,使用 ext 扩展块可以一次添加多个属性.
例子 13.3. 使用扩展属性
build.gradle
apply plugin: "java"
ext {
springVersion = "3.1.0.RELEASE"
emailNotification = "[email protected]"
}
sourceSets.all { ext.purpose = null }
sourceSets {
main {
purpose = "production"
}
test {
purpose = "test"
}
plugin {
purpose = "production"
}
}
task printProperties << {
println springVersion
println emailNotification
sourceSets.matching { it.purpose == "production" }.each { println it.name }
}
使用gradle -q printProperties输出结果
> gradle -q printProperties
3.1.0.RELEASE
[email protected]
main
plugin
在上面的例子中,一个 ext 扩展块向 Project 对象添加了两个扩展属性. 名为 perpose 的属性被添加到每个 source set,然后设置 ext.purpose 等于 null ( null值是被允许的 ). 当这些扩展属性被添加后,它们就像预定义的属性一样可以被读取,更改值.
例子中我们通过一个特殊的语句添加扩展属性,当您试图设置一个预定义属性或者扩展属性,但是属性名拼写错误或者并不存在时,操作就会失败. Project 对象可以在任何地方使用其扩展属性 ,它们比局部变量有更大的作用域. 一个项目的扩展属性对其子项目也可见.
关于扩展属性更多的细节还有它的API,请看 ExtraPropertiesExtension 类的 API 文档说明.
Groovy 提供了大量的特性用来创建 DSL. Gradle 构建语言知道 Groovy 语言的工作原理,并利用这些特性帮助您编写构建脚本,特别是您在编写 plugin 或者 task 的时候,你会觉得很方便.
Groovy 在 Java 基础上添加了很多有用的方法. 例如,Iterable 有一个 each 方法, 通过使用 each 方法,我们可以迭代出 Iterable 中的每一个元素:
例子: 13.4.Groovy JDK 方法
build.gradle
configuration.runtime.each { File f -> println f }
更多内容请阅读 http://groovy.codehaus.org/groovy-jdk/
Groovy 自动将一个属性的引用转换为相应的 getter 或 setter 方法.
例子: 13.5. 属性存取器
// 使用 getter 方法
println project.buildDir
println getProject().getBuildDir()
// 使用 setter 方法
project.buildDir = 'target'
getProject().setBuildDir('target')
在调用方法时,圆括号可有可无,是个可选的.
例子: 13.6.不使用圆括号调用方法
build.gradle
test.systemProperty 'some.prop', 'value'
test.systemProperty('some.prop', 'value')
Groovy 为预定义的 List 和 Map 集合提供了一些操作捷径,这两个字面值都比较简单易懂,但是 Map 会有一些不同.
例如,当您使用 "apply" 方法使用插件时,apply 会自动加上 Map 的一个参数,当您这样写 " apply plugin: 'java' "时,实际上使用的是 name 参数(name-value),只不过在 Groovy 中 使用 Map 没有 < > ,当方法被调用的时候,name 参数就会被转换成 Map 键值对,只不过在 Groovy 中看起来不像一个 Map.
**例子 13.7.List 和 Map 集合
build.gradle
// List 集合
test.includes = ['org/gradle/api/**', 'org/gradle/internal/**']
List<String> list = new ArraryList<String>()
list.add('org/gradle/api/**')
list.add('org/gradle/internal/**')
test.includes = list
// Map 集合
Map<String,String> map = [key1:'value1', key2:'valu2']
// Groovy 会强制将Map的键值对转换为只有value的映射
apply plugin: 'java'
Gradle DSL 在很多地方使用闭包,这里我们将讨论更多关于闭包的使用. 当一个方法的最后一个参数是一个闭包时,您可以在方法调用后放置一个闭包.
例子: 13.8.闭包作为方法的参数
build.gradle
repositories {
println "in a closure"
}
repositories() { println "in a closure" }
repositories({println "in a closure" })
每个闭包都有一个委托对象,当闭包既不是局部变量也不是作为方法参数时,Groovy 使用委托对象查找变量和方法引用. 当委托对象被用来管理时,Gradle 使用它来管理闭包.
例子 13.9.闭包引用
build.gradle
dependencies {
assert delegate == project.dependencies
testCompile('junit:junit:4.11')
delegate.testCompile('junit:junit:4.11')
}