gvmの使い方をあまり理解していなかったので書き出してみた

gvmを使って環境を設定していたのだけど、gvmのことを理解できていなかったことがわかったので、備忘録にまとめておく。

## gvm自体のインストール

まずgvmをインストールするには `brew` を使えるようにして以下実行。

```bash
brew update
brew install mercurial 
```

その後更に以下を実行。

```bash
zsh < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
Cloning from https://github.com/moovweb/gvm.git to /home/hoge/.gvm
Created profile for existing install of Go at "/usr/lib/go"
Installed GVM v1.0.22

Please restart your terminal session or to get started right away run
 `source /home/hoge/.gvm/scripts/gvm`
```

 こうすると、自分の使っているシェルのrcファイル（自分の場合は~/.zshrc）に以下が書き込まれる。
 なのでsourceとか別シェルとか開く。

```bash 
 [[ -s "/home/hoge/.gvm/scripts/gvm" ]] && source "/home/hoge/.gvm/scripts/gvm"
```

## インストール可能な一覧の表示

まずgvmとして利用可能な環境を一覧表示する。
以下のような感じでいっぱい表示される。

```bash
% gvm listall

gvm gos (available)

   go1
   go1.0.1
   ...
   go1.10.5
   go1.11
   go1.11beta1
   go1.11beta2
   go1.11beta3
   go1.11rc1
   go1.11rc2
   go1.11.1
   go1.11.2
   ...
   release.r60.3   
```

## go1.10.5 をインストールしてみる

環境のインストールには、 `gvm install` を使う。

```bash
% gvm install go1.10.5
Installing go1.10.5...
 * Compiling...
go1.10.5 successfully installed!
```

とりあえずgvmで現時点で入れれる最新は `1.11.2` だったので、`gvm install go1.11.2` もしておいた。

## go1.11.2 をデフォルトの環境にしてみる

まず使える環境を一覧表示する。

```bash
% gvm list

gvm gos (installed)

   go1.10.5
   go1.11.2
   go1.9.7
   system
```

デフォルトをセットする場合はこう。

```bash
% gvm use go1.11.2 --default
% go version
go version go1.11.2 darwin/amd64
```

この状態で、別なシェルを開いて `go version` してみる。

```bash
% go version
go version go1.11.2 darwin/amd64 <-- ちゃんとデフォルトになっている
```

## 別な go version に切り替える

デフォルトにしないで使いたい場合、 `--default` をしなければいい。

```
% gvm use 1.10.5
Now using version go1.10.5
% gvm list

gvm gos (installed)

=> go1.10.5
   go1.11.2
   go1.9.7
   system

% go version
go version go1.10.5 darwin/amd64
```

ちゃんと `go1.10.5` に切り替わっているのがわかる。

## で、その時のgo環境って実際にはどこにある？

基本的に、 `~/.gvm` に存在する。

```bash
% echo $GOPATH
/<$HOME>/.gvm/pkgsets/go1.10.5/global
% echo $GOROOT
/<$HOME>/.gvm/gos/go1.10.5
```

## ここで疑問

僕の場合、この時点で `go1.10.5` で、さらに `$GOPATH` を切り替えたい場合はどうするのか・・・という疑問が出た

- npmならフォルダで分かれるからndenvでバージョンだけ切り替えれればいいけど・・・
- pyenvならpyenv virtualenv <python version> <venv name> とかでいいけど・・・

## そんなときの pkgset

direnvとかで最初やってたんだけど、そもそも、 `pkgset` , `pkgenv` というものがある。

### pkgset の一覧を見てみる

```
% gvm pkgset list

gvm go package sets (go1.10.5)

    global
```

まだglobalというpkgsetしかない。これがまた僕を混乱させたのだが後述。

### pkgsetを作ってみる

```
% gvm pkgset create unittest
% gvm pkgset list

gvm go package sets (go1.10.5)

    global
    unittest
```

unittestというpkgsetが出来たっぽい。

### では使ってみる    

```
% gvm pkgset use unittest
Now using version go1.10.5@unittest
% gvm pkgset list

gvm go package sets (go1.10.5)

    global
=>  unittest
```

矢印がついた。これを使うことが出来たらしい。

### ここでポイント

`pkgset list` の結果に、 `gvm go package sets (go1.10.5)` と出ている。
つまり今見ているのは、 `使っているgoバージョン(=1.10.5)において存在するpkgsetである` ということ。

ためしに、一度goのバージョン自体をgvmで切り替えてみる。

```
% gvm use go1.11.2
Now using version go1.11.2
% gvm pkgset list

gvm go package sets (go1.11.2)

=>  global
```

僕の場合 go1.11.2がdefaultなので矢印がついていると思われるが、要はこっちのgoバージョンには `pkgsetがない` ということになる。

