諸事情により 相当大きなサイズのファイルを scp でサーバにアップロードすることがあるのだが、転送途中で接続が切れるなどの問題が生じるとはじめからやり直しになる。それを避けるために、split コマンドを使ってファイルを小分けにした上で転送して、サーバ上で cat で元に戻す、という昔からの方法がある。
しかしこの作業も繰り返し行うとなるとこれはほとんど拷問なので、Gradle SSH Plugin で半自動化して手間を省く話です。
たとえば foo.tar.gz という大きなサイズのファイルがあったとする。
split -b 10m foo.tar.gz foo.
こうすると foo.aa, foo.ab, foo.ac, .... という foo.tar.gz が分割されたファイルがカレントディレクトリに生成されるので、scp を使って以下のようにサーバへ転送します。
ls foo.?? | while read line; do scp $line hoge@servername:~/ ; done
これで foo.aa, foo.ab, foo.ac, .... ファイルは scp コマンドで サーバの hoge ユーザのホームディレクトリに転送されます。
※)もし途中で転送が失敗した場合は、転送済みファイルのみ削除して、再度実行する。
全部の foo.?? ファイルをサーバに無事転送できたら、サーバ側で cat します。
cat foo.?? > foo.tar.gz
一度きりの作業ならこれでよいのですが、何度もこんな作業が発生すると気が滅入ります。対象が大きなファイルなので、全部転送するまでに時間がかかりますし、転送が終わったころを見計らって cat 作業を行わなければならないのはとても面倒です。
そこで Gradle SSH Plugin を使ってこの作業を自動化します。
build.gradle
plugins {
id 'org.hidetake.ssh' version '1.4.0'
}
ssh.settings {
dryRun = project.hasProperty('dryRun')
}
remotes {
cloudsrv {
role 'myworkspace'
host = '192.168.0.99' // set your server IP address
user = 'foo' // set your server unix username
identity = file('/paht/to/id_rsa')
}
}
task upload << {
"split -b 10m foo.tar.gz foo.".execute().waitFor()
def filter = { it.name=~/foo\.[a-z]{2}$/ }
def filenamelist = new File('.').listFiles().findAll(filter).join(/ /)
println filenamelist
ssh.run {
session(remotes.role('myworkspace')) {
filenamelist.split(/ /).each { filename->
println filename
put( filename, filename )
}
execute( 'cat foo.?? > foo.tar.gz' )
}
}
}
これを foo.tar.gz ファイルが存在するディレクトリに build.gradle というファイル名で保存して
gradle upload
これで split/転送/cat を自動化できます。
ネットワークが安定していれば、そもそも分割などしないで foo.tar.gz を scp すればこんな面倒なことは不要なわけで...