前回の続き。保留していた Go 1.5 の Vendoring 機能について。
今回の調査も含めて以下のパッケージを作った
spiegel-im-spiegel/gcat は cat
コマンド相当の機能を持つコマンドラインツールで,内部で spiegel-im-spiegel/gutil パッケージを呼んでいる。 spiegel-im-spiegel/gutil パッケージは雑多な処理を集めたものだが,まだ作りかけ。とりあえず spiegel-im-spiegel/gcat で使うものだけを置いている。
まずはこれを導入してみる。 spiegel-im-spiegel/gutil を submodule にしてるのでちょっとウザいけどご勘弁を。あと,ユーザ名が長いのはホンマごめん。こんなことならもっと短い名前にするんだった。
C:>mkdir C:\workspace\gcat
C:>cd C:\workspace\gcat
C:\workspace\gcat>SET GO15VENDOREXPERIMENT=1
C:\workspace\gcat>SET GOPATH=C:\workspace\gcat
C:\workspace\gcat>go get -d github.com/spiegel-im-spiegel/gcat
# cd .; git --git-dir=C:\workspace\gcat\src\github.com\spiegel-im-spiegel\gcat/.git submodule update --init --recursive
No submodule mapping found in .gitmodules for path 'vendor/github.com/spiegel-im-spiegel/gutil'
package github.com/spiegel-im-spiegel/gcat: exit status 1
C:\workspace\gcat>pushd src\github.com\spiegel-im-spiegel\gcat
C:\workspace\gcat\src\github.com\spiegel-im-spiegel\gcat>git submodule init
Submodule 'vendor/github.com/spiegel-im-spiegel/gutil' (https://github.com/spiegel-im-spiegel/gutil.git) registered for path 'vendor/github.com/spiegel-im-spiegel/gutil'
C:\workspace\gcat\src\github.com\spiegel-im-spiegel\gcat>git submodule update
Cloning into 'vendor/github.com/spiegel-im-spiegel/gutil'...
remote: Counting objects: 25, done.
remote: Compressing objects: 100% (20/20), done.
remote: Total 25 (delta 10), reused 15 (delta 4), pack-reused 0
Unpacking objects: 100% (25/25), done.
Checking connectivity... done.
Submodule path 'vendor/github.com/spiegel-im-spiegel/gutil': checked out '7d271650d9937ef0e7b447aff5a55f410f2c9f89'
C:\workspace\gcat\src\github.com\spiegel-im-spiegel\gcat>popd
C:\workspace\gcat>go install -v ./...
github.com/spiegel-im-spiegel/gcat/vendor/github.com/spiegel-im-spiegel/gutil
github.com/spiegel-im-spiegel/gcat/internal/gcat
github.com/spiegel-im-spiegel/gcat/internal/facade
github.com/spiegel-im-spiegel/gcat
C:\workspace\gcat>echo Take the Go-lang! | bin\gcat.exe
Take the Go-lang!
導入時のフォルダ構成はこうなっている。
C:\workspace\gcat>tree .
C:\WORKSPACE\GCAT
├─bin
├─pkg
│ └─windows_amd64
│ └─github.com
│ └─spiegel-im-spiegel
│ └─gcat
│ ├─internal
│ └─vendor
│ └─github.com
│ └─spiegel-im-spiegel
└─src
└─github.com
└─spiegel-im-spiegel
└─gcat
├─internal
│ ├─facade
│ └─gcat
└─vendor
└─github.com
└─spiegel-im-spiegel
└─gutil
このフォルダ構成に対して main.go
の記述は以下のとおりである。
package main
import (
"os"
"github.com/spiegel-im-spiegel/gcat/internal/facade"
"github.com/spiegel-im-spiegel/gutil"
)
func main() {
cli := &gutil.CliContext{Reader: os.Stdin, Writer: os.Stdout, ErrorWriter: os.Stderr}
facadeCxt := &facade.Context{Cli: cli, CommandName: Name, Version: Version}
os.Exit(facadeCxt.Run(os.Args))
}
ポイントになるのは internal
フォルダと vendor
フォルダだ。もう少し詳しく見ていこう。
パッケージ外部からの呼び出しを禁止する Internal Packages
Internal Packages の仕組みは 1.4 のころから存在したが, 1.5 から GOPATH
配下のパッケージまで拡張された。
要するに internal
フォルダ以下のパッケージは外部から参照できない。これは再利用の難しいビジネスロジックを含むパッケージを配置する場合にはよい仕掛けである。 Internal Packages の制約から外すには internal
フォルダの外側にパッケージを再配置すればよい。
Vendoring 機能
環境変数 GO15VENDOREXPERIMENT
に 1 をセットすると Go 1.5 の Vendoring 機能が使える。
(追記 当初の予告通り Vendoring 機能は 1.6 から既定の機能になった。環境変数 GO15VENDOREXPERIMENT
をセットしなくても有効になる)
Vendoring 機能が有効な状態では vendor
フォルダが特別な意味を持つ。たとえば mypackage
パッケージに対して mypackage/vendor/vpackage
と配置した場合, import "vpackage"
と記述すれば mypackage/vendor
フォルダ以下の vpackage
を探してくれる。上述の spiegel-im-spiegel/gcat の場合は github.com/spiegel-im-spiegel/gutil
がこれにあたり,実体は github.com/spiegel-im-spiegel/gcat/vendor/github.com/spiegel-im-spiegel/gutil
にある。パッケージが見つからない場合は
C:\workspace\gcat>go install -v ./...
src\github.com\spiegel-im-spiegel\gcat\internal\gcat\catenate.go:4:2: cannot find package "github.com/spiegel-im-spiegel/gutil" in any of:
C:\workspace\gcat\src\github.com\spiegel-im-spiegel\gcat\vendor\github.com\spiegel-im-spiegel\gutil (vendor tree)
C:\Go\src\github.com\spiegel-im-spiegel\gutil (from $GOROOT)
C:\workspace\gcat\src\github.com\spiegel-im-spiegel\gutil (from $GOPATH)
という感じのエラーになり, Vendor tree → GOROOT
→ GOPATH
の順でパッケージを探していることが分かる。
ただしこの Vendoring 機能は実験段階であり,上手くいけば次かその次のバージョンでは既定で有効になるようだが,当面は様子見というところだろうか。