Try Golang! “go get”でツールを配布する際に気を付けるべきこと
How to release Golang tools with “go get”
これまで、Goで書いたツールを配布する際は、バイナリをGitHubのリリースページから落としてもらっていたのですが、実はGoの標準コマンドであるgo get
を使えば、ダウンロードだけでなくインストールまでしてくれるということを今更ながら知りました。
もちろんこのことはgo get
のドキュメントに記載されているのですが、じゃぁgo get
を使ってツールを配布する時には、何に気をつけたらいいの?って話は、意外に記事になっていない気がしたので、今回はそれについてさらりと書いてみたいと思います。
“go get”のおさらい
おなじみのgo get
はGitHubなどのリポジトリにあるGo言語で書かれたライブラリやツール類をローカル環境にget
してくるコマンドです。上述したとおり、特にオプション指定しなければ、ダウンロード後にインストール処理が走ります。
まずは一番シンプルな形について見てみましょう。ルート直下にmain.go
があるリポジトリをgo get
で取得してみます。
(repository root)
|- main.go
go get
コマンドはこんな感じ。
$ go get github.com/<owner>/<repository>
すると、ファイルのダウンロード後、$GOPATH/bin
以下にリポジトリ名のバイナリファイルが作成されます。$GOPATH/bin
をちゃんとPATHに設定していれば、すぐにコマンドを利用することができます。
続いて、cmd
の下にmain.go
を配置しているタイプのリポジトリ。ライブラリとしての用途がメインで、コマンドとしての機能も提供しているリポジトリはこの形式を取ることが多いですね。
(repository root)
|- cmd/<repository>
| |- main.go
|- ...
この形式のリポジトリの場合は、下記のようにgo get
してもらうことになります。
$ go get github.com/<owner>/<repository>/cmd/<repository>
これで、先ほどと同様に$GOPATH/bin
の下にリポジトリ名のバイナリファイルが作成されます。なお、この時のバイナリファイル名はmain.go
が格納されているディレクトリ名になるので、必ずしもリポジトリ名と一致させなくても構いません。
“go get”でのツール配布時に気を付けるべきこと
さて、上の例では、依存パッケージの有無については触れませんでしたが、依存パッケージがある場合はどうなるでしょうか。
実は、go get
は依存パッケージがある場合でも、自動でそれらを落としてインストールを進めてくれます。しかし、特に何も考慮しないと、いずれも各パッケージの最新バージョンがダウンロードされてしまいます。
依存パッケージのバージョンを指定したい場合、Go標準の依存パッケージ管理手法であるvendoring機能を使用します。
(repository root)
|- vendor
| |- github.com
| |- ...
|- main.go
ここまでは当たり前の話なのですが、気を付けないといけないのは、ちゃんとvendor
をリポジトリにコミットすることです(gitignoreしない)。depなどで管理している場合、Gopkg.lock
とGopkg.toml
だけリポジトリに入れてvendor
自体はリポに入れないケースをたまに見かけますが、go get
でインストールさせたい場合は原則入れてあげましょう。
それこそdep本体もvendor
をコミットしていますし、クロスコンパイルツールであるgoxや、パスワード管理ツールのgopassなんかも同様の手法をとっています。
なお、depのドキュメントでは、vendor
をコミットするかしないかは、利用者の考え次第だと記載されています。ライブラリとしての用途しかない場合や、go get
以外で配布するようなケースでは、メリット・デメリットを考えて判断してもらえばよいのかなと思います。
気を付ける点はあるものの、さらりとgo get
と書いてもらうだけでツールを配布できるのはとてもお手軽です。もちろん利用者側の環境にGoがインストールされている必要がありますが、開発者向けのツール配布はこれで十分な気がします。
ちなみに、depの代わりに標準になろうとしているvgoは、Goの標準として入るらしいので、vendorがリポジトリになくてもgo get
の際に考慮されたりするのかもしれませんね。