R2を同期するr2syncというツールをRustで書いてcrate公開した
https://crates.io/crates/r2sync
コマンドラインツールであり以下でインストールできる。
$ brew install Songmu/tap/r2sync
# or
$ cargo install r2sync
これはローカルディレクトリの中身をCloudflare R2に簡易的に同期するごく単純なツールで以下のように使う。
$ r2sync ./dir r2://your-bucket/path
リモートに同一ファイルが存在する場合にputをスキップするようになっていて、それが欲しくて作った。ちなみに、--public-domain
というオプションを付けると、同一ファイルチェックを公開URL経由で行うようになってAPIアクセスを減らせる。
$ r2sync --public-domain files.example.com ./dir r2://your-bucket/path
ファイルの同一性チェックは、Content-LengthとETagを見ている。S3やR2はETagがコンテンツのMD5ハッシュ値なので、それで同一性チェックをしている。この挙動が未来永劫担保されるかわからないが、単にContent-Lengthだけ見るのも嫌だったし、実際にContent-Lengthだけ主に見ている aws s3 sync
がたまにハマるという話も聞くのでそうした。
GitHub Actions
カスタムアクションも公開していて、以下のように使える。oss4.funでも導入した。
- uses: Songmu/r2sync@v0
with:
r2_account_id: ${{ secrets.R2_ACCOUNT_ID }}
r2_access_key_id: ${{ secrets.R2_ACCESS_KEY_ID }}
r2_secret_access_key: ${{ secrets.R2_SECRET_ACCESS_KEY }}
src: ./audio
dest: r2://<your-bucket>/audio
public_domain: files.example.com
作った動機
ポッドキャストの音声ファイルのアップロードをGitHub Actionsでやっているが、ディレクトリ内の全部の音声ファイルを毎回素朴にputしていたので流石に富豪すぎるので解決しようと考えたのが契機。
案外、既存の良いツールが見つけられなかったのと、aws s3 sync
を使っても良かったのだけど、前述のETagの話もあったし、せっかくR2はエグレス料金が無料なのだからファイルの同一性チェックを公開URL経由でおこなうアイデアを盛り込んで作った。
Rust
習作がてらちょっとしたものをRustで作ってみたいと思っていたので、ちょうどよい題材だった。strとStringの使い分けとか、unwrap
を使いすぎだったりとかまだまだお作法が分からない部分が多いが、とりあえずcrate公開までいけたのは良かった。Resultとかパターンマッチ含めた言語自体の書き味はかなり良い。
思っていたよりクロスビルド周りが難しくて、各プラットフォームにバイナリを提供するのに手こずった。とりあえず、GitHub Actions上で作るのは一旦断念して手元でバイナリをビルドしてGitHub Releasesにghrでアップロードするという一昔前のスタイルでお茶を濁した。
Rustを書き始めるにあたって「Rustの練習帳」が参考になった。Rustの考え方やコマンドラインツール作成について実践を通して学べる点で有益だった。Goでもこういう本があると良さそう(すでにあるかも)、とか思った。