Gradle Copy タスクのまとめ

f:id:Naotsugu:20150224234525p:plain

Copy タスク

Copy タスクは Gradle の core で提供されている。

簡単な Copy タスク例は以下。

task copyConfig(type: Copy) {
    from 'config'
    into 'build/config'
}

gradle copyConfig でタスクを実行すると 'config' ディレクトリにあるファイルを'build/config'ディレクトリにコピーする。

exclude

コピー対象のフィルタリングは Ant 形式の glob パターンで指定できる。

ファイル名に Test という文字が入ったものを除外するには以下のように指定する。

task copyConfig(type: Copy) {
    from 'config'
    into 'build/config'
    exclude '**/*Test*'
}

** とすることで対象ディレクトリに対して再帰的にルールが適用される。

include

Dev という文字が入ったテキストファイルだけをコピーしたい場合は以下のように指定する。

task copyConfig(type: Copy) {
    from 'configdir'
    into 'build/configdir'
    include '**/*Dev*.txt'
}

複数指定する場合には include('**/*.txt', '**/*.xml', '**/*.properties') のように指定することができる。        

以下のようにクロージャで複雑な除外設定を表現することもできる。

exclude { details -> details.file.name.endsWith('.html') &&
                         details.file.text.contains('staging') }

includeEmptyDirs で空ディレクトリを除外

includeEmptyDirs で空ディレクトリをコピー対象外に設定できる。

task copyConfig(type: Copy) {
    from 'configdir'
    into 'build/configdir'
    includeEmptyDirs = false
}

デフォルトはtrue で空ディレクトリもコピーされる

複数箇所からのコピー

複数のディレクトリからコピーする例。

task complexCopy(type: Copy) {
    from ('src/main/templates') {
        include '**/*.gtpl'
    }
    from('i18n')
    from('config') {
        exclude 'Development*.groovy'
    }
    into 'build/resources'
}

対象のディレクトリを from で並べれば良い。  

複数ディレクトリからのコピーでファイルが重複していた場合の動作は duplicatesStrategy でストラテジを定義する。

task complexCopy(type: Copy) {
    from 'dir1'
    from 'dir2'
    duplicatesStrategy 'exclude'
}

include がデフォルトで、後からコピーされたもので上書きされる。指定することで、重複が発生した場合には警告が出力されるようになる。

excludeでは重複したファイルは無視されます。最初にコピーされたファイルが最終的に使われる。

rename リネームコピー

正規表現でファイル名のリネームができる。

task rename(type: Copy) {
    from 'source'
    into 'dest'
    rename(/file-template-(¥d+)/, 'production-file-$1.txt')
}

グループ指定したものを $1$2 などで参照してリネーム後のファイル名に利用している。         

renameクロージャを渡すこともでき、より柔軟な処理を記載できる。

task rename(type: Copy) {
    from 'source'
    into 'dest'
    rename { fileName ->
        "production-file${(fileName - 'file-template')}"
}

Groovy では文字列同時の-は、最初に見つかった文字列を削除するため、前述の例と同じ動きとなる。

expand で変数の置換

ビルド時に環境毎に設定ファイルを書き換えたい場合など expand() メソッドが使える。

versionId = '1.6'

task copyProductionConfig(type: Copy) {
    from 'source'
    include 'config.properties'
    into 'build/war/WEB-INF/config'
    expand([
        databaseHostname: 'db.foo.com',
        version: versionId,
        buildNumber: (int) (Math.random() * 1000),
        date: new Date()
    ])
}

expand は groovy.text.SimpleTemplateEngine を利用しているので、JSP形式<% %> <%= %> または GString形式 ${}プレースホルダとして利用できる。

以下のような設定ファイルのプレースフォルダが expand の指定で文字列置換される。

# App configuration file
hostname: ${databaseHostname}
appVersion: ${version}
buildNumber: ${buildNumber}
buildDate: ${date.format("yyyyMMdd'T'HHmmssZ")}

fileMatching で変数の置換

前述の例では include で置換ファイル対象を指定したが、fileMatching で該当したファイルのみ置換を行うことができる。

task copyFiles(type : Copy) {
    from 'source'
    into 'build/war/WEB-INF/config'
    filesMaching('**/*.properties') {
        expand version: '1.0'
    }
}

filter で1行毎に変換

コピー対象のファイルを1行ずつ変換処理するには filter を使う。

以下の例では filter にクロージャを渡してコピー時にファイルの内容を1行毎に変換処理している。

task copyProductionConfig(type: Copy) {
    from 'source'
    include 'templ.conf'
    into 'build'
    rename { it - 'templ' + 'production'}
    filter { line -> 
        "[$line]"
    }
}

filter() には java.io.FilterReader のサブクラスを渡せるので、ant のフィルタがそのまま使える。

import org.apache.tools.ant.filters.FixCrLfFilter
import org.apache.tools.ant.filters.ReplaceTokens
import org.apache.tools.ant.filters.TabsToSpaces

task copyProductionConfig(type: Copy) {
    ・・・
    filter(FixCrLfFilter)
    filter(ReplaceTokens, tokens: [copyright: '2009', version: '2.3.1'])
    filter(TabsToSpaces, tablength: 4)
}

改行コードをプラットフォームに応じて変更し、@copyright@ @version@ という文字を変換し、タブをスペースに変換など。

eachFile でファイル毎に処理

filter() では行単位であったが、eachFile() はファイル単位で処理する。

task copyFile(type: Copy) {
    into 'build/deploy'
    from 'source'
    eachFile { fileCopyDetails ->
        println fileCopyDetails.file.name
    }
}

上記ではクロージャを渡している。引数には org.gradle.api.file.FileCopyDetails が渡される。

CopySpec を定義する

コピーの仕様を定義して with で適用できる。

def contentSpec = copySpec {
    from("content") {
        include "**/*.txt"
    }
}

task copy(type: Copy) {
    into "$buildDir/copy"
    with contentSpec
}

Gradle Effective Implementation Guide

Gradle Effective Implementation Guide

Gradle徹底入門 次世代ビルドツールによる自動化基盤の構築

Gradle徹底入門 次世代ビルドツールによる自動化基盤の構築