RubyでディレクトリごとFTPで一括アップロードする方法

ruby

RubyからディレクトリごとサーバーにFTP転送する処理を書きたかったのですが、最初なかなかうまくいきませんでした。

  1. Rubyのftpライブラリでエラー多発
  2. lftpで解決
  3. 参考

Rubyのftpライブラリでエラー多発

RubyからFTPを使う場合net/ftpを使うのが一般的らしいです。また、これをラップしているdouble-bag-ftpsも試しました。

ですが、loginまでは正常にできるのですが、一覧取得やファイル転送をすると止まってしまったり、エラーが発生してしまいます。

例えば、以下のようなエラーです。

1
Errno::ECONNRESET: Connection reset by peer
1
Net::FTPReplyError: 150 Opening ASCII mode data connection for file list
1
200 Type set to I. (Net::FTPReplyError)

かなりハマりましたが、結局Rubyのライブラリーではなく、外部コマンドを使って行うことで解決しました。

lftpで解決

lftpというコマンドです。MacでHomebrewをお使いであれば、

1
brew install homebrew/boneyard/lftp

でインストールできるはずです。

このコマンドはかなり安定感があり、今まで一度もエラーは発生していません。また、Rubyのnet/ftpなんかは仮に正常に動いたとしてもディレクトリ全体を転送することはできないので、1ファイルごとに転送する必要がありました。ですが、lftpはディレクトリを指定し、一括で転送することができます。

Rubyからの使い方としては、こんな感じのスクリプトにしておくと

1
2
3
command = "lftp -u #{id},#{pass} -e \'mirror -R --only-newer #{source} #{dest}; exit;\' #{host}"
puts command
puts `#{command}`

こんな出力をしてくれて、きちんと転送してくれます。

1
2
3
4
5
lftp -u id,password -e 'mirror -R --only-newer source_dir dest_dir; exit;' host.jp
Total: 3 directories, 161 files, 0 symlinks
Modified: 161 files, 0 symlinks
704729 bytes transferred in 10 seconds (71.4 KiB/s)
To be removed: 1 directory, 0 files, 0 symlinks

いやー、でもなんでRubyのnet/ftpはいまいち動作がおかしいんだろうか。

参考