Gradle 1.12用户指南翻译——第五十九章. 组织构建逻辑

其他章节的翻译请参见:
http://blog.csdn.net/column/details/gradle-translation.html
翻译项目请关注Github上的地址:
https://github.com/msdx/gradledoc
本文翻译所在分支:
https://github.com/msdx/gradledoc/tree/1.12。
直接浏览双语版的文档请访问:
http://gradledoc.qiniudn.com/1.12/userguide/userguide.html。
另外,Android 手机用户可通过我写的一个程序浏览文档,带缓存功能的,目前0.6开发中版本兼容 Android 2.3以上系统,项目地址如下:
https://github.com/msdx/gradle-doc-apk
翻译不易,转载请注明本文在CSDN博客上的出处:

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. 继承的属性和方法

任何定义在一个项目的构建脚本中的属性和方法,对于它的所有子项目都是可见的。你可以通过这个方法去定义共同的配置,然后把构建逻辑抽取到可以被子项目重用的方法里。

示例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

59.2. 注入配置

你可以使用在 第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

59.3. 在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 里看到。

59.4. 从一个构建中运行另一个Gradle构建

你可以使用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.

59.5. 构建脚本的外部依赖

如果你的构建脚本需要使用一些外部库,你可以在这个构建脚本的把它们添加到该脚本的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

对于多项目构建,定义在一个项目的构建脚本中的依赖,是可以在所有子项目的构建脚本中用的。

59.6. Ant 可选依赖

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没有提供正确的信息。

59.7. 总结

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,就很好。


你可能感兴趣的:(Gradle 1.12用户指南翻译——第五十九章. 组织构建逻辑)