GoのCLIツールとgo get

goでネストしたパッケージの下にCLIツールを作る場合、go get時の挙動がよくわからなかったので試した。

gocmdtest
├── go.mod
├── go.sum
└── tools
   ├── gocmdtestx
   │  └── cmd
   │     └── gocmdtestx.go # package main
   └── gocmdtesty
      └── cmd
         └── gocmdtesty.go # package main

このようなディレクトリ構造を例にする。

go get のパスをネストする・しないで何が変わるのか

この gocmdtest は、Go Modules的にはひとつのモジュールだが、次の2つの go get にどのような違いがあるか?

go get github.com/castaneai/gocmdtest 
go get github.com/castaneai/gocmdtest/tools/gocmdtestx/cmd

まず、パスを掘らずに一番上位だけをgo getしてみる。

$ go get github.com/castaneai/gocmdtest  
package github.com/castaneai/gocmdtest: no Go files in $GOPATH/src/github.com/castaneai/gocmdtest

$ ls $GOPATH/src/github.com/castaneai/gocmdtest
gocmdtest

なるほど。一番上をgo getしただけでは、tools/以下まで一緒にビルドされることはない。ただ、リポジトリ全体は$GOPATH/src/...以下にcloneされていた。

では、次はパスを掘ったgo getしてみる。

$ go get github.com/castaneai/gocmdtest/tools/gocmdtestx/cmd

$ ls $GOPATH/src/github.com/castaneai/gocmdtest
gocmdtest

$ ls $GOPATH/bin
cmd

だいたい最初のgo getと同じだが、$GOPATH/bin にcmdという名前でgocmdtestxの実行ファイルがビルドされていた。 なるほど。実行ファイルを $GOPATH/bin に配置したい場合は、こうやってフォルダを掘ってgo getすればいいということか〜。

実行ファイルの名前について

cmd/ をそのまま package main にしてしまうと、実行ファイル名が cmd になってしまうので、cmd/ツール名 までフォルダを掘ったほうがいいということだな。

golang-standards/に同じ内容が書かれていた。

https://github.com/golang-standards/project-layout/blob/master/cmd/README.md