お題
Goにとってvendoring(versioningでもあるかな)は長年の課題であるようで、「GoにはGenericsがない!」と同様、ホットな議論が繰り返されてきた。
そうした議論の中で現在試せる最新のツールが「Go module」ということになる。
経験上、GoにはVer1.7と1.9とで、それぞれglide、depといったvendoringツールにお世話になってきた。
個人的にはこれらのツールに大きな不満はなかった(もちろんハマることはあったし、実務レベルで言うとどうにかならないかと思う課題もあったけど、そんなのはどのツールを使っても一緒)のだけど、やはり公式に(dep自体もGo自身にvendoring(versioning)の機能を持たせるための実験的なツール)ツールを提供してくれるなら、それを使いたい。
というわけで、Go moduleを使ってみようなんだけど、ついでなので、これまでに自分が使ってきたツールでの方法を振り返ってみる。
開発環境
# OS
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="17.10 (Artful Aardvark)"
# Golang
$ go version
go version go1.11.2 linux/amd64
バージョンの切り替えはgoenvで行っている。
実践
■GOPATHで依存パッケージ解決
試行ソースは下記。
https://github.com/sky0621/go-modules/tree/4f5e5a5187c79413550655c9620d539923c65615
環境変数でGOPATH
をセット
$ env | grep GOPATH
GOPATH=/work/src/golang
GOPATH
配下にソースを配置
$ pwd
/work/src/golang/src/github.com/sky0621/go-modules
$ tree
.
├── cmd
│ └── main.go
└── rootpackage.go
main.go
同じプロジェクトの別パッケージ「github.com/sky0621/go-modules
」の関数を実行する。
また、別プロジェクト(github.com/satori/go.uuid
)の関数を実行する。
※GOPATH
配下に↑が置かれるよう$ go get github.com/satori/go.uuid
しておく。
package main
import (
"fmt"
"github.com/sky0621/go-modules"
uuid "github.com/satori/go.uuid"
)
func main() {
fmt.Println("Hello, World!")
modules.SayBye()
u1 := uuid.Must(uuid.NewV4())
fmt.Printf("UUIDv4: %s\n", u1)
}
実行結果。
$ pwd
/work/src/golang/src/github.com/sky0621/go-modules/cmd
$ go run main.go
Hello, World!
Bye!
UUIDv4: 2a601fdb-fe9d-49e7-81b8-15b554d2e42e
備考
プロダクトでGOPATH
指定でのビルド・デプロイはしたことがない。
例えばKubernetesを使う(いや、使わなくてもDockerコンテナを使う)場合、dockerfile
にGOPATH
をセットする記述をして、外部依存パッケージを軒並みgo get
していく記述もする感じなのだろうか。で、最後にバイナリにする。
■Vendoring( glide )で依存パッケージ解決
例えば、GOPATH
配下にアプリが使っているパッケージが存在しなかった場合、go run
した時にエラーが起こる。
$ env | grep GOPATH
GOPATH=/work/src/golang
$ ll /work/src/golang/src/github.com/satori
ls: '/work/src/golang/src/github.com/satori' にアクセスできません: そのようなファイルやディレクトリはありません
$ pwd
/tmp/go-modules/cmd
$
$ go run main.go
main.go:8:2: cannot find package "github.com/satori/go.uuid" in any of:
/home/koge/.goenv/versions/1.11.2/src/github.com/satori/go.uuid (from $GOROOT)
/work/src/golang/src/github.com/satori/go.uuid (from $GOPATH)
main.go:6:2: cannot find package "github.com/sky0621/go-modules" in any of:
/home/koge/.goenv/versions/1.11.2/src/github.com/sky0621/go-modules (from $GOROOT)
/work/src/golang/src/github.com/sky0621/go-modules (from $GOPATH)
glide
のインストールと適用
インストール
$ curl https://glide.sh/get | sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 4833 100 4833 0 0 1611 0 0:00:03 0:00:03 --:--:-- 1294
〜〜〜 省略 〜〜〜
Downloading https://github.com/Masterminds/glide/releases/download/v0.13.2/glide-v0.13.2-linux-amd64.tar.gz
glide version v0.13.2 installed successfully
適用
$ pwd
/tmp/go-modules
$
$ glide init
[INFO] Generating a YAML configuration file and guessing the dependencies
〜〜〜 省略 〜〜〜
[INFO] Writing updates to configuration file (glide.yaml)
[INFO] You can now edit the glide.yaml file.:
[INFO] --> For more information on versions and ranges see https://glide.sh/docs/versions/
[INFO] --> For details on additional metadata see https://glide.sh/docs/glide.yaml/
生成ファイルの確認
$ tree
.
├── cmd
│ └── main.go
├── glide.yaml
└── rootpackage.go
glide.yaml
の中身
$ cat glide.yaml
package: .
import:
- package: github.com/satori/go.uuid
version: ~1.2.0
- package: github.com/sky0621/go-modules
依存パッケージのvendoring
$ glide up
[INFO] Downloading dependencies. Please wait...
[INFO] --> Fetching github.com/sky0621/go-modules
[INFO] --> Fetching github.com/satori/go.uuid
[INFO] --> Detected semantic version. Setting version for github.com/satori/go.uuid to v1.2.0
[INFO] Resolving imports
[INFO] Downloading dependencies. Please wait...
[INFO] Setting references for remaining imports
[INFO] Exporting resolved dependencies...
[INFO] --> Exporting github.com/sky0621/go-modules
[INFO] --> Exporting github.com/satori/go.uuid
[INFO] Replacing existing vendor dependencies
[INFO] Project relies on 2 dependencies.
glide.lock
が生成され、vendor
ディレクトリ配下に依存パッケージのソースが取得されている。
$ tree
.
├── cmd
│ └── main.go
├── glide.lock
├── glide.yaml
├── rootpackage.go
└── vendor
└── github.com
├── satori
│ └── go.uuid
│ ├── LICENSE
│ ├── README.md
│ ├── codec.go
│ ├── codec_test.go
│ ├── generator.go
│ ├── generator_test.go
│ ├── sql.go
│ ├── sql_test.go
│ ├── uuid.go
│ └── uuid_test.go
└── sky0621
└── go-modules
├── README.md
├── cmd
│ └── main.go
└── rootpackage.go
glide.lock
$ cat glide.lock
hash: 450d4cce664d8e157d796b280456c6e33dbcf1a6529a42bd413a990516ba6bef
updated: 2018-11-19T01:58:50.856499847+09:00
imports:
- name: github.com/satori/go.uuid
version: f58768cc1a7a7e77a3bd49e98cdd21419399b6a3
- name: github.com/sky0621/go-modules
version: 4f5e5a5187c79413550655c9620d539923c65615
testImports: []
このファイルをソース管理しておけば、何かの拍子に依存関係の問題でビルドがこけても、正常だった頃に戻すことが可能。
※glide.yaml
だけだと(設定次第で)マイナーバージョンないしパッチバージョンはglide up
を叩いた時点のバージョンに上がってしまうので、依存関係の修復が困難になるケースがある。
さて動作確認
GOPATH
外でトライ
$ pwd
/tmp/go-modules/cmd
$
$ go run main.go
main.go:8:2: cannot find package "github.com/satori/go.uuid" in any of:
/home/koge/.goenv/versions/1.11.2/src/github.com/satori/go.uuid (from $GOROOT)
/work/src/golang/src/github.com/satori/go.uuid (from $GOPATH)
main.go:6:2: no Go files in /work/src/golang/src/github.com/sky0621/go-modules
あれっ???
えーと、どうやら、glide
ではソースがGOPATH
配下にないと、結局vendoringできない様子。
参照:https://qiita.com/mom0tomo/items/b66203b2718dd2626fd3#glideで何が問題になるのか-confused
GOPATH
内でトライ
$ pwd
/work/src/golang/src/github.com/sky0621/go-modules/cmd
$
$ go run main.go
Hello, World!
Bye!
UUIDv4: 46225e42-8129-47de-b284-146d16d7a948
いけた。
一応、GOPATH
配下にmain.go
でインポートしている「github.com/satori/go.uuid
」が存在しないことは確認したけど、なんだか結局GOPATH
に依存するのか。
試行ソースは下記。
https://github.com/sky0621/go-modules/tree/94e18719957dc74129667a0fb95b286e9169f08a
■Vendoring( dep )で依存パッケージ解決
dep
のインストールと適用
インストール
$ curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
〜〜〜 省略 〜〜〜
Setting executable permissions.
Moving executable to /work/src/golang/bin/dep
GOPATH
外で適用
$ pwd
/tmp/go-modules
$
$ dep init
init failed: unable to detect the containing GOPATH: /tmp/go-modules is not within a known GOPATH/src
う〜ん、やっぱりdep
もGOPATH
内でないとダメなのか。
GOPATH
内で適用
$ pwd
/work/src/golang/src/github.com/sky0621/go-modules
$
$ dep init
Using ^1.2.0 as constraint for direct dep github.com/satori/go.uuid
Locking in v1.2.0 (f58768c) for direct dep github.com/satori/go.uuid
Gopkg.toml
及びGopkg.lock
が生成され、vendor
ディレクトリ配下に依存パッケージのソースが取得されている。
$ tree
.
├── Gopkg.lock
├── Gopkg.toml
├── cmd
│ └── main.go
├── rootpackage.go
└── vendor
└── github.com
└── satori
└── go.uuid
├── LICENSE
├── README.md
├── codec.go
├── generator.go
├── sql.go
└── uuid.go
さて、動作確認
$ pwd
/work/src/golang/src/github.com/sky0621/go-modules/cmd
$
$ go run main.go
Hello, World!
Bye!
UUIDv4: b5e4a50f-b1bc-4044-8bc5-cea56d770992
試行ソースは下記。
https://github.com/sky0621/go-modules/tree/0e9b65282b80d3064528baf13c464e35e95bb573
まとめ
時間切れとなったので、Go moduleを試すのは、また次回。
ちなみに、実際にソース書いて試してというものではないけど、Goとバージョニングに関する歴史的な経緯も含めた情報はここに記載がある。(英語)
↑を翻訳したQiita記事もある。すごいね。