この記事では、Gradle でディレクトリ内のファイルを別のディレクトリにコピーする際に、中身が同じファイルはコピーしないようにする方法を紹介します。
ディレクトリをコピーする
コピー元と、コピー先のディレクトリ間のコピーをする場合
Gradleでは、Copyタスクか、自分で実装したタスク内で、project.copy を使って、ディレクトリ内のファイルを再帰的にコピーする事ができます。
更に、eachFile で、各ファイルの中身が同じかどうかチェックして、もし同じ場合にはコピーしないようにする事ができます。
ファイルの中身が同じか判定
多くの場合は、ファイルサイズと、タイムスタンプ(更新日時)を参考にして、コピーするかどうか判定するので充分な場合が多いです。
しかし、今回はファイルの中身(バイト配列)が一致するかどうかで判定したいと思います。※1
(タイムスタンプは無視する)
ファイルの中身、つまりバイト配列が同じかどうかを判定するには、Apache Commons のFileUtils.contentEqualsメソッドを利用するのがてっとり早くで簡単です。
コピータスクの実装
build.gradle 今回はKotlin DSLの例を記載します。
特定のディレクトリと、
ビルド成果物のコピーを実行するタスク実装をしてみます。
build.gradle.kts 書き方
buildscript {
// Gradleのタスクで使う依存ライブラリの設定
dependencies {
// FileUtils.contentEquals を使う為に必要
classpath("commons-io:commons-io:2.10.0")
}
}
ApacheCommonsのFileUtilsを利用するために、
buildscriptディレクティブでライブラリ追加の宣言をします。
/**
* build/image ディレクトリ内のファイルを、/path/to/somewhere にコピーする。
* バイト比較でファイル内容が同じ場合は、コピーしない。
*/
tasks.register("myCopy") {
doLast {
val distDir = "/path/to/somewhere"
copy {
from("$buildDir/image")
into(distDir)
// コピー対象のファイルをひとつひとつチェック
eachFile {
// ファイルが同じ内容なら、exclueしてコピーされないようにする。
val distFile = File(distDir, path)
if (org.apache.commons.io.FileUtils.contentEquals(file, distFile)) {
exclude()
}
}
}
}
}
copyディレクティブに、from と into を記載のうえ
eachFileで、ファイルごとにコピー先とファイルの中身が同じかどうかチェックしています。
ファイルの中身が同じ場合は、excludeすることで、
そのファイルはコピーされなくなります。
まとめ
- Copyタスクや、project.copy メソッドを使えば、簡単にディレクトリのコピーができる。
- eachFile メソッドを使う事で、ファイルごとに追加のチェック処理を記述可能。
- コピー対象から除きたい場合は、excludeメソッドを使う。
※1 ファイルの中身で判定したかった理由としては、
ビルド成果物をどこかのディレクトリに配置する際に、同じファイルなのにタイムスタンプが変わるのが嫌なケースがあったからです。
例えば、共有の社内ドライブに、成果物のファイル郡を配置しておいて、XCOPYや、ROBOCOPYでダウンロードしているような場合、ファイルが同じものであってもタイムスタンプが変わっていると、残念ながら再ダウンロードされてしまいます。
なので、共有のドライブにファイルを配置する際には、
中身が同じファイルであれば、再アップロードしないように(タイムスタンプが変わらないように)運用する必要がありました。