最近作ったコマンドラインツールの話

どうもnasaです! (良いタイトルが思いつきませんでした。アイディア募集中! @nasa_desuコチラまで!)

最近寒いです。誰かボクの心と体を温めて下さい。カレー風呂に入りたい。

この記事は Treasure Advent Calendar 2019 の記念すべき1日目の記事です!

某YAGE GROUPにちなんだ内容にしたかったのですが、思いつきませんでした。

今回は、11月に作ったコマンドラインツールの紹介とHomebrewに公開するまでの話を書こうと思います。

特に難しいことはやっていないので技術的な話はありません。 読んで得るものもないかもしれません。スミマセン。

目次

Homebrewに公開する

注: 今回一貫して、「Homebrewに公開する」と言いますが、これはHomebrew本家にPRを送って登録するのではなく、brew tapを使うことを想定しています。

brew tapサードパーティー製のツールなどを公式ツールと同様にbrew [install, update, trace]などのコマンドで扱えるように登録するためのコマンドです。

例えばボクは11月初旬にgokuというツールを作りましたがこれは

brew tap k-nasa/tap
brew install goku

もしくは

brew install k-nasa/tap/goku

でインストールすることができます。上のコマンドでは明示的にk-nasa/taptapコマンドで登録していることが分かりますね。

ちょっと余談

うろ覚えで、下調べも何もしていないので余談とします。

tapなんか使わずにbrew install hogeで直接インストールできるツールはどうしてるの?と疑問に思った人もいると思います。

macユーザーの方は以下のコマンドを実行してみて下さい。

brew tap | grep core

homebrew/coreというのが見つかりましたか? brew tapで追加した覚えはありますか?

このhomebrew/coreというのはデフォルトであります

coreに追加するためにはhomebrew-coreリポジトリにPRを投げて、自分のツールを登録する必要があります。

逆に言えばPRを投げることで誰でも登録できるということでもありますね。

しかし、PRを出せば何でも追加できるわけではありません。半年前に調べたことなどでうろ覚えなのですが、例えば、登録したいツールのソースコードGitHubにあったとすると、starを50集めないと、登録できない。などの決まり事が多数あった気がします。

Formulaファイル

本題に戻りましょうか。(本題ってなんでしたっけ? 忘れましたが、、、)

brew tapで自分のツールを登録するためには、まずhomebrew-<ツール名>というリポジトリを作り、Formulaファイルと呼ばれるファイルを追加しなければなりません。多分GitHubで無くてもいいとは思いますが、未確認です。

ちなみに、リポジトリ名はhomebre-<ツール名>が主流のようですが、ボクはhomebrew-tapとして、すべてのツールのFormulaファイルをこのリポジトリに置くようにしています。

好みだとは思いますが、1つのリポジトリで管理しておいたほうが何かと便利だと思うので、homebrew-tapを作ることをオススメします。

k-nasa/homebrew-tap

homebrew-tapで無ければいけないのか?と思われそうな言い方をしてしまいましたがhomebrew-で始まっていればリポジトリ名は何でも大丈夫です。

homebrew-hogeだった場合brew tap リポジトリowner/hogeコマンドを叩いて登録します。 (ボクの場合brew tap k-asa/hoge)

Formulaファイルの詳細な書き方は説明しません、ググって下さい(というか説明できるほど知らない)

例としてはこんな感じです。

class Rgh < Formula
  # ツールの説明
  desc "Creates GitHub release and upload asset files"
  # ホームページのurl
  homepage "https://github.com/k-nasa/rgh"
  # バイナリファイルのダウンロード先
  url "https://github.com/k-nasa/rgh/releases/download/0.2.0/rgh_x86_64-apple-darwin.tar.gz"
  version "0.2.0"
  # バイナリファイルのハッシュ値
  sha256 "8ecc01c8be96c67c6091e9a5df2f442d01dedeb056c1e7a27f93a6b3288cfcc7"

  def install
    # こうしておけばダウンロードしたファイルを解凍していい感じに実行パスに置いてくれる
    bin.install "rgh"
  end

  test do
    system "#{bin}/rgh --version"
  end
end

今回作ったツールはGitHub releaseに実行バイナリがあるので、ダウンロードして、解凍して、パスを通す。ということをすればインストール終わりなので、Formulaファイルもシンプルです。 ツールによってはソースコードからビルドして、ビルドのために〇〇が必要なので依存関係を解決して〜と色々とやっている事もあります。

ハッシュ値は以下のようなコマンドで求めることができます。また、間違った値にしていても、brew installをしたときに、「なんかハッシュ値違うんだけど?こっちじゃない?」と教えてくれるので、間違っても問題ないです。

shasum -a 256 dist/prf_x86_64-apple-darwin.tar.gz

いざインストール!!

あとはbrew installするだけ!

brew tap <あなたのGitHub id>/<ツール名>
brew install <ツール名>

homebrewだけでいいのか?

macユーザーの人〜?

はーい。

じゃあそれ以外の人〜?

(しーん、、、)

となるような世の中であればhomebrewで公開するだけで良いとは思いますが、現実はそうではありません。Windowsの人,linuxの人などもいるでしょう。

