Homebrewに自作コマンドを登録して使えるようにする【Go編】

Goの勉強も兼ねて自作コマンドを作ろうと思った。
その前に作ったコマンドを公開して誰でもインストールできるようにしたかったので、その備忘録。

## 前提条件
下記の環境が整っていることとする。

* homebrew (v2.1.0)
* go (v1.12.3)
* githubのアカウント

## 大まかな流れ


1. Goで実行ファイルを作成する
2. Githubにソース管理用のリポジトリを作る
3. リリース作業をする
4. Githubにインストール用のリポジトリを作る
5. `Formula`ファイルを作成する
6. `brew tap` / `brew install`でコマンドをインストールする
7. コマンド実行

## やっていき

### Goで実行ファイルを作成する
とりあえず動けば何でも良いので、実行すると`hello, world`と出力する`hello`コマンドを作る。
プログラムは以下。

```golang
package main

import "fmt"

func main() {
	fmt.Println("hello, world")
}
```

`go build`でビルドして実行ファイルを作成する。
実行ファイル名は実行時に指定するコマンド名と同じにする。

```shell
go build -o hello
```

この時、後で使うのでsha256のハッシュ値を取得しておく。

```shell
shasum -a 256 hello
# 2dbc3742be9c77c4e3bb30c99790699b7d9c3cfa7895ecc9c1e1663f9507fddd ←こんなのが出力される
```

### Githubにソース管理用のリポジトリを作る
Githubにリポジトリを作成し、先程作ったファイルをpushする。この時、**実行ファイルはpushしなくてよい**。
リポジトリ名は何でも良いが、ここではコマンド名と同じで一旦`hello`とする。こんな感じで。

https://github.com/katsumitakano/hello

### リリース作業をする
作った実行ファイルをリリースする作業をする。
下図の`release`に行くと「Create a new release」というボタンがあるのでそれを押すとリリース情報の入力画面に行く。
（UIが変わって、`release`ボタンは今は右サイドバーにあるかも）

![hello 2019-04-13 14-17-51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27623/be9366ce-c1f3-6a55-8603-d6cdfdbb78f5.png)

タグバージョンやタイトルなどの情報は、一旦適当に入れておく。
大事なのは下図の赤枠の部分で、ここをクリックして先程作った実行ファイルを登録する。

![homebrew-hello 2019-04-13 14-24-42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27623/a35538a4-83de-35c1-894f-da7a54fab2ca.png)

終わったら「Publish release」をクリックする。
リリース情報が表示されるので、実行ファイル部分のURLを控えておく（後で使う）。

![hello 2019-04-13 14-37-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27623/df4d64ff-6d77-6aac-bf9f-7c3c3118f460.png)

### Githubにインストール用のリポジトリを作る

ソース管理とは別に**Homebrewでインストールできるようにするリポジトリ**を作成する。
このリポジトリの命名ルールは決まっており、必ず`homebrew-${コマンド名}`とする。
今回だと`homebrew-hello`となる。こんな感じ。

https://github.com/katsumitakano/homebrew-hello

Github上から適当に作成したら次に進む。

### `Formula`ファイルを作成する
一番厄介そうな部分。やりたきことは「これこれこういう形式でインストールしますよ」という手順を書いた`Formula`ファイルを作成し、それを先程作った**インストール用リポジトリ**に登録すると、あとはHomebrew側がそれを見てよしなにインストール作業をしてくれるという仕組みになってるっぽい。

ということで先程作ったリポジトリに`Formula`を置きたい。
リポジトリをクローンする必要があるが、実はこれは`brew tap`コマンドでできる。

`brew tap`を実行すると`/usr/local/Homebrew/Library/Taps/${Githubのアカウント名}`配下に先程のリポジトリがクローンされている。
そこに`Formula`ファイルを配置する必要があるが、これも`brew create`コマンドで実行できる。
まとめると、***下記のコマンドを打ってくれ***。

```shell
brew tap katsumitakano/hello # アカウント名とコマンド名の部分は適宜読み替える
brew create --tap katsumitakano/hello
```

そうすると`Formula`ファイルの雛形がエディタで開くので、必要な情報を入力する。
下記をコピペして、urlとsha256の値だけ読み替えてもらえれば動くはず。

```ruby
class Hello < Formula
  desc "コマンドの説明" # ←コマンドに関する説明を記述する
  homepage "https://github.com/katsumitakano/hello" # ←何でも良いがGithubのリポジトリを書くことにする
  url "https://github.com/katsumitakano/hello/releases/download/v0.0.1/hello" # ←コピーしておいた実行ファイルのURL
  sha256 "2dbc3742be9c77c4e3bb30c99790699b7d9c3cfa7895ecc9c1e1663f9507fddd" # ←実行ファイルのsha256の値

  def install
    bin.install "hello" # ←実行ファイルを実行Pathに配置するよの意味
  end

  test do
    system "true" # ←本来はここにテストを書くが今回は一旦無視
  end
end
```

終わったらcommitしてpushし、リポジトリに反映させる。

### `brew tap` / `brew install` でコマンドをインストールする
一旦tapし直してリポジトリを最新化させる。その後installコマンドを打つことでコマンドが実行できるようになる。
本来なら`brew install ${コマンド名}`でインストールできるはずだが、今回作ったhelloコマンドはhomebrewの公式にすでに同じ名前のものが存在しているため、普通にやるとそちらがインストールされてしまう。

その場合はインストール時にどのコマンドをインストールするか直接指定する。
形式は`${tap元}/${Formula名}`になっている。今回だと`katsumitakano/hello/hello`になる（感じ取ってくれ）。

```bash
brew untap katsumitakano/hello
brew tap katsumitakano/hello
brew install katsumitakano/hello/hello
```

## コマンド実行
```bash
> hello
hello, world
```

動いた。

## まとめ
今回はとりあえず動かすことが目的だったので、実行ファイルの置き方とか、Formulaファイルの書き方とか、あまり正しくはないかもしれない。
自分と周囲の人が気軽に使えるようにする場合の最小構成ということで。

リリース作業を自動化する[goreleaser](https://github.com/goreleaser/goreleaser)というものがあるので、最終的にはそれを使うのが良さそう。

## 参考資料
[Goで自作コマンドを作成し、homebrewで公開する](https://qiita.com/kcwebapply/items/4777dfc9151ebb3e8a19)
[Homebrewで自作のプロジェクト（ライブラリ）を公開する](https://qiita.com/mountcedar/items/f10161d4e483aa8c1283)
[HomeBrewで自作ツールを配布する](https://deeeet.com/writing/2014/05/20/brew-tap/)
[brew tapでGolangの自作アプリケーションを公開する方法](https://tomokazu-kozuma.com/how-to-release-golangs-homebrew-application-with-brew-tap/)
[goでcliのコマンドを作ってhomebrewで使えるようにしてみた](https://qiita.com/sakajunquality/items/48b5138986056eb4b49c)
[brew tapとは](https://qiita.com/saa/items/85ed5e914d424fbf9fd6)