Goとvendoring

# お題
Goにとってvendoring（versioningでもあるかな）は長年の課題であるようで、「GoにはGenericsがない！」と同様、ホットな議論が繰り返されてきた。
そうした議論の中で現在試せる最新のツールが「[Go module](https://github.com/golang/go/wiki/Modules)」ということになる。

経験上、GoにはVer1.7と1.9とで、それぞれ[glide](https://github.com/Masterminds/glide)、[dep](https://github.com/golang/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](https://github.com/syndbg/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`しておく。

```go
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](https://github.com/Masterminds/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`の中身

```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](https://github.com/golang/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とバージョニングに関する歴史的な経緯も含めた情報は[ここ](https://research.swtch.com/vgo-intro)に記載がある。（英語）
↑を翻訳した[Qiita記事](https://qiita.com/nekketsuuu/items/60634417e6279ccfd95b#go-module-%E3%81%AE%E5%AE%9A%E7%BE%A9)もある。すごいね。