复制文件

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

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

例 15.10. 使用复制任务复制文件

build.gradle

  1. task copyTask(type: Copy) {
  2. from 'src/main/webapp'
  3. into 'build/explodedWar'
  4. }

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

例 15.11 指定复制任务的源文件和目标目录

build.gradle

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

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

例 15.12 选择要复制文件

build.gradle

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

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

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

build.gradle

  1. task copyMethod << {
  2. copy {
  3. from 'src/main/webapp'
  4. into 'build/explodedWar'
  5. include '**/*.html'
  6. include '**/*.jsp'
  7. }
  8. }

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

build.gradle

  1. task copyMethodWithExplicitDependencies{
  2. // 对输入做最新检查,添加 copyTask 作为依赖
  3. inputs.file copyTask
  4. outputs.dir 'some-dir' //对输出做最新检查
  5. doLast{
  6. copy {
  7. // 复制 copyTask 的输出
  8. from copyTask
  9. into 'some-dir'
  10. }
  11. }
  12. }

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

15.6.1 重命名文件

例 15.15 在复制时重命名文件

build.gradle

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

15.6.2 过滤文件

例 15.16 在复制时过滤文件

build.gradle

  1. import org.apache.tools.ant.filters.FixCrLfFilter
  2. import org.apache.tools.ant.filters.ReplaceTokens
  3. task filter(type: Copy) {
  4. from 'src/main/webapp'
  5. into 'build/explodedWar'
  6. // 在文件中替代属性标记
  7. expand(copyright: '2009', version: '2.3.1')
  8. expand(project.properties)
  9. // 使用 Ant 提供的过滤器
  10. filter(FixCrLfFilter)
  11. filter(ReplaceTokens, tokens: [copyright: '2009', version: '2.3.1'])
  12. // 用一个闭合来过滤每一行
  13. filter { String line ->
  14. "[$line]"
  15. }
  16. // 使用闭合来删除行
  17. filter { String line ->
  18. line.startsWith('-') ? null : line
  19. }
  20. }

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

15.6.3 使用 CopySpec 类

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

例 15.17. 嵌套复制规范

build.gradle

  1. task nestedSpecs(type: Copy) {
  2. into 'build/explodedWar'
  3. exclude '**/*staging*'
  4. from('src/dist') {
  5. include '**/*.html'
  6. }
  7. into('libs') {
  8. from configurations.runtime
  9. }
  10. }