progrhyme's tech blog

主にIT関連の技術メモ

GitHub Pagesをメタデータサーバとする簡易インストーラー「binq」をGo言語で作った

※2020-07-13追記: 各リポジトリGitHub Org https://github.com/binqry に移しました。*1

どんなツールか

「簡易インストーラー」と書きましたが、単純にインターネットからソフトウェアをダウンロードして、実行ファイルを指定されたディレクトリに配置します。
圧縮ファイル形式で配布されているものは解凍して、実行ファイルを見つけて配置します。
バイナリのまま配布されているものだと、UNIX系OS環境だとよく chmod +x しないといけないのですが、それは自動的にやります。
WINDOWSだともうちょっと別の対応が要りそうですが、まだやってません。

使い方

# フルURL指定
binq https://github.com/peco/peco/releases/download/v0.5.7/peco_darwin_amd64.zip \
  -d path/to/bin
binq https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 \
  -d path/to/bin -f jq

# メタデータサーバ + プログラム名指定
binq -s https://progrhy.me/binq-index mdbook -d path/to/bin

## 環境変数でメタデータサーバとインストール先ディレクトリを設定可能
export BINQ_SERVER=https://progrhy.me/binq-index
export BINQ_BIN_DIR=path/to/bin
## @VERSION でバージョン指定可能
binq jq@1.6 -f jq

なぜ作ったか?

LinuxでもLinuxbrewが使える昨今では、だいたいHomebrewで済むのですが、以下のようなことがあります:

  • たまにHomebrewに対応してないツールがある
  • たまにHomebrewを環境にインストールするのが憚られることがある(サーバとか)

代替手段としてSongmu/ghgがたまに使えることがあるのですが、URLが期待通りじゃなかったり、そもそもGitHub Releasesで配られてなかったりすると使えません。

…というわけで、もうちょい汎用的なやつを作ってみることにしました。

メタデータメタデータサーバ

概念

GitHub Releases以外のURLにも対応しつつ、ghgのいいとこ取りをするために考案した仕組みです。

サーバの機能としては、今のところ単に静的なJSONデータを返せれば十分なので、GitHub Pagesでも実現できているというわけです。

progrhyme/binq-indexのgh-pagesブランチのファイル構成は次のようになっています:

.
├── github.com
│   ├── peco
│   │   └── peco
│   │       └── index.json
│   ├── progrhyme
│   │   └── shelp
│   │       └── index.json
│   ├── rust-lang
│   │   └── mdBook
│   │       └── index.json
│   └── stedolan
│       └── jq
│           └── index.json
├── index.json
└── terraform
    └── index.json

メタデータサーバを指定して binq [install] jq を実行すると、次のようにして、 github.com/stedolan/jq/index.json を見つけます:

  1. ${メタデータサーバのURL}/jq にHTTP GETリクエス
  2. 見つからなければ ${メタデータサーバのURL} にHTTP GETリクエスト => /index.json が返ってくる
  3. このJSON内の "items" というリストに {"name": "jq", "path": "github.com/stedolan/jq/index.json"} というエントリがある
  4. ${メタデータサーバのURL}/github.com/stedolan/jq/index.json にHTTP GETリクエス

…で、 jq/index.json の中身を見て、jqのダウンロードURLを見つけます。

上のような照合順序になっているので、メタデータサーバ内で ${プログラム名}/index.json というパスに配置しておけば、HTTP GET一発でJSONを見つけられます。上のファイル構成だと、terraformがそうなっています。
逆に、 binq github.com/stedolan/jq と指定してjqをインストールすることも可能です。

メタデータの更新について

binqによって常にソフトウェアの最新版をインストールしたい場合、メタデータを継続的に更新していく必要があります。

任意の配布元に対する汎用的な手段を講じるのは難しいですが、とりあえずGitHub Releasesのものについては、GitHub APIを叩いて最新のリリースを見つけ、更新があればメタデータを更新するようにGitHub Actionsで設定しました。

これを実現するワークフローの設定はこちらです。

