課題
Goはビルドしてバイナリファイルのみを配布するので、それがどのバージョンであるか、いつビルドされたかの情報は重要です。バグの調査や、リリース時にそれが確認できないと、適切な対処ができないためです。
PHP,Python,Rubyなどはそのままコードが読めるので、そこに情報があれば見ることができますが、Goの場合、自分で準備します。
実装方法
Goでは、ビルドの引数-ldflagsを使って外から値を埋め込むことができます。
go build -ldflags "-X パッケージ名.変数=値"
これを使って、ビルドスクリプトから埋め込みます。簡単なコードとビルドスクリプトは以下のようなものです。
package main
import (
"fmt"
)
var (
version string
hash string
builddate string
goversion string
)
func main() {
fmt.Printf("version: %s (%s)\n", version, hash)
fmt.Printf("build at %s with %s\n", builddate, goversion)
}
#!/bin/bash
VERSION=0.1.0
HASH=$(git rev-parse --verify HEAD)
BUILDDATE=$(date '+%Y/%m/%d %H:%M:%S %Z')
GOVERSION=$(go version)
go build -ldflags "-X main.version=$VERSION -X main.hash=$HASH -X \"main.builddate=$BUILDDATE\" -X \"main.goversion=$GOVERSION\""
gitで管理している場合、git rev-parse --verify HEAD
で現在のコミットハッシュが取れるので、それを渡して埋め込みます。
オプションの書式が変わりました
以前のgoでは、変数と値の間はスペースでしたが、Go1.5では、書式が変更されて今後動かなくなる旨の警告がでます。-X
の変数名と値の間は=
にする必要があります。ビルドは通りますが、変えておいたほうがいいです。
# github.com/reiki4040/go-memo/inject_vars
link: warning: option -X main.version 0.1.0 may not work in future releases; use -X main.version=0.1.0
link: warning: option -X main.hash 73ce517b5b17ec2a1a0cd44fdce1a72712ce0a03 may not work in future releases; use -X main.hash=73ce517b5b17ec2a1a0cd44fdce1a72712ce0a03
link: warning: option -X main.builddate 2015/08/29 22:27:40 JST may not work in future releases; use -X main.builddate=2015/08/29 22:27:40 JST
link: warning: option -X main.goversion go version go1.5 darwin/amd64 may not work in future releases; use -X main.goversion=go version go1.5 darwin/amd64
埋め込む値がスペースを含む場合は、参考のリンクにあるように-X main.hoge="foo var"
ではなく、-X "main.hoge=foo var"
といった形になります。
結果
$ bash build.sh
$ ./inject_vars
version: 0.1.0 (73ce517b5b17ec2a1a0cd44fdce1a72712ce0a03)
build at 2015/08/29 22:27:40 JST with go version go1.5 darwin/amd64
これでビルド時に情報が埋め込めるので、実行オプション等で出力処理を作る必要はありますが、このバイナリいつのどのバージョン?といったことがなくなります。