HomebrewのFormulaを更新する場合

  • Formulaのバージョン
  • ダウンロードするファイルのSHA256

を変更する必要があります。毎回手作業でやるには面倒な上に、Travis CIなどでバイナリをビルドしてGithubのReleasesページに自動アップロードする処理を書いていたりすると、tarコマンド(GNU or BSD)やアーカイブ時間、UID/GIDの差異によって、tar.gzのバイナリが変わってしまうためハッシュ値取得のところでハマりやすいです。例えば、macOSで作成したtar.gzのハッシュ値とTravisの環境で作成したハッシュ値が異なるので、macOSからFormulaをgit commit/pushで更新する場合は、GithubのReleasesページからダウンロードしてきたものに対してハッシュ値を取る必要があります。

ということで今回はTravis CIでHomebrewの独自リポジトリをGithub Contents APIを使って自動更新する方法を紹介します。

Makefileや.travis.ymlの設定はこちらのリポジトリも参考にしてもらえればと思います↓
tzmfreedom/goroon: Cybozu garoon library and command line interface by golang

Github Contents APIの使い方

Github Contents APIは単一ファイルをピンポイントに取得、作成、更新するAPIになります。作成のAPIの場合は、clone/pull + add + commit + pushを1回のAPIコールで行うことができます。

例えば、ファイル情報の取得は以下のcurlコマンドで実行可能です。

レスポンスはこんな感じです↓

ファイルの中身はcontentプロパティにBase64エンコードされて入っており、gitのblobのsha1はshaプロパティに入っています。

更新は以下のように行います。

blobのsha1はgitのハッシュになり、以下のコマンドで取得可能です。

自動更新のスクリプト

Makefileで表現すると以下のようなスクリプトになります。

まず、cat/sedはリポジトリにformulaのテンプレートを持たせて、sedで置換することでsha1の値やバージョン番号をバインドしています。古いファイルのsha1を取得するために、wgetでmasterブランチのHEADのファイルを取得します。最後にcurlでGithub Contents APIを叩いてファイルを更新しています。

formula/goroon.rb.tmplはこんな感じです↓

git hash-objectで古いファイル(=wgetしてきたファイル)のgit blobのハッシュを取っています。contentはopensslでbase64エンコードした値をセットしています。opensslのbase64はPEMコンテキストのため、64文字の改行区切りです。そのため、opensslでbase64したあとはtrを噛ませて改行や空白を削除しています。

あとはこのmakeタスクを.travis.ymlのafter_deployあたりで実行すればOKです。

env.global.secureのtokenは$ travis encrypt GH_TOKEN='xxxx' --addで追加したトークンです。

所感

暗号化するとはいえ秘密鍵をパブリックリポジトリに置くのは微妙かなーと思いGithub APIで試してみました。APIだとある程度権限制御できそうなのがGoodです。gitでcommitするとなるとリポジトリごとgit clone/pullしないといけないので、ネットワークの効率も良さそう。

そもそも論になっちゃうけど配布方法はHomebrewじゃなくて、curl -L http://xxx/install.sh | shのインストールスクリプトで/usr/local/binに置く方がLinuxもいけるしFormulaのメンテが不要になるので、そっちの方が良かったかもです。Homebrewの方が配布物のバージョンアップに対応しやすそうだけど。

参考URL