jarで作成したCLIツールをhomebrewで配布するまで
Kotlinの勉強ついでにCLIのツールを作成したのですが、いざこれを実際にmacやLinuxで実行するために開発環境とは別のマシンに配布しようと思ったときに悩みました。
macで同じみのhomebrewを使うと自作のツールでも簡単に配布できることが分かったので、その方法のメモ
jarのツールもjava -jarなしで実行したい
今ではKotlin Multiplatformというものがあるので必ずしもそうではないが、Kotlinで作成したプログラムを実行可能な形にしようとするとjarになる。
gradleなど無しで単独で実行するには java -jar hoge.jar
のようにどうしても java -jar
が必要になる。これはさすがにかっこ悪いのでなんとかしたい。
世の中のツールで java -jar
を付けさせるものは見たことがないので何とかする方法があるはず。というわけでまずはjava製の代表的なツールであるJenkinsがどうしているのか調べてみた。
ちょうど手元のmacにはhomebrewでJenkinsをインストールしていたのでこれを調べてみる。
$ cat `which jenkins`
#!/bin/bash
JAVA_HOME="$(/usr/libexec/java_home --version 1.8)" exec java -jar /usr/local/Cellar/jenkins/2.234/libexec/jenkins.war "$@"
なるほど、bashのラッパースクリプトを用意しているのか。頭いい。
$@
はスクリプトの引数すべてを表しているので jenkins --httpPort=8080
のように引数を渡した場合、java -jar jenkins.war --httpPort=8080
のように実行したのと同じことになるというカラクリになっている。
特にデメリットもなさそうなので、jarとセットでこのようなラッパースクリプトを用意してやれば見た目上はgoなどで作られたシングルバイナリのツールと遜色ない形にできそうなことが分かった。
jarのツールをhomebrewで配布するFormulaを見てみる
このjenkinsのコマンドがhomebrewではどのように配布されているのかを見てみる。
まだ分からないことだらけだが、
url "http://mirrors.jenkins.io/war/2.279/jenkins.war"
がおそらくダウンロードするwarの場所、
depends_on "openjdk@11"
が依存パッケージ、
def install
がインストール処理だと想像できる。
ここでinstallの中の bin.write_jar_script libexec/"jenkins.war", "jenkins", java_version: "11"
が気になった。write_jar_script
とは?これをgithubの検索で調べてみる
javaやKotlinで有名なツールがザクザク出てきた
- https://github.com/Homebrew/homebrew-core/blob/master/Formula/apktool.rb
- https://github.com/Homebrew/homebrew-core/blob/master/Formula/detekt.rb
- https://github.com/Homebrew/homebrew-core/blob/master/Formula/digdag.rb
そして関連してそうなissueも発見。
差分を見てみると、どうやら昔は多くのパッケージでbashのラッパーを手書きしていたようだがそれらをまとめて write_jar_script
に書き直している。
ということは、Jenkinsにもあったbashのラッパーはhomebrewが提供している機能らしい。
Jenkins以外のツールも発見できたことで、Formulaファイルにどういう内容を書けばいいのか大体想像がついたので次のステップに進む
オレオレtapを作る
いきなりhomebrew本家にPRを出すとかえって面倒そうなので、まずはオレオレtapを作成ししてしばらくはそこで運用したい。
- github上で
homebrew-xxx
というリポジトリを用意するとbrew tap
で取り込むことができる -
brew tap-new
でtapのテンプレートが作成できる
ななめ読みしたところ、上記のことが分かったのでまずはテンプレートを作成する。
(以下の実行環境はWindowsのWSLで動かしているubuntu)
$ brew tap-new Kesin11/homebrew-tap
Initialized empty Git repository in /home/linuxbrew/.linuxbrew/Homebrew/Library/Taps/kesin11/homebrew-tap/.git/
[master (root-commit) 4e04054] Create kesin11/tap tap
3 files changed, 85 insertions(+)
create mode 100644 .github/workflows/publish.yml
create mode 100644 .github/workflows/tests.yml
create mode 100644 README.md
==> Created kesin11/tap
/home/linuxbrew/.linuxbrew/Homebrew/Library/Taps/kesin11/homebrew-tap
When a pull request making changes to a formula (or formulae) becomes green
(all checks passed), then you can publish the built bottles.
To do so, label your PR as `pr-pull` and the workflow will be triggered.
tapのディレクトリが作られるので、最初にgithubにもpushしてしまう。LICENSEが含まれていなかったので、リポジトリ作成時にgithubに作ってもらったファイルをコピペしてinit commitに含めた。
Github Releasesを作成する(jarをアップロードする)
後述する brew create
を実行するには、まずリリース予定のjarをパブリックなところにアップロードする必要がある。場所はどこでもいいと思うが、個人の制作物なので一番手軽なGithub Releaseを使うことにする。
暫定的なtagを打ち、Github Actionsでアーティファクトに保存していた最新のjarをアップロードした。
Formulaをテンプレートから作成する
ドキュメントを見ると brew create <URL>
でFormulaのテンプレが作成できると書いてあるので、 アップロードしたjarのurlをコピーして以下のようなコマンドを実行する。
オプションは brew create --help
を見て良さげなものを追加した。
brew create --set-name skw --set-license MIT --tap Kesin11/homebrew-tap https://github.com/Kesin11/SkyWarehouse/releases/download/v0.1.0-beta.1/skw.jar
すると先ほど作成したtapの中のFormulaに新しいファイルが作成されている。特に一番めんどくさそうな sha256
を自動的に埋めてくれるのが嬉しい。
事前に調べていた他のjar製ツールのFormulaを参考に必要な項目を埋めていく。
class Skw < Formula
desc "Tool making cloud object storage as a artifact repository"
homepage "https://github.com/Kesin11/SkyWarehouse"
url "https://github.com/Kesin11/SkyWarehouse/releases/download/v0.1.0-beta.1/skw.jar"
sha256 "2109b9e1e75c443bfc8095ea027e130e6a343b76ce50ac56d59e36cc42ddf5de"
license "MIT"
bottle :unneeded
depends_on "openjdk@8" => :recommended
def install
libexec.install "skw.jar"
bin.write_jar_script libexec/"skw.jar", "skw"
end
test do
assert_match "Usage: Sky Warehouse options_list", shell_output("#{bin}/skw --help")
end
end
ちなみに test
として実行する内容を単に --help
にするのはアンチパターンとドキュメントには書かれているが、今回のツールはいずれのコマンドも実行するためにGCPの認証情報が必要なため、やむを得ず --help
が実行できるかどうかだけをチェックしている。
別にちゃんと実装するのが面倒だったからではない
後はいつもhomebrewを使うのと同様に brew install skw
と実行するとGithub Releasesからjarをダウンロードし、bashのラッパースクリプトも含めてインストールしてくれてPATHも自動的に通してくれる。
以上、これだけで自作のツールをhomebrewで配布することができる。便利~~
アップデートの方法
TODO
少なくとも url
と sha256
は更新する必要があるはずだが、手動でやると面倒くさい。自動でやるツールが何かしらあると思われるので調べたら追記するかも。
参考
tapについて
Formulaの基本について。まずはここを見るとよさそう。
homebrew本家に取り込んでもらうために守ってほしいことが書いてあるっぽい。オレオレtapで使う分には遵守しなくても問題ないだろうが、一読しておいた方がよいだろう
FormulaのDSLのリファレンス(DSL=rubyなのでrubyのドキュメント)
参考にするFormulaを読んでいて分からない記述が出てきたらここで調べる