14.Go程序版本信息(一)

Go程序版本信息(一)

日期:2022-01-25 11:02:18

作者:JonathanJiang

此文章为个人笔记,有误请指正,推荐读者查看参考资料的原文

一、参考资料

  1. Golang中管理程序的版本信息
  2. Golang程序版本管理
  3. ldflags_使用ldflags设置Go应用程序的版本信息
  4. 软件项目版本号的命名规则及格式
  5. 官方文档_ldflags
  6. 官方文档_link

二、版本信息

2.1 使用目的

追踪、管理软件的变更迭代,能够提高开发效率

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

2.3 查看方式

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: \t\t %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
    

四、link版本信息(推荐)

  • 优化

    版本信息一般是在发布时确定的,所以最好不要写死在代码中。最好是在编译时传入信息,类似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找不到变量,也就无法赋值

你可能感兴趣的:(Golang,golang,开发语言,后端)