目的
- バージョンが勝手に変わると、アプリケーション動作の保障ができないので、任意のバージョンのgoをインスコして使う
対象環境
- ビルド環境 (CircleCI)
- 実行環境 (AWS EC2)
今回ビルド環境と実行環境を分ける予定であるため、その両方への作業が必要ですが、今回は、ひとつめの、CircleCIでの適用作業をします。
利用するライブラリ
gvm: https://github.com/moovweb/gvm
gvm使ってみる
gvmはgolangのバージョン管理ライブラリです。
あまり気に入ってないけど、他にいいやつあったらおしえてほしいです。
自分のローカルで先にやっても良かったのですが、まだVM環境になってないので、CicleCIのコンテナでためしました。
CircleCIはデバッグ用途で、30min限定でコンテナにsshできます。
ぶっ壊れてもいいので、今回の作業以外でも色々遊ぶといいです。
現在使っているシェルを確認
$ echo $SHELL
/bin/bash
現在使っているgoのバージョンを確認
$ go version
go version go1.6.2 linux/amd64
gvmをインストール
$ bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
Cloning from https://github.com/moovweb/gvm.git to /home/ubuntu/.gvm
Created profile for existing install of Go at "/usr/local/go"
Installed GVM v1.0.22
Please restart your terminal session or to get started right away run
source /home/ubuntu/.gvm/scripts/gvm
上記出力の通り、以下を読み込んであげましょう。
source /home/ubuntu/.gvm/scripts/gvm
インストールgo一覧の確認
$ gvm list
gvm gos (installed)
system
現状システムインストールされたgoだけが表示されています。CircleCIで使われてるイメージはデフォルトでgo入ってるので。すなわちsystemですね。
gvmで任意のバージョンのgoインストール
gvm install go1.4 -B
Installing go1.4 from binary source
ちゃんと入ったようなので、先ほどインストールしたバージョンを使います
gvm use go1.4
Now using version go1.4
--defaultオプションをつけることもできます。たぶん基本的につけてつかうことになるでしょう。
goのバージョン確認
go version
go version go1.4 linux/amd64
ちゃんと1.4に変わってます。
元に戻す
gvm use system
ちなみにgvm経由でインストール可能なgoのバージョンの一覧は以下で得ることができます
gvm listall
バルスコマンド。インストールしたバイナリなどに加え、gvm自身も消え去ります。
けっきょく、${HOME}/.gvm (= ${GVM_ROOT}) をrm -rfすればおなじことです。
gvm implode
さて。もともと、やりたかったことは、CircleCIのビルド時のバージョン固定なので、これをcircle.ymlに落とし込みます。
CircleCIで任意のバージョンのgo使ってビルドする
Since the install is in the default location, GOROOT is not set. If you install your own version of Go, make sure to set the location in GOROOT
任意のバージョン使いたければちゃんと$GOROOTセットしてねって書いてるけど、これはgvmが勝手にやってくれてました。
echo $GOROOT
これはありがたいのでしたが、しかし、とてもありがた迷惑だったのが、$GOPATHの変更まで勝手にやっちゃってくれます。
echo $GOPATH
e.g.
/Users/a13533/.gvm/pkgsets/system/global
ここで結構はまります。
このGOPATHで頑張ってみてもいいのですが、circleciでは$HOME/.go_projectをGOPATHと扱うよう推奨してあります。推奨ではなくデフォルトですが、これをぼくは推奨として受け取ります。公式ドキュメントに沿っておいた方が後続のコーダーが理解しやすいとおもうので良。
a symlink is placed to your project’s directory at /home/ubuntu/.go_project/src/github.com/<USER>/<REPO_NAME>
なので、gvmが決めるGOPATHにこちらが指定したいGOPATHを追加する方法で解決しました。
そもそもどこで環境変数を上書きしているのかを探します。結論は、当該シェルのrcファイルを改変してくれていたのでした。
bashでインスコしたなら.bashrc、zshでインスコしたなら.zshrcの末尾に以下が追記されていると思います。
[[-s "$HOME/.gvm/scripts/gvm"]] && source "$HOME/.gvm/scripts/gvm"
このなかを追って読むと、デフォルトのpkgsetに書かれてある環境変数がロードされていることがわかるとおもいます。
そこで、デフォルトのpkgsetの設定ファイル末尾に追記してGOPATHをoverrideします。
注意: gvmのpkgsetやpkgenvを使ってGOPATH管理をしない前提です。
echo "export GOPATH; GOPATH=\"${GVM_ROOT}/pkgsets/${GVM_GOS}/global:${GOPATH}:${GOPATH_ORG}\"" >> ${GVM_ROOT}/environments/default
これで、こちらが設定したGOPATH_ORGがGOPATHに追加されるようになります。
環境変数がセットできない、cdできない...etc
ここまで話して、export GOPATH=$GOPATH:$追加パスでよくないか?と思われるかとおもいますが、
ひっかかりポイントとして、CircleCIは、各コマンドをサブシェルとして実行します。
どういうことかというと、
- export HOGE=fuga
- echo $HOGE
この結果は、設定した環境変数の中身は空になります。
なぜなら環境変数入れたあとに実行されるechoコマンドは別シェルで実行されるからです。
cdコマンドしてから何かを実行したいパターンでよくはまりそうです。以下も想定した通りにはいきません。
- cd path/to/repo
- sh ./hoge.sh
sh: ./hoge.sh: No such file or directory
流れるようにコマンドが実行されるかと思いきやここ要注意です。
さて。以下、今回やった範囲の設定です。
machine:
environment:
GOROOT: ""
PATH: "/usr/local/go/bin:/usr/local/go_workspace/bin:~/.go_workspace/bin:${PATH}"
GOPATH_ORG: "${HOME}/.go_workspace:/usr/local/go_workspace:${HOME}/.go_project"
GVM_GOS: "go1.6.2"
post:
- bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer) && source ${HOME}/.gvm/scripts/gvm
- gvm install ${GVM_GOS} -B
- gvm use ${GVM_GOS} --default
# `gvm` arbitrarily changes GOPATH value :( so forcibly override it with its original value.
- echo "export GOPATH; GOPATH=\"${GVM_ROOT}/pkgsets/${GVM_GOS}/global:${GOPATH}:${GOPATH_ORG}\"" >> ${GVM_ROOT}/environments/default
dependencies:
pre:
- go get github.com/golang/lint/golint
- sudo add-apt-repository ppa:masterminds/glide -y && sudo apt-get update && sudo apt-get install glide -y
- mkdir -p ${HOME}/.go_project/src/github.com/${CIRCLE_PROJECT_USERNAME}
- ln -sfnv ${HOME}/${CIRCLE_PROJECT_REPONAME} ${HOME}/.go_project/src/github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}
override:
- glide install
- cd ${HOME}/.go_project/src/github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME} && go build -v -race -o build/output
test:
override:
- cd ${HOME}/.go_project/src/github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME} && go test -v -race -cover `glide nv`
今回なかなか強引に対応しましたがほかにいいやりかたないかな。
ghq使っている自分としてはGOPATH問題がなかなかめんどうなためやりづらい。
普通に単体で使えばちゃんと便利なんだけど。