若是你曾經運行過 docker version
, 就會發現它提供了不少信息:linux
PS C:\Users\tzh> docker version
Client: Docker Engine - Community
Version: 19.03.4
API version: 1.40
Go version: go1.12.10
Git commit: 9013bf5
Built: Thu Oct 17 23:44:48 2019
OS/Arch: windows/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 19.03.4
API version: 1.40 (minimum version 1.12)
Go version: go1.12.10
Git commit: 9013bf5
Built: Thu Oct 17 23:50:38 2019
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v1.2.10
GitCommit: b34a5c8af56e510852c35414db4c1f4fa6172339
runc:
Version: 1.0.0-rc8+dev
GitCommit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657
docker-init:
Version: 0.18.0
GitCommit: fec3683
複製代碼
對於編譯好的二進制文件而言, 獲取版本信息是很是重要的. 儘量地提供詳細信息, 有利於後期的維護和排錯.git
對於版本信息等, 有兩種方式, 一種從外部獲取, 好比配置文件等, 另外一種從源代碼中獲取, 將配置信息寫死在源代碼中.github
這兩種都不太好, 好比編譯時間就不太好肯定. 最好是能在 go build 時肯定這些信息.golang
幸虧, go build
提供了一個選項叫作 -ldflags '[pattern=]arg list'
.web
-X importpath.name=value
Set the value of the string variable in importpath named name to value.
This is only effective if the variable is declared in the source code either uninitialized
or initialized to a constant string expression. -X will not work if the initializer makes
a function call or refers to other variables.
Note that before Go 1.5 this option took two separate arguments.
複製代碼
這使得咱們能夠在編譯生成二進制文件時, 指定某些變量的值.docker
好比咱們有個文件是 company/buildinfo
包的一部分.shell
package buildinfo
var BuildTime string
複製代碼
運行 go build -ldflags="-X 'company/buildinfo.BuildTime=$(date)'"
會記錄編譯時間, 將 BuildTime
的值設置爲編譯時的時間, 即從 $(date)
中獲取的時間.express
參考:json
新增 pkg/version
包, 用於獲取版本信息.windows
package version
// 這些值應該是從外部傳入的
var (
gitTag string = ""
gitCommit string = "$Format:%H$" // sha1 from git, output of $(git rev-parse HEAD)
gitTreeState string = "not a git tree" // state of git tree, either "clean" or "dirty"
buildDate string = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
)
複製代碼
package version
import (
"fmt"
"runtime"
)
// 構建時的版本信息
type VersionInfo struct {
GitTag string `json:"git_tag"`
GitCommit string `json:"git_commit"`
GitTreeState string `json:"git_tree_state"`
BuildDate string `json:"build_date"`
GoVersion string `json:"go_version"`
Compiler string `json:"compiler"`
Platform string `json:"platform"`
}
func (info VersionInfo) String() string {
return info.GitTag
}
func Get() VersionInfo {
return VersionInfo{
GitTag: gitTag,
GitCommit: gitCommit,
GitTreeState: gitTreeState,
BuildDate: buildDate,
GoVersion: runtime.Version(),
Compiler: runtime.Compiler,
Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH),
}
}
複製代碼
主要定義了一個結構體, 保持版本信息.
有些信息能夠經過 runtime 獲取, 有些是編譯時傳進來的.
這裏沒有明確的版本號, 而是使用 git tag 做爲版本標籤.
最後, 定義一個命令 version
.
package cmd
import (
"encoding/json"
"fmt"
"github.com/spf13/cobra"
"tzh.com/web/pkg/version"
)
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version info of server",
Long: "Print the version info of server",
Run: func(cmd *cobra.Command, args []string) {
printVersion()
},
}
func printVersion() {
info := version.Get()
infoj, err := json.MarshalIndent(&info, "", " ") // 加一點縮進
if err != nil {
fmt.Printf("遇到了錯誤: %v\n", err)
}
fmt.Println(string(infoj))
}
複製代碼
別忘了使用 AddCommand
添加子命令.
// 初始化, 設置 flag 等
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "./conf/config.yaml", "config file (default: ./conf/config.yaml)")
rootCmd.AddCommand(versionCmd)
}
複製代碼
由此, 代碼基本已經改完了, 還剩下最後一點, 修改 Makefile 文件, 以便簡化操做過程.
SHELL := /bin/bash
BASEDIR = $(shell pwd)
# build with version infos
versionDir = "tzh.com/web/pkg/version"
gitTag = $(shell if [ "`git describe --tags --abbrev=0 2>/dev/null`" != "" ];then git describe --tags --abbrev=0; else git log --pretty=format:'%h' -n 1; fi)
buildDate = $(shell TZ=UTC date +%FT%T%z)
gitCommit = $(shell git log --pretty=format:'%H' -n 1)
gitTreeState = $(shell if git status|grep -q 'clean';then echo clean; else echo dirty; fi)
ldflags="-w -X ${versionDir}.gitTag=${gitTag} -X ${versionDir}.buildDate=${buildDate} -X ${versionDir}.gitCommit=${gitCommit} -X ${versionDir}.gitTreeState=${gitTreeState}"
all: gotool build
build:
go build -ldflags ${ldflags} ./
run:
go run -ldflags ${ldflags} ./
docker:
go run -ldflags ${ldflags} ./ -c ./conf/config_docker.yaml
複製代碼
首行定義了運行的 shell, 默認是 /bin/sh
, 這裏改爲了更經常使用的 /bin/bash
.
而後, 就是定義了一大堆須要的參數. 在運行 go build
的時候添加了參數 -ldflags ${ldflags}
.
如此, 之後只要使用 make build
就能生成具備版本信息的二進制文件了.
編譯好以後, 能夠運行 ./web version
查看具體的版本信息.
經過爲編譯時添加額外信息, 能夠生成更具交互性的二進制文件. 同時, 也能體會到 Makefile 帶來的便捷.
做爲版本 v0.12.0