GradleUserGuide中文版 15)文件操作 16)Ant插件

来源:互联网 发布:java包下载 编辑:程序博客网 时间:2024/05/18 17:44

15.4 使用一个归档文件的内容作为文件树

可以使用 ZIP 或者 TAR 等压缩文件的内容作为文件树, Project.zipTree()Project.tarTree() 方法返回一个 FileTree 实例, 可以像使用其他文件树或者文件集合一样使用它.
e.g. 可以使用它去扩展一个压缩文档或者合并一些压缩文档.

15.7 使用压缩文档作为文件树
build.gradle

// 使用路径创建一个 ZIP 文件FileTree zip = zipTree('someFile.zip')// 使用路径创建一个 TAR 文件FileTree tar = tarTree('someFile.tar')//tar tree 能够根据文件扩展名得到压缩方式, 如果你想明确的指定压缩方式, 可以使用下面方法FileTree someTar = tarTree(resources.gzip('someTar.ext'))

15.5 指定一组输入文件

在 Gradle 中有一些对象的某些属性可以接收一组输入文件. e.g. ,JavaComplile 任务有一个 source 属性, 它定义了编译的源文件, 可以设置这个属性的值, 只要 files() 方法支持.
这意味着可以使用 File , String , collection , FileCollection 甚至是使用一个闭包去设置属性的值.

15.8 指定文件
build.gradle

//使用一个 File 对象设置源目录compile {    source = file('src/main/java')}//使用一个字符路径设置源目录compile {    source = 'src/main/java'}// 使用一个集合设置多个源目录compile {    source = ['src/main/java', '../shared/java']}// 使用 FileCollection 或者 FileTree 设置源目录compile {    source = fileTree(dir: 'src/main/java').matching { include 'org/gradle/api/**' }}// 使用一个闭包设置源目录compile {    source = {        // Use the contents of each zip file in the src dir        file('src').listFiles().findAll {it.name.endsWith('.zip')}.collect { zipTree(it) }    }}

通常情况下, 会有一个方法名和属性名相同的方法能够附加到这一组文件, 这个方法接收 files() 方法支持的任何类型的值.

15.9 指定文件
build.gradle

