Go 1.11 Modules

# お題
Go 1.11 における「Modules」は Go 1.12 での完成を目指す実験的なバージョン管理機能。
[公式のwiki](https://github.com/golang/go/wiki/Modules#quick-start-example)に従い、試してみよう。

# 開発環境
### # 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)で行っている。

# 実践

## ■クイックスタートサンプルをトレース

### 1)`GOPATH`外にプロジェクトを作成

```
$ env | grep GOPATH
GOPATH=/work/src/golang
$
$ mkdir -p /tmp/scratchpad/hello
$ cd /tmp/scratchpad/hello
```

### 2)Modulesの初期化

```
$ go mod init github.com/you/hello
go: creating new go.mod: module github.com/you/hello
```

`go.mod`が出来る。

```
$ ll
-rw-r--r-- 1 koge koge   28 11月 19 09:30 go.mod
$
$ cat go.mod 
module github.com/you/hello
```

### 3)外部パッケージのimportを含むソースを作成

```go
$ cat <<EOF > hello.go
> package main
> 
> import (
>     "fmt"
>     "rsc.io/quote"
> )
> 
> func main() {
>     fmt.Println(quote.Hello())
> }
> EOF
```

### 4)ビルド

```
$ go build
```

すると、実行ファイル「`hello`」の他に、`go.sum`というファイルも作られる。

```
$ ll
-rw-r--r-- 1 koge koge   57 11月 19 09:35 go.mod
-rw-r--r-- 1 koge koge  499 11月 19 09:35 go.sum
-rwxr-xr-x 1 koge koge 2.2M 11月 19 09:35 hello
-rw-r--r-- 1 koge koge  102 11月 19 09:33 hello.go
```

```
$ cat go.sum 
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3Y=
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
```

そして、先ほどまではなかった「quote」パッケージに関する記述が`go.mod`に増えている。
`go build`時に勝手にソースから依存パッケージを抽出してくれる様子。

```
$ cat go.mod 
module github.com/you/hello

require rsc.io/quote v1.5.2
```

### 5)実行

```
$ ./hello 
こんにちは世界。
```

## ■コンセプト

### モジュール
「Modules」は関連するGoパッケージの集合であり、それらを１つの単位としてバージョニングしたもの。
目的は、依存関係を正確に記録しておき、再現可能なビルドを作成できるようにすること。

「Modules」は[セマンティックバージョニング](https://semver.org/)する必要がある。
先頭は「v」であり、「【メジャーバージョン】.【マイナーバージョン】.【パッチバージョン】」の形式である。
（例：「v0.1.0」、「v1.2.3」）

### go.mod
モジュールは、あるディレクトリに「`go.mod`」ファイルを持つGoソースのツリーとして定義される。
<b>モジュールのソースコードは、`GOPATH`の外部に配置されている必要がある。</b>

モジュールの例：

```
module github.com/my/thing

require (
    github.com/some/dependency v1.2.3
    github.com/another/dependency/v4 v4.0.0
)
```

`go.mod`には、「module」、「require」、「exclude」、「replace」の４つのディレクティブがある。
「module」は、そのモジュールを定義するパス。
「require」は、そのモジュール内のソースがimportする外部パッケージ。
「exclude」と「replace」は、メインモジュールをビルドする時に無視されるパッケージ。
例えば、「[https://github.com/sky0621/go-modules](https://github.com/sky0621/go-modules)」を`git clone`してモジュール化する場合、あらかじめ「`【適当なパス】/github.com/sky0621`」というディレクトリを掘っておき、その下に`git clone`する。
それからそのプロジェクト内に移動してモジュール初期化。

```
$ cd go-modules/
$
$ pwd
/work/src/gomodule/github.com/sky0621/go-modules
$
$ go mod init github.com/sky0621/go-modules
go: creating new go.mod: module github.com/sky0621/go-modules
$
$ cat go.mod 
module github.com/sky0621/go-modules
```

### バージョンについて
Goのモジュールには従うべきルールがある。

- セマンティックバージョニングであること
- バージョン「v2」以上の場合はモジュールパスとimportパスに「v2」を含めること
- バージョン「v0」ないし「v1」の場合はモジュールパス、importパスにバージョンを含めないこと

## ■モジュールの使い方

### インストール
以下参照。

- https://golang.org/dl/
- https://golang.org/doc/install/source

### アクティベート
以下いずれか。

- 環境変数「`GO111MODULE`」をアンセット後、`GOPATH`以外のパスに`go.mod`ファイルを配置して`go`コマンド実行
- 「`GO111MODULE=on`」を環境変数にセットして`go`コマンド実行

# まとめ
だいぶ端折ったけど、ひとまず必要最低限は書いたかな。