これをやるためにbinqのラッパーとして動作するbinq-ghというCLIをGo言語で書きました。
今のbinqはCLIの機能をあまりエクスポートしてないこともあって、結局、中で binq コマンドを叩いています。
気が向いたら、そのうち改善するかもしれません。

その他、 binq コマンド側でもメタデータJSONを楽に生成・更新できるようなサブコマンドをいくつか作りました。
例えばterraformの新しいバージョンが出た、というときは下のような感じで更新できます。

binq revise path/to/terraform/index.json -v $NEW_VERSION

# 更に、以下を実行すると、ダウンロードURLが有効か検証して、JSONにchecksumを足すことができる
binq verify path/to/terraform/index.json -v $NEW_VERSION [-o OS] [-a ARCH]

正直、ダウンロード・インストールの機能を作るより、この辺の周辺機能を作り込む方が大変でした。

利用例

まだ設定していませんが、こんな感じでdotfilesに設定しようと思っています:

# bash / zsh
export BINQ_SERVER=https://progrhy.me/binq-index
export BINQ_BIN_DIR=$HOME/bin # いつもここにパスを通しているので
BINQ_VERSION=0.6.1

# binqをインストール
if ! command -v binq &>/dev/null; then
  _os=linux # or darwin
  _tmpfile=$(mktemp)
  curl -Lo $_tmpfile "https://github.com/progrhyme/binq/releases/download/v${BINQ_VERSION}/binq_${BINQ_VERSION}_${_os}_amd64.zip"
  unzip -d $BINQ_BIN_DIR $_tmpfile
  rm $_tmpfile
  unset _os _tmpfile
fi

_BINQ_ITEMS=(
  shelp
)

for _bin in ${_BINQ_ITEMS[@]}; do
  if ! command -v $_bin &>/dev/null; then
    binq $_bin
  fi
done
unset _bin

アドホックに使いたいツールも、利用頻度が多いものはbinq-indexに登録してbinqコマンド一発で入れられるようにしておこうと思います。

今後の予定

パッケージ管理機能

今だとインストールされたソフトウェアのバージョン管理ができません。

いまどのバージョンが入っているのかを管理し、必要に応じてアップグレードしたり、バージョン固定したいようなケースを考えると、やはりパッケージ管理ツール的な機能が必要になってくるかな、と考えています。

既にbinqにはバージョン指定でインストールする機能はありますし、自分的にそれほど優先度が高いわけではありませんが、その内対応しようかなぁと思っています。

URLフォーマットの自動生成

新しいソフトウェアのメタデータをbinqのインデックスに登録するときに一番面倒なのがこれです。
頑張れば自動化できそうだなとは思うものの、そこそこ気を使って実装する必要がありそうで、とりあえずは手動で作成している現状です。

その他

あとは、テストをもっと書かないとな…と思っています。正常系、何も書いてない…。

まとめ

HTTPなメタデータサーバを利用する簡易インストーラー「binq」を紹介しました。

よろしければ、どうぞご利用ください。

メタデータサーバはforkしてもらってもいいですし、便利なものだったらprogrhyme/binq-indexにプルリクエストしてもらっても構いません。
自分が使わない類のものは判断がつかないかもしれませんが、誰かにとって有用なものなら、載せておいてもいいかなと思っています。

参考

GitHub PagesでJSONをサーブする件:

免責事項

ソフトウェアのメタデータを集めて公開するのは、著作権やライセンスとの関係でどうなのだろう、と少し頭に過りました。
…が、このツールそのものでソフトウェアをホストするわけではなく、基本的にオリジナルのダウンロードURLを参照する形を取るので、再配布には当たらない認識です。

これが駄目だと、検索エンジンとかパッケージ検索サービス(例: https://libraries.io/)とかも駄目そうな気がする。
…という認識でいますが、誰か詳しい人いたら教えて下さい。

ひょっとしたら、モノによってはこういった形での公開もライセンスで明示的に禁止されているかもしれませんが、少なくともOSSフリーソフトウェアに限ってインデックスしている限りは問題ないだろうと思っています。

※まずいケースがあるなら、メタデータを公開しないでローカルのファイルシステムに置いたまま使えるモードを作るかもしれません。