这一章我们来看一些基本的构建脚本是如何写的
13.1 Gradle构建语言
Gradle提供了一个动态构建语言或者成为DSL,来描述一个构建过程。这个构建语言是基于Groovy,然后添加了一些东西来使它更容易来描述一个构建。
一个构建脚本可以包含任何的Groovy语言元素。Gradle假设任何构建脚本是以utf8编码的。
13.2 工程API
在第七章中快速开始Java中我们使用了一个叫apply的方法,这个方法是来自那里呢?我们前面说过,在Gradle中,构建脚本定义了一个工程。在这个构建脚本中的每个工程,Gradle创建一个类型为Project的对象并把这个Project对象关联到构建脚本上。当构建脚本执行的时候,它会配置Project对象。
a、任何在你构建脚本中调用但没有定义的方法会代理给这个Project对象
b、任何在你工程中访问但是没有定义的属性也会代理给这个Project对象。
让我们来测试一下并且访问Project对象的name属性:
Example 13.1. Accessing property of the Project object
build.gradle
println name
println project.name
Output of gradle -q check
> gradle -q check
projectApi
projectApi
两个println语句都会打印同一个属性。第一个使用了自动代理到Project对象,因为构建脚本中没有定义这个属性。第二个使用project属性,这个属性对每个构建脚本都是可以使用的,它放回与Project对象相关联的属性。只有当你自己定义了一个属性和方法,他的名字和Project对象中方法的名字是一样,这时候你要使用project的属性才需要使用第二种方法。
13.2标准的project属性
project对象提供了一些标准的属性,这些属性在你的构建脚本中都是可以使用的。下面这张表列举了一些常用的属性:
Table 13.1. Project Properties
13.3 脚本的API接口
当Gradle执行一个脚本的时候,它把脚本编译成一个实现了Scrip接口的类。这也意味着所有在Script接口中定义的方法和属性在你的脚本中都是可以访问的。
13.4 定义变量
在一个构建脚本中可以定义两种类型的变量:局部变量和外部属性
13.4.1 局部变量
局部变量是通过关键字key来定义的。它们只在他们定义的范围内有效。局部变量是Groovy语言的一个特性。
Example 13.2. Using local variables
build.gradle
def dest = "dest"
task copy(type: Copy) {
from "source"
into dest
}
13.4.2 外部属性
在Gradle域模型中的所有增强对象都可以额外的用户自定义属性。这包括那不只限于projects,tasks,以及source sets.额外的属性可以被添加,读取并且通过拥有这个额外属性的对象去设置。最终,一个ext代码块可以用来一次添加多个属性。
Example 13.3. Using extra properties
build.gradle
apply plugin: "java"
ext {
springVersion = "3.1.0.RELEASE"
emailNotification = "build@master.org"
}
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 }
}
Output of gradle -q printProperties
> gradle -q printProperties
3.1.0.RELEASE
build@master.org
main
plugin
在这个例子中,在ext代码块中添加了两个外部的属性到工程中,另外,一个名叫prupose的属性通过设置ext.purpose为null添加到每个源码目录。一旦一个属性被添加,他们可以像其他预先定义的属性一样被读取和设置。
通过使用特殊的语法来添加一个属性,当Gradle尝试去设置一个先前定义或外部的属性,但是这个属性找不到或者不存在的时候,Gradle将会快速的失败。外部属性可以在拥有他的对象可访问的任何地方访问,他们拥有比局部属性更宽的作用域。外部属性在一个工程的子工程中都是可见的。
关于外部属性的详细信息以及他们相关的Api,查看Api文档中的 ExtraPropertiesExtension类
13.5 配置任意对象
你可以通过下面非常可读的方式配置任何对象。
Example 13.4. Configuring arbitrary objects
build.gradle
task configure << {
def pos = configure(new java.text.FieldPosition(10)) {
beginIndex = 1
endIndex = 5
}
println pos.beginIndex
println pos.endIndex
}
Output of gradle -q configure
> gradle -q configure
1
5
13.6 使用外部脚本配置任意对象
你也可以使用一个外部的脚本来配置任意的对象
You can also configure arbitrary objects using an external script.
Example 13.5. Configuring arbitrary objects using a script
build.gradle
task configure << {
def pos = new java.text.FieldPosition(10)
// Apply the script
apply from: 'other.gradle', to: pos
println pos.beginIndex
println pos.endIndex
}
other.gradle
// Set properties.
beginIndex = 1
endIndex = 5
Output of gradle -q configure
> gradle -q configure
1
5
13.7 一些Groovy的基础知识
Groovy提供了许多的特性来创建DSL,Gradle构建语言充分利用了这些特性。理解这些购机价语言是怎么工作对我们自己写构建脚本,特别是当你开始写自定义的插件及任务时是非常有帮助的。
13.7.1 Groovy JDK
Groovy添加了许多的方法到标准的Java类中,例如Iterale提供了一个each的方法iterates是Iterable的一个元素:
Example 13.6. Groovy JDK methods
build.gradle
// Iterable gets an each() method
configurations.runtime.each { File f -> println f }
Have a look at http://groovy.codehaus.org/groovy-jdk/ for more details.
13.7.2 属性访问器
Groovy会自动的将对属性的应用转换为调用相应的合适的getter或setter方法。
Example 13.7. Property accessors
build.gradle
// Using a getter method
println project.buildDir
println getProject().getBuildDir()
// Using a setter method
project.buildDir = 'target'
getProject().setBuildDir('target')
13.7.3 可选的括符操作
括号操作对方法调用是可选的
Example 13.8. Method call without parentheses
build.gradle
test.systemProperty 'some.prop', 'value'
test.systemProperty('some.prop', 'value')
13.7.4 . List 和 map 文字
Groovy提供了一些简写来定义list和Map实例,两者字面意思都是非常直接了断的,但是map拥有一些非常有趣的东西。
例如,apply方法(典型情况下一般用来应用插件)一般携带一个map参数。但是,但是看到一行类似"apply plugin:'java'"时,你时间没有使用map,你使用的是“named parameters”,它跟map的语法非常像,除了没有被括号包含。这个named参数列表会转为map当他被调用的时候,但是开始的时候不是map
Example 13.9. List and map literals
build.gradle
// List literal
test.includes = ['org/gradle/api/**', 'org/gradle/internal/**']
List<String> list = new ArrayList<String>()
list.add('org/gradle/api/**')
list.add('org/gradle/internal/**')
test.includes = list
// Map literal.
Map<String, String> map = [key1:'value1', key2: 'value2']
// Groovy will coerce named arguments
// into a single map argument
apply plugin: 'java'
13.7.5闭包作为方法的最后一个参数
Gradle DSL在很多地方都使用了闭包,你可以在这里找到更多关于闭包相关的只是,如果一个方法的最好一参数是一个闭包,你可以把这个闭包放在方法调用的后面。
Example 13.10. Closure as method parameter
build.gradle
repositories {
println "in a closure"
}
repositories() { println "in a closure" }
repositories({ println "in a closure" })
13.7.6 闭包委派
每个闭包都有一个代理对象,Groovy使用这个代理对象来查找变量或方法的引用,这些不是闭包的局部变量或参数。Gradle对此使用configuration闭包,代理对象被设置为被配置的对象。
Example 13.11. Closure delegates
build.gradle
dependencies {
assert delegate == project.dependencies
testCompile('junit:junit:4.12')
delegate.testCompile('junit:junit:4.12')
}