しかし、それぞれのOSにhomebrew的な存在があるとは限りませんし、何より、個人でツールを作っているようなら、それぞれに公開するという手間は相当なもののはずです。

なので、GitHub releaseを活用して、windows, linux, mac用のバイナリをアップロードするようにしています。

release例

こうしておくことで、curlで落として解凍してpathを通すだけで使うことができます。

curl -L -o goku.tar.gz https://github.com/k-nasa/goku/releases/download/0.1.1/goku_x86_64-apple-darwin.tar.gz
tar -zxvf goku.tar.gz

# Move binary file to the path

brewに比べれば面倒くささは有るのですが、開発者の手間と使用者の手間を考えれば悪くないトレードオフだと思います。

バージョンアップのたびにバイナリアップロードするのか?

バージョンアップのたびにtarで固めて(固めなくてもいいけど)GitHub releaseにアップロードするのって面倒くさい!

しかも、複数OSに向けた実行ファイルがあるので、それが増えれば増えるほど手間になる。。。。ひーん。

複数OSに向けた実行バイナリ作成(クロスコンパイル)は一度調べれば次から手間ではないんですが、手動で毎回アップロードするのは非常に面倒くさいです。

なので、アップロードのためのツールを作りました。

github.com

コチラのツールのパクリです。

普段CLIツールはRustで書いているのですがCIでGitHub releaseまでやろうと考えると、アップロードツールもRustにしてたほうが良いかなーと思い、作りました。

rgh <タグ名> <ディレクトリ>

とすることで、ディレクトリ配下のファイルをすべてアップロードできます。

rust製のツールはこんな感じのMakefileを書いてクロスコンパイルしてアップロードするようにしています。

# x86_64-unknown-linux-gnu
# x86_64-apple-darwin
# x86_64-pc-windows-gnu

BIN_NAME:=prf.exe
CRATE_NAME:=prf
MISC:= README.md LICENSE
DIRNAME:=${CRATE_NAME}_${TARGET}

.PHONY: release_all
release_all:
    rm -rf dist/
    make release TARGET=x86_64-pc-windows-gnu    BIN_NAME=${BIN_NAME}
    make release TARGET=x86_64-apple-darwin      BIN_NAME=${CRATE_NAME}
    make release TARGET=x86_64-unknown-linux-gnu BIN_NAME=${CRATE_NAME}

.PHONY: release
release:
    cross build --target ${TARGET} --release # rustのクロスコンパイル
    mkdir -p ${DIRNAME}
    \
    cp ./target/${TARGET}/release/${BIN_NAME} ${DIRNAME}
    cp ${MISC} ${DIRNAME}
    \
    mkdir -p dist
    tar czf dist/${DIRNAME}.tar.gz ${DIRNAME}
    rm -rf ${DIRNAME}

そもそもFormulaを弄りたくない(今後の展望)

今後の展望ですが、ボクはいまバージョンアップのたびにFormulaファイルのダウンロードリンクとハッシュ値を手動で変更しています。

しかし、クソほど面倒くさい作業です。

なので、ココも自動化したいお気持ちです。来月中にそこら編もいい感じに出来るGitHub actionでも作りたい。

宣伝。作ったもの紹介

最後に、せっかくなので、今月に作ったツールの紹介をさせて下さい。

rghはもう紹介しましたが。

goku

vegetaというベンチマーカーが有るらしく、それならgokuもあっていいだろと思い作りました。

かめはめ波コマンドを打つことでサーバーにリクエストを投げることができます。

goku kamehameha -c 10 -n 10000 'http://127.0.0.1:8080'
# or goku attack -c 10 -n 10000 'http://127.0.0.1:8080'

完全にギャグツールです。がちょこちょこ便利にしていく予定です!

応援、Contributeお待ちしております!

rgh

先程も紹介したやつですね。

これはgokuをGitHub releaseにアップロードするためだけに作りました。

完全にgokuのおまけですが、star数はこっちのほうが高いという。謎。

prf

これは昨日作りました。

試したいPRブランチがあったときに

git fetch upstream pull/503/head:random_merge

このようなコマンドを打って、ローカルリポジトリにfetchしていたんですが、PR番号とブランチ名の2つの情報が必要になります。

これは地味に面倒です。 しかもブランチ名は <forkしたユーザーID>:<ブランチ名>となっているため、コピーボタンを押しても必要な箇所だけが、クリップボードにコピーされるわけではありません。

なので、PR番号とremoteの向き先を指定するとPRブランチをローカルにfetchするツールを作りました。

prf 55 upstream

こんな感じに

最後に

最後まで読んでくれて(最後を覗き見してくれて?)ありがとうございました。

なんかテーマのブレブレで「お前、結局何が伝えたいねん!」となる文章でしたが、許して下さい。

現在nasaGitHubのスターを集めることに固執しており、star欠乏症になっています。

今回紹介したツールのリンクを張っておくのでスターボタンをポチッと押して、やる気エナジーを下さい!(もちろん、「いいね!」と思ったらですよ)

github.com

github.com

github.com