compile {    // 使用字符路径添加源目录    source 'src/main/java', 'src/main/groovy'    // 使用 File 对象添加源目录    source file('../shared/java')    // 使用闭包添加源目录    source { file('src/test/').listFiles() }}

15.6 复制文件

可以使用复制任务( Copy )去复制文件. 复制任务扩展性很强, 能够过滤复制文件的内容, 映射文件名.

使用复制任务时需要提供想要复制的源文件和一个目标目录, 如果要指定文件被复制时的转换方式,可以使用 复制规则. 复制规则被 CopySpec 接口抽象, 复制任务实现了这个接口. 使用 CopySpec.from() 方法指定源文件.使用 CopySpec.into() 方法指定目标目录.

15.10. 使用复制任务复制文件
build.gradle

task copyTask(type: Copy) {    from 'src/main/webapp'    into 'build/explodedWar'}

from() 方法接收任何 files() 方法支持的参数.
当参数被解析为一个目录时, 在这个目录下的任何文件都会被递归地复制到目标目录(但不是目录本身).
当一个参数解析为一个文件时, 该文件被复制到目标目录中.
当参数被解析为一个不存在的文件时, 这个参数就会忽略.
如果这个参数是一个任务, 任务的输出文件(这个任务创建的文件)会被复制, 然后这个任务会被自动添加为复制任务的依赖.

15.11 指定复制任务的源文件和目标目录
build.gradle

task anotherCopyTask(type: Copy) {    // 复制 src/main/webapp 目录下的所有文件    from 'src/main/webapp'    // 复制一个单独文件    from 'src/staging/index.html'    // 复制一个任务输出的文件    from copyTask    // 显式使用任务的 outputs 属性复制任务的输出文件    from copyTaskWithPatterns.outputs    // 复制一个 ZIP 压缩文件的内容    from zipTree('src/main/assets.zip')    // 最后指定目标目录    into { getDestDir() }}

可以使用Ant-style 规则或者一个闭包选择要复制的文件.

15.12 选择要复制文件
build.gradle

task copyTaskWithPatterns(type: Copy) {    from 'src/main/webapp'    into 'build/explodedWar'    include '**/*.html'    include '**/*.jsp'    exclude { details -> details.file.name.endsWith('.html') &&                         details.file.text.contains('staging') }}

也可以使用 Project.copy() 方法复制文件,它的工作方式有一些限制,
首先, 该方法不是增量的, 请参考 第 14.9节 跳过 up-to-date 的任务.
其次, 当一个任务被用作复制源时(例如 from() 方法的参数), copy() 方法不能够实现任务依赖, 因为它是一个普通的方法不是一个任务. 因此,如果使用 copy()方法作为一个任务的一部分功能, 需要显式的声明所有的输入和输出以确保获得正确的结果.

15.13 不使用最新检查方式下用 copy() 方法复制文件
build.gradle

task copyMethod << {    copy {        from 'src/main/webapp'        into 'build/explodedWar'        include '**/*.html'        include '**/*.jsp'    }}

15.14 使用最新的检查方式下用 copy() 方法复制文件
build.gradle

task copyMethodWithExplicitDependencies{     // 对输入做最新检查,添加 copyTask 作为依赖    inputs.file copyTask    outputs.dir 'some-dir' //对输出做最新检查    doLast{        copy {            // 复制 copyTask 的输出            from copyTask            into 'some-dir'        }    }}

建议尽可能的使用复制任务,因为它支持增量化的构建和任务依赖推理, 而不需要去额外的费力处理这些.
不过 copy() 方法可以用作复制任务实现的一部分. 即该 方法被在自定义复制任务中使用, 请参考 第60章 编写自定义任务. 在这样的场景下,自定义任务应该充分声明与复制操作相关的输入/输出。

15.6.1 重命名文件

15.15 在复制时重命名文件
build.gradle

task rename(type: Copy) {    from 'src/main/webapp'    into 'build/explodedWar'    // 使用一个闭包映射文件名    rename { String fileName ->        fileName.replace('-staging-', '')    }    // 使用正则表达式映射文件名    rename '(.+)-staging-(.+)', '$1$2'    rename(/(.+)-staging-(.+)/, '$1$2')}

15.6.2 过滤文件

15.16 在复制时过滤文件
build.gradle

import org.apache.tools.ant.filters.FixCrLfFilterimport org.apache.tools.ant.filters.ReplaceTokenstask filter(type: Copy) {    from 'src/main/webapp'    into 'build/explodedWar'    // 在文件中替代属性标记    expand(copyright: '2009', version: '2.3.1')    expand(project.properties)    // 使用 Ant 提供的过滤器    filter(FixCrLfFilter)    filter(ReplaceTokens, tokens: [copyright: '2009', version: '2.3.1'])    // 用一个闭包来过滤每一行    filter { String line ->        "[$line]"    }    // 使用闭包来删除行    filter { String line ->        line.startsWith('-') ? null : line    }}

在源文件中扩展和过滤操作都会查找的某个标志 token,如果它的名字是 tokenName , 它的格式应该类似于 @tokenName@.

15.6.3 使用 CopySpec 类

复制规范来自于层次结构,一个复制规范继承其目标路径,包括模式,排除模式,复制操作,名称映射和过滤器.
15.17. 嵌套复制规范
build.gradle

task nestedSpecs(type: Copy) {    into 'build/explodedWar'    exclude '**/*staging*'    from('src/dist') {        include '**/*.html'    }    into('libs') {        from configurations.runtime    }}

15.7 使用同步任务

同步任务 ( Sync ) 任务继承自复制任务 ( Copy ) , 当它执行时,它会复制源文件到目标目录中, 然后从目标目录中的删除所有非复制的文件, 这种方式非常有用, 比如安装一个应用, 创建一个文档的副本, 或者维护项目的依赖关系副本.

e.g. 维护 build/libs 目录下项目在运行时的依赖
15.7 使用 Sync 任务复制依赖关系
build.gradle

task libs(type: Sync) {    from configurations.runtime    into "$buildDir/libs"}

15.8 创建归档文件

一个项目可以有很多 JAR 文件, 可以向项目中添加 WAR , ZIP 和 TAR 文档,使用归档任务可以创建这些文档: Zip , Tar , Jar , War 和Ear. 它门都以同样的机制工作.

15.19 创建一个 ZIP 文档
build.gradle

apply plugin: 'java'task zip(type: Zip) {    from 'src/dist'    into('libs') {        from configurations.runtime    }}

所有的归档任务的工作机制和复制任务相同, 它们都实现了 CopySpec 接口, 和 Copy 任务一样,使用 from() 方法指定输入文件, 可以选择性的使用 into() 方法指定什么时候结束. 还可以过滤文件内容, 重命名文件等等, 就如同使用复制规则一样.

重命名文档
projectName-vsersion.type 格式可以被用来生成文档名,
例 15.20 创建压缩文档
build.gradle

apply plugin: 'java'version = 1.0task myZip(type: Zip) {    from 'somedir'}println myZip.archiveNameprintln relativePath(myZip.destinationDir)println relativePath(myZip.archivePath)

输出:

> gradle -q myZipzipProject-1.0.zipbuild/distributionsbuild/distributions/zipProject-1.0.zip

上面例子使用一个名为 myZip的 Zip 归档任务生成名称为 zipProject-1.0.zip 的 ZIP 文档, 区分文档任务名和最终生成的文档名非常的重要;

可以通过设置项目属性 archivesBaseName 的值来修改生成文档的默认名. 当然, 文档的名称也可以通过其他方法随时更改.

归档任务中有些属性可以配置
t15.1 归档任务-属性名

属性名 类型 默认值 描述 archiveName String baseName-appendix-version-classifier.extension,
如果其中任何一个都是空的,则不添加名称 归档文件的基本文件名 archivePath File destinationDir/archiveName 生成归档文件的绝对路径 destinationDir File 取决于文档类型, JAR 和 WAR 使用project.buildDir/distributions.
project.buildDir/libraries.ZIP 和 TAR 归档文件的目录 baseName String project.name 归档文件名的基础部分 appendix String null 归档文件名的附加部分 version String project.version 归档文件名的版本部分 classifier String null 归档文件名的分类部分 extension String 取决于文档类型和压缩类型: zip, jar, war, tar, tgz 或者 tbz2 归档文件的扩展名

15.21 配置归档文件-自定义文档名
build.gradle

apply plugin: 'java'version = 1.0task myZip(type: Zip) {    from 'somedir'    baseName = 'customName'}println myZip.archiveName

输出:

> gradle -q myZipcustomName-1.0.zip

更多配置:
15.22 配置归档任务- 附加其他后缀
build.gradle

apply plugin: 'java'archivesBaseName = 'gradle'version = 1.0task myZip(type: Zip) {    appendix = 'wrapper'    classifier = 'src'    from 'somedir'}println myZip.archiveName

输出:

> gradle -q myZipgradle-wrapper-1.0-src.zip

多个文档共享内容
可以使用 Project.copySpec() 在不用归档文件间共享内容. 如果想发布一个文档, 然后在另一个项目中使用,这部分将在第 53 章 发布文档 中讲述

16 使用 Ant插件

Gradle 出色地集成了 Ant. 可以在 Gradle 构建时使用单独的 Ant 任务或完整的 Ant 构建.
事实上, 你会发现在 Gradle 构建脚本中使用Ant任务远比直接使用 Ant 的 XML 格式更加容易和强大. 甚至可以将 Gradle 仅仅作为一个强大的 Ant 脚本工具.

Ant 可以分为两层.
第一层是 Ant 语言. 它给 build.xml 文件, 处理目标, 像 macrodefs 的特殊构造等提供语法支持. 换句话说, 除了 Ant 任务和类型, 其余一切都支持.
Gradle 了解这种语言, 并允许用户直接导入 Ant 的 build.xml 到 Gradle 的项目下. 然后, 可以 像 Gradle 任务一样直接使用这些 Ant 构建.

第二层是 Ant 丰富的任务和类型, 如 javac, copy 或 jar. Gradle 提供了基于 Groovy 的集成以及梦幻般的 AntBuilder.

最后, 由于构建脚本是 Groovy 脚本, 可以执行一个 Ant 构建作为一个外部进程. 构建脚本可能会含有类似的语句:ant clean compile”.execute().

你可以使用 Gradle 的 Ant 集成,作为迁移路径将构建 Ant 迁移到 Gradle.
e.g. 可以从通过导入现有的 Ant 构建开始, 然后将你的依赖声明从 Ant 脚本迁移到 build 文件. 最后, 可以将任务迁移到你的构建文件, 或者用一些 Gradle 插件代替他们. 随着时间的推移, 这部分工作会一步一步地完成, 并且你可以在整个进程中有一个运行良好的 Gradle 构建.

16.1 使用 Ant 任务和 Ant 类型的构建

在构建脚本中, Ant 属性是由 Gradle提供的. 这是一个用于参考的 AntBuilder 实例. AntBuilder 用于从构建脚本访问 Ant 任务, 类型和属性. 下面的例子解释了从 Ant 的 build.xml 格式到 Grooy 的映射.

可以通过调用 AntBuilder 实例的方法执行 Ant 任务. 可以使用任务名称作为方法名, e.g. 可以通过调用 anto.echo() 任务执行 Ant echo 任务. Ant 任务属性通过 Map 参数传递给方法.
下面是一个 echo 任务的例子, 注意我们也可以混合使用 Groovy 代码和 Ant 任务标记, 这点个功能非常强大.
16.1.使用 Ant 任务
build.gradle

task hello << {    String greeting = 'hello from Ant'    ant.echo(message: greeting)}

输出

> gradle hello
:hello
[ant:echo] hello from Ant
BUILD SUCCESSFUL
Total time: 1 secs

可以添加嵌套元素添加到一个封闭的 Ant 任务的内部. 定义嵌套元素跟定义任务的方式相同, 通过与调用我们要定义的元素名相同的方法.

16.3.添加嵌套元素到一个Ant任务
build.gradle

task zip << {    ant.zip(destfile: 'archive.zip') {        fileset(dir: 'src') {            include(name: '**.xml')            exclude(name: '**.java')        }    }}

可以像访问任务一样访问 Ant type,只需要将 type 名作为方法名即可. 该方法调用返回的 Ant 数据类型,可以直接在构建脚本中使用.
下面的例子中, 创建了一个ant path对象,然后遍历内容.
16.4.使用 Ant 类型
build.gradle

task list << {    def path = ant.path {        fileset(dir: 'libs', includes: '*.jar')    }    path.list().each {        println it    }}

更多关于 AntBuilder 的信息可以参考 ‘Groovy in Action’8.4 或者Groovy Wiki.

16.1.1 在构建中使用自定义Ant任务

为了让构建可以自定义任务, 可以使用 taskdef(通常更容易) 或者 typedef Ant 任务, 就像你在一个build.xml文件中一样. 然后,可以参考内置 Ant 任务去定制 Ant 任务.
16.5.使用自定义 Ant 任务
build.gradle

task check << {    ant.taskdef(resource: 'checkstyletask.properties') {        classpath {            fileset(dir: 'libs', includes: '*.jar')        }    }    ant.checkstyle(config: 'checkstyle.xml') {        fileset(dir: 'src')    }}

可以使用 Gradle 的依赖管理去组装你自定义任务所需要的 classpath. 要做到这一点, 你需要定义一个自定义配置类路径, 然后添加一些依赖配置.在Section 51.4, “How to declare your dependencies部分有更详细的说明.

16.6.声明类路径的自定义 Ant 任务
build.gradle

configurations {    pmd}dependencies {    pmd group: 'pmd', name: 'pmd', version: '4.2.5'}

要使用 classpath 配置, 使用自定义配置的asPath属性。
16.7.一起使用自定义Ant任务和依赖管理
build.gradle

task check << {    ant.taskdef(name: 'pmd',                classname: 'net.sourceforge.pmd.ant.PMDTask',                classpath: configurations.pmd.asPath)    ant.pmd(shortFilenames: 'true',            failonruleviolation: 'true',            rulesetfiles: file('pmd-rules.xml').toURI().toString()) {        formatter(type: 'text', toConsole: 'true')        fileset(dir: 'src')    }}

16.2 导入一个Ant构建

可以在你的gradle项目中通过 ant.importBuild()来导入一个ant构建, 当你导入了一个ant构建, 每一个ant target都会被视为一个Gradle任务. 这意味着可以像操作, 执行gradle任务一样操作, 执行ant target
16.8.导入ant构建
build.gradle

ant.importBuild 'build.xml'

build.xml

<project>    <target name="hello">        <echo>Hello, from Ant</echo>    </target></project>

输出

> gradle hello
:hello
[ant:echo] Hello, from Ant

BUILD SUCCESSFUL

Total time: 1 secs

可以添加一个依赖于ant target的任务:
16.9.依赖于ant target的任务
build.gradle

ant.importBuild 'build.xml'task intro(dependsOn: hello) << {    println 'Hello, from Gradle'}

输出

gradle intro :hello [ant:echo] Hello, from Ant :intro Hello, from Gradle
BUILD SUCCESSFUL
Total time: 1 secs

或者, 可以为ant target添加动作
16.10.为Ant target添加动作
build.gradle

ant.importBuild 'build.xml'hello << {    println 'Hello, from Gradle'}

输出

gradle hello :hello [ant:echo] Hello, from Ant Hello, from Gradle
BUILD SUCCESSFUL
Total time: 1 secs

当然, 一个ant target也可以依赖于gradle的任务
例 16.11.为Ant target添加动作
build.gradle

ant.importBuild 'build.xml'task intro << {    println 'Hello, from Gradle'}

build.xml

<project>    <target name="hello" depends="intro">        <echo>Hello, from Ant</echo>    </target></project>

输出

gradle hello :intro Hello, from Gradle :hello [ant:echo] Hello, from Ant
BUILD SUCCESSFUL
Total time: 1 secs

有时候可能需要’重命名ant target以避免与现有的gradle任务冲突. 需要使用AntBuilder.importBuilder()方法.

16.12.重命名导入的ant target
build.gradle

ant.importBuild('build.xml') { antTargetName ->    'a-' + antTargetName}

build.xml

<project>    <target name="hello">        <echo>Hello, from Ant</echo>    </target></project>

输出

gradle a-hello :a-hello [ant:echo] Hello, from Ant
BUILD SUCCESSFUL
Total time: 1 secs

注意, 方法的二个参数应该是一个TransFormer, 在Groovy编程的时候,由于Groovy的支持自动闭包单抽象方法的类型。可以简单地使用闭包取代匿名内部类,
—TBC—
—YCR—

0 0