きっかけ
自作のCLIツールやdotfiles用のスクリプトを複数のマシンに配るとき、毎回git cloneしてシンボリックリンクを張るのが面倒になってきた。普段からパッケージはdnfとbrewで管理しているので、自分のツールも同じ仕組みに乗せてしまえば dnf upgrade や brew upgrade のついでに更新される。ということで、自分専用のdnfリポジトリとbrew tapを用意してみた。
brew tap
GitHubに homebrew-tools という名前でリポジトリを作る。homebrew- というプレフィックスが必須で、これがあると brew tap ユーザー名/tools のように短い名前で参照できる。
リポジトリ直下に Formula ディレクトリを作って、rubyのファイルを置くだけでいい。
※USER_NAMEは自分のGitHubユーザ名に置き換えること
class Mytool < Formula
desc "My personal CLI tool"
homepage "https://github.com/USER_NAME/mytool"
url "https://github.com/USER_NAME/mytool/archive/refs/tags/v0.2.0.tar.gz"
sha256 "ここにtarballのsha256を書く"
license "MIT"
def install
bin.install "mytool"
end
end
sha256は次のコマンドで取れる。
curl -sL https://github.com/USER_NAME/mytool/archive/refs/tags/v0.2.0.tar.gz | shasum -a 256
使う側はこれだけ。
brew tap USER_NAME/tools
brew install mytool
タグを切るたびにFormulaのurlとsha256を書き換える必要があるけど、それ以外にやることがない。メタデータの生成も署名も不要で、GitHubのリポジトリがそのまま配布チャネルになる。
dnf
こっちはそれなりに手順がある。大まかには、rpmを作る、createrepo_cでメタデータを生成する、httpで公開する、の流れになる。
rpmを作る
まずspecファイルを書く。
Name: mytool
Version: 0.2.0
Release: 1%{?dist}
Summary: My personal CLI tool
License: MIT
URL: https://github.com/ttakahashi/mytool
Source0: %{url}/archive/refs/tags/v%{version}.tar.gz
%description
Personal CLI tool for daily tasks.
%prep
%autosetup -n mytool-%{version}
%install
install -Dm755 mytool %{buildroot}%{_bindir}/mytool
%files
%license LICENSE
%{_bindir}/mytool
ビルドはrpmbuildでも良いが、chrootを使用するmockを使った。
mock -r fedora-44-x86_64 --buildsrpm --spec mytool.spec --sources .
mock -r fedora-44-x86_64 --rebuild mytool-0.2.0-1.fc44.src.rpm
リポジトリのメタデータを作る
できたrpmをディレクトリに集めて createrepo_c を実行する。
mkdir -p repo/fedora/44/x86_64
cp result/mytool-0.2.0-1.fc44.x86_64.rpm repo/fedora/44/x86_64/
createrepo_c repo/fedora/44/x86_64
これで repodata ディレクトリが生成されて、dnfが読める形式になる。
rpmを追加したり更新したりしたら、毎回createrepo_cを実行し直す必要がある。
最初これを忘れて、新しいバージョンを置いたのにdnfから見えないとしばらく悩んだ。
公開する
httpで配信できればなんでもいいので、GitHub Pagesに乗せた。repoディレクトリをそのままpagesブランチに置くだけ。
クライアント側には .repo ファイルを置く。
# /etc/yum.repos.d/USER_NAME.repo
[USER_NAME]
name=USER_NAME personal repo
baseurl=https://USER_NAME.github.io/repo/fedora/$releasever/$basearch
enabled=1
gpgcheck=0
これで dnf install mytool が通るようになる。
gpgについて
上の例では gpgcheck=0 にしているけど、自分しか使わないリポジトリでも署名はしておいた方がいい。rpmsignで署名して、公開鍵をリポジトリに置いて gpgkey= で参照させる。手順は長くなるので省くが、署名なし運用だとdnfの設定で警告を黙らせ続けることになって精神衛生に悪い。
ハマったところ
- createrepo_cの実行を忘れると、rpmを置いてもdnfからは存在しないことになる。リリース用のMakefileに組み込んで忘れないようにした
- GitHub Pagesのデプロイには少しラグがあるので、pushした直後にdnfを叩くと404になることがある。dnf clean metadata してから再試行すれば直る
- brewのFormulaはsha256が一致しないとインストールが止まる。タグを打ち直すとtarballのハッシュが変わるので、リリース後にタグを動かすのはやめた方がいい
まとめ
個人ツールの配布なら、macOS向けはbrew tap一択でいいと思う。リポジトリを作ってrubyファイルを1枚置くだけで終わる。
dnfの方はFedoraならCOPRを使う方が実は簡単らしいがそれに気がついたのは一通り終わったあとなので機会があれば試そうと思う。