一、参考资料日期:2022-01-25 11:02:18
作者:JonathanJiang
此文章为个人笔记,有误请指正,推荐读者查看参考资料的原文
- Golang中管理程序的版本信息
- Golang程序版本管理
- ldflags_使用ldflags设置Go应用程序的版本信息
- 软件项目版本号的命名规则及格式
- 官方文档_ldflags
- 官方文档_link
追踪、管理软件的变更迭代,能够提高开发效率
2.2 GNU命名方式主版本号 . 子版本号 [. 修正版本号 [. 编译版本号 ]] Major_Version_Number.Minor_Version_Number[.Revision_Number[.Build_Number]] 示例 : 1.2.1、 2.0、 5.0.0 build-13124
| 情景 | 主版本号 | 子版本号 | 修正版本 | 最终版本号 |
|---|---|---|---|---|
| 项目初始版本 | 1 | 0 | 0 | 1.0.0 |
| 修复bug或局部修改 | 不变 | 不变 | +1 | 1.0.1 |
| 增加功能、兼容优化、性能优化 | 不变 | +1 | 归零 | 1.1.0 |
| 重大修改或修改过多,导致项目整体发生变化,无法向前兼容 | +1 | 归零 | 归零 | 2.0.0 |
以docker举例,查看版本信息有子命令与参数两种方式
# 使用参数查看 jonathanjiang@linux:~$ docker -v Docker version 20.10.12, build e91ed57 # 使用子命令查看 jonathanjiang@linux:~$ docker version Client: Docker Engine - Community Version: 20.10.12 API version: 1.41 Go version: go1.16.12 Git commit: e91ed57 Built: Mon Dec 13 11:45:33 2021 OS/Arch: linux/amd64 Context: default Experimental: true Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/version": dial unix /var/run/docker.sock: connect: permission denied
三、硬编码版本信息(不推荐)后续的代码中模仿docker的形式,提供版本信息
-
项目simple_app目录结构
jonathanjiang@linux:simple_app$ tree . ├── app ├── go.mod ├── main.go ├── simple_app └── version └── version.go 1 directory, 5 files将版本信息单独放入version包中,引用即可
-
main.go代码
package main import ( "flag" "fmt" "gitee.com/Jonathan_Jiang/simple_app/version" ) func main() { v := flag.Bool("v", false, "Print Version") flag.Parse() vi := version.GetVersion() // 参数获取 if *v { fmt.Printf("SimpleApp Version %s Built %s n", vi.Version, vi.Built) return } // 命令方式 args := flag.Args() if len(args) > 0 && args[0] == "version" { fmt.Printf("Version: t %s n", vi.Version) fmt.Printf("Built: tt %s n", vi.Built) fmt.Printf("Platform: t %s n", vi.Platform) fmt.Printf("GoVersion: t %s n", vi.GoVersion) fmt.Printf("GitCommit: t %s n", vi.GitCommit) return } // 正常执行 fmt.Println("start app") } -
version/version.go代码
package version type VersionInfo struct { Version string `json:"version"` Built string `json:"built"` Platform string `json:"platform"` GoVersion string `json:"go_version"` GitCommit string `json:"git_commit"` } func GetVersion() VersionInfo { return VersionInfo{ Version: "1.0.0", Built: "mock", Platform: "mock", GoVersion: "mock", GitCommit: "mock", } } -
使用效果
# 编译程序,-o app 命名为app jonathanjiang@linux:simple_app$ go build # 参数方式,查询版本信息 jonathanjiang@linux:simple_app$ ./simple_app -v SimpleApp Version 1.0.0 Built mock # 命令方式,查询版本信息 jonathanjiang@linux:simple_app$ ./simple_app version Version: 1.0.0 Built: mock Platform: mock GoVersion: mock GitCommit: mock # 正常执行 jonathanjiang@linux:simple_app$ ./simple_app start app
-
优化
版本信息一般是在发布时确定的,所以最好不要写死在代码中。最好是在编译时传入信息,类似C/C++在代码中预置版本宏定义,在编译中从外部传入版本号,虽然golang不支持宏定义,但是提供了link去处理相似场景
-
link基础
- go build -ldflags,编译时将参数传递给go tool link
- go tool link -X importpath.name=value,将importpath.name的值设置为value
-
修改version/version.go代码
package version import ( "fmt" "runtime" ) var ( // 声明包变量,方便link设置值 // 尽量不要作为函数入参使用 version string built string git_commit string ) type VersionInfo struct { Version string `json:"version"` Built string `json:"built"` Platform string `json:"platform"` GoVersion string `json:"go_version"` GitCommit string `json:"git_commit"` } func GetVersion() VersionInfo { // 使用runtime读取go信息 return VersionInfo{ Version: version, Built: built, Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), GoVersion: runtime.Version(), GitCommit: git_commit, } } -
使用
# 编译 jonathanjiang@linux:simple_app$ go build -ldflags="-X 'gitee.com/Jonathan_Jiang/simple_app/version.version=1.0.1' -X 'gitee.com/Jonathan_Jiang/simple_app/version.built=2022-01-26T16:57:31+0800' -X 'gitee.com/Jonathan_Jiang/simple_app/version.git_commit=abcdef'" # 打印 jonathanjiang@linux:simple_app$ ./simple_app version Version: 1.0.1 Built: 2022-01-26T16:57:31+0800 Platform: linux/amd64 GoVersion: go1.17.2 GitCommit: abcdef jonathanjiang@linux:simple_app$ ./simple_app -v SimpleApp Version 1.0.1 Built 2022-01-26T16:57:31+0800
-
注意:
importpath是指变量的包路径,比如我在main包中引用version包,其引用路径是gitee.com/Jonathan_Jiang/simple_app/version,那么你在go build时就要把包路径带进去,不然link找不到变量,也就无法赋值



