http://blog.csdn.net/maosidiaoxian/article/details/70880742
关于我对Gradle的翻译,以Github上的项目及http://gradledoc.qiniudn.com 上的文档为准。如发现翻译有误的地方,将首先在以上两个地方更新。因时间精力问题,博客中发表的译文基本不会同步修改。
另外,目前Gradle1.12版本的文档已经翻译完并进入校稿阶段,校稿的方式为到该项目https://github.com/msdx/gradledoc 提交issue或是pull request。校稿的结果不只是在此版本更新,也会用于改善Gradle下一版本(2.0)文档的翻译。
Gradle 提供了多种方式来组织你的构建逻辑。首先,你可以把你的构建逻辑直接放到一个任务的action闭包里。如果两个任务有相同的逻辑,你可以把这段逻辑抽取为一个方法。如果一个多项目构建中的多个项目有相同的逻辑,你可以把这个方法定义在父项目里。如果构建逻辑通过方法来正确建模比较复杂的话,你就要使用面向对象的模型了。[25] 这对Gradle来说很简单。只需要把你的类放在一个确定的目录,Gradle会自动地对它们编译,并且把它们加入到你的构建脚本的classpath中。
下面是你可以组织你的构建逻辑的方法摘要:
POGOs。你可以直接在你的构建脚本中定义和使用普通的旧Groovy对象(POGOs)。别忘了构建脚本是用Groovy来写的,Groovy会向你提供许多优秀的方式来组织代码。
继承的属性和方法。在一个多项目构建中,子项目会继承父项目的属性及方法。
配置注入。在一个多项目构建中,一个项目(通常是根项目)可以把属性和方法注入到另一个项目中。
buildSrc
项目。把你的构建的类的源码放到一个指定的目录中,然后Gradle会自动地编译它们,并把它们包含到你的构建脚本的classpath里。
共享脚本。Define common configuration in an external build, and apply the script to multiple projects, possibly across different builds.
自定义任务。把你的构建逻辑放到一个自定义任务中,然后在多个地方复用这个任务。
自定义插件。把你的构建逻辑放到一个自定义插件中,然后在多个项目应用这个插件 。这个插件必须在你的构建脚本的classpath中。你可以通过使用build sources
,或者是添加一个包含了该插件的外部 library,来获得这个插件。
执行一个外部构建。从当前的构建中执行另一个Gradle构建。
外部 libraries。直接在你的构架文件中使用外部libraries。
任何定义在一个项目的构建脚本中的属性和方法,对于它的所有子项目都是可见的。你可以通过这个方法去定义共同的配置,然后把构建逻辑抽取到可以被子项目重用的方法里。
示例59.1. 使用继承的属性和方法
build.gradle
srcDirName = 'src/java' def getSrcDir(project) { return project.file(srcDirName) }
child/build.gradle
task show << { // Use inherited property println 'srcDirName: ' + srcDirName // Use inherited method File srcDir = getSrcDir(project) println 'srcDir: ' + rootProject.relativePath(srcDir) }
gradle -q show
的输出结果
> gradle -q show srcDirName: src/java srcDir: child/src/java
你可以使用在 第56.1节,“跨项目配置”和第56.2节,“子项目配置” 所论述的配置注入技术,来向不同的项目注入属性和方法。通常来说,它是比继承更好的选择,有好几个原因:注入是显示地存在于构建脚本中的,你可以向不同的项目注入不同的逻辑,并且你可以注入任意一种配置,例如仓库,插件,任务等等。下面是展示注入的例子。
示例59.2. 使用注入的属性和方法
build.gradle
subprojects { // Inject a property and method srcDirName = 'src/java' srcDir = { file(srcDirName) } // Inject a task task show << { println 'project: ' + project.path println 'srcDirName: ' + srcDirName File srcDir = srcDir() println 'srcDir: ' + rootProject.relativePath(srcDir) } } // Inject special case configuration into a particular project project(':child2') { srcDirName = "$srcDirName/legacy" }
child1/build.gradle
// Use injected property and method. Here, we override the injected value srcDirName = 'java' def dir = srcDir()
gradle -q show
的输出结果
> gradle -q show project: :child1 srcDirName: java srcDir: child1/java project: :child2 srcDirName: src/java/legacy srcDir: child2/src/java/legacy
buildSrc
项目中的构建源代码当你运行Gradle时,它会检查buildSrc
目录是否存在。然后Gradle会自动的编译和测试它的代码,并且把它们加入到你的构建脚本的classpath中。你不需要再提供任何进一步的指示。这可以是用于添加你的自定义任务和插件的好地方。
对于多项目构建,它们可能只有一个buildSrc
目录,在根项目的目录中。
下面列出的是Gradle应用到 buildSrc
项目的默认构建脚本。
图 59.1. 默认的buildSrc构建脚本
apply plugin: 'groovy' dependencies { compile gradleApi() compile localGroovy() }
这意味着你可以只把你的构建源代码放到这个目录当中,并且保留一个 Java/Groovy 项目的约定布局(见表 23.4,“Java 插件 - 默认项目布局”)。
如果你需要更多的灵活性,你可以提供你自己的build.gradle
。Gradle配置了一个默认的构建脚本,无论是否有脚本被指定。这意味着,你只需声明你所需要的额外的东西。下面是一个例子。请注意,此示例不需要声明对 Gradle API的依赖,因为这由默认的构建脚本完成:
示例 59.3. 自定义buildSrc构建脚本
buildSrc/build.gradle
repositories {
mavenCentral()
}
dependencies {
testCompile 'junit:junit:4.11'
}
The buildSrc
project can be a multi-project build. 这就像其他常规的Gradle多项目构建。但是,你需要使你想要的所有项目在buildSrc
的根项目的实际构建runtime
依赖的classpath上。 你可以通过把它添加到每一个你想导出的项目的配置上来完成:
示例 59.4. 将子项目添加到根 buildSrc 项目
buildSrc/build.gradle
rootProject.dependencies { runtime project(path) }
注意: 此例子的代码可以在Gradle的二进制文件或源码中的 samples/multiProjectBuildSrc
里看到。
你可以使用GradleBuild
任务。你可以通过使用 dir
或 buildFile
属性来指定执行哪一个构建,以及使用 tasks
属性来指定执行哪一个任务。
示例 59.5. 从一个构建运行另一个构建
build.gradle
task build(type: GradleBuild) { buildFile = 'other.gradle' tasks = ['hello'] }
other.gradle
task hello << {
println "hello from the other build."
}
gradle -q build
的输出结果
> gradle -q build hello from the other build.
如果你的构建脚本需要使用一些外部库,你可以在这个构建脚本的把它们添加到该脚本的classpath中。你可以通过使用buildscript()
方法,传入一个定义构建脚本classpath的闭包。
示例 59.6. 声明构建脚本的外部依赖
build.gradle
buildscript { repositories { mavenCentral() } dependencies { classpath group: 'commons-codec', name: 'commons-codec', version: '1.2' } }
这个传给buildscript()
方法的闭包配置了一个ScriptHandler
实例。你可以通过添加依赖到classpath
配置来定义构建脚本的classpath。这和你定义Java编译classpath是同样的。你可以使用在 第50.4节,“如何定义你的依赖”描述的除了项目依赖之外的任何依赖类型。
声明了构建脚本的classpath之后,你可以使用构建脚本中的类,就像classpath上的任何其他类一样。下面的示例将添加到前面的示例中,并使用构建脚本classpath中的类。
示例 59.7. 具有外部依赖的构建脚本
build.gradle
import org.apache.commons.codec.binary.Base64 buildscript { repositories { mavenCentral() } dependencies { classpath group: 'commons-codec', name: 'commons-codec', version: '1.2' } } task encode << { def byte[] encodedString = new Base64().encode('hello world\n'.getBytes()) println new String(encodedString) }
gradle -q encode
的输出结果
> gradle -q encode aGVsbG8gd29ybGQK
对于多项目构建,定义在一个项目的构建脚本中的依赖,是可以在所有子项目的构建脚本中用的。
For reasons we don't fully understand yet, external dependencies are not picked up by Ant's optional tasks. 但是你可以很容易地通过另一种方法做到。[26]
示例 59.8. Ant 的可选依赖
build.gradle
configurations { ftpAntTask } dependencies { ftpAntTask("org.apache.ant:ant-commons-net:1.9.3") { module("commons-net:commons-net:1.4.1") { dependencies "oro:oro:2.0.8:jar" } } } task ftp << { ant { taskdef(name: 'ftp', classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP', classpath: configurations.ftpAntTask.asPath) ftp(server: "ftp.apache.org", userid: "anonymous", password: "[email protected]") { fileset(dir: "htdocs/manual") } } }
这对于客户端模块的用法也是一个很好的例子。在这个用例中,针对 ant-commons-net 任务的Maven中央仓的POM没有提供正确的信息。
Gradle 提供了多种组织你的构建逻辑的方式。你可以选择最适合你的领域的方式,并在不必要的间界引用之间找到平衡,避免冗余和难以维护的代码库。It is our experience that even very complex custom build logic is rarely shared between different builds. Other build tools enforce a separation of this build logic into a separate project. Gradle为你节省了这些不必要的开销和间接引用。
[25] 这范围可能是从一个类到一些非常复杂的东西。
[26] 事实上,我们认为这是更好的解决方案。仅当你的构建脚本和Ant的可选任务需要相同的 library时,你才需要定义它两次。在这种情况下,如果Ant 的可选任务会自动地获取在 gradesettings
中定义的classpath,就很好。