また、`go1.10.5` 側で `gvm pkgset use unittest` をしたときに `go1.10.5@unittest`と表示されたのも少し頷ける。

( "@"の日常的な使い方的に `unittest@go1.10.5` な気もするが、おそらくgoライブラリの `path@version` と同じなのだろう)

またこのようにパッケージを切り替えながらgoの環境を見ていくと、こういう変化が起きている。

```bash
% gvm pkgset list

gvm go package sets (go1.10.5)

    global
=>  unittest <-- 今はunittestを使っている

% echo $GOPATH; echo $GOROOT; echo $PATH <-- GOPATH, GOROOT, PATHは？
/<$HOME>/.gvm/pkgsets/go1.10.5/unittest:/Users/yuzu/.gvm/pkgsets/go1.10.5/global
/<$HOME>/.gvm/gos/go1.10.5
/<$HOME>/.gvm/pkgsets/go1.10.5/unittest/bin: (長いので略)

% gvm pkgset use global
Now using version go1.10.5@global
% echo $GOPATH; echo $GOROOT; echo $PATH
/<$HOME>/.gvm/pkgsets/go1.10.5/global:/Users/yuzu/.gvm/pkgsets/go1.10.5/global
/<$HOME>/.gvm/gos/go1.10.5
/<$HOME>/.gvm/pkgsets/go1.10.5/global/bin: (長いので略)
```

つまり `$GOPATH` と `$PATH` が切り替わっている。goのbinaryとかを環境ごとに入れ替えることを想定して `$PATH` も切り替わっているのだろう。

### 環境を更に細かく設定したい場合

`pkgenv` を使う。

```bash
% gvm pkgenv unittest
export GVM_ROOT; GVM_ROOT="/<$HOME>/.gvm"
export gvm_go_name; gvm_go_name="go1.10.5"
export gvm_pkgset_name; gvm_pkgset_name="global"
export GOROOT; GOROOT="$GVM_ROOT/gos/go1.10.5"
export GOPATH; GOPATH="$GVM_ROOT/pkgsets/go1.10.5/global"
export GVM_OVERLAY_PREFIX; GVM_OVERLAY_PREFIX="${GVM_ROOT}/pkgsets/go1.10.5/global/overlay"
export PATH; PATH="${GVM_ROOT}/pkgsets/go1.10.5/global/bin:${GVM_ROOT}/gos/go1.10.5/bin:${GVM_OVERLAY_PREFIX}/bin:${GVM_ROOT}/bin:${PATH}"
export LD_LIBRARY_PATH; LD_LIBRARY_PATH="${GVM_OVERLAY_PREFIX}/lib:${LD_LIBRARY_PATH}"
export DYLD_LIBRARY_PATH; DYLD_LIBRARY_PATH="${GVM_OVERLAY_PREFIX}/lib:${DYLD_LIBRARY_PATH}"
export PKG_CONFIG_PATH; PKG_CONFIG_PATH="${GVM_OVERLAY_PREFIX}/lib/pkgconfig:${PKG_CONFIG_PATH}"
export gvm_pkgset_name="unittest"
export GOPATH; GOPATH="/<$HOME>/.gvm/pkgsets/go1.10.5/unittest:$GOPATH"
export PATH; PATH="/<$HOME>/.gvm/pkgsets/go1.10.5/unittest/bin:$PATH"
# Package Set-Specific Overrides
export GVM_OVERLAY_PREFIX; GVM_OVERLAY_PREFIX="${GVM_ROOT}/pkgsets/go1.10.5/unittest/overlay"
export PATH; PATH="/<$HOME>/.gvm/pkgsets/go1.10.5/unittest/bin:${GVM_OVERLAY_PREFIX}/bin:${PATH}"
export LD_LIBRARY_PATH; LD_LIBRARY_PATH="${GVM_OVERLAY_PREFIX}/lib:${LD_LIBRARY_PATH}"
export DYLD_LIBRARY_PATH; DYLD_LIBRARY_PATH="${GVM_OVERLAY_PREFIX}/lib:${DYLD_LIBRARY_PATH}"
```

## 他言語と比較するとgvmってこんな感じ

なので、他の言語と比較すると、こんな感じの対応関係になるかと。

| 言語   | バージョン自体を変える | その中でさらに環境を分ける                                   |
| ------ | ---------------------- | ------------------------------------------------------------ |
| python | pyenv install 3.6.6    | pyenv virtualenv 3.6.6 myvenv; pyenv shell(or global) myvenv |
| node   | ndenv install v11.2.0  | フォルダで分ければOKと思っている(違う？)                     |
| go     | gvm install 1.11.2     | gvm pkgset create mypkgset; gvm pkgset use mypkgset          |

ということで頭がスッキリしたので、明日から開発が多分もう少し捗ると思う。