使用”go install”命令自动适配应用程序的版本信息【Go 1.16+】

这篇文章适用于 Go 1.16 及更高版本。

使用go install命令来显示Go应用的版本

我想将我的Go语言(以下简称为Golang)应用程序添加版本信息显示的功能。

在使用自家制作的Golang应用程序中显示版本信息时,通常需要将版本信息嵌入到源代码中或在构建时通过选项传递。

如果在源代码中嵌入版本信息,可能会遇到更新繁琐或者遗忘更新的问题。因此,我们会在构建脚本等工具中读取通过git tag命令打的标签,并将其传递给构建时的参数,以解决这个问题。

然而,如果在构建时通过参数传递版本号,那么问题就出现在用 go install 安装后无法体现版本的变动。

换句话说,即使是通过 “go install” 进行安装,我也希望应用程序的版本信息能够跟随 git 标签。

顺便提一下,如果您想要批量更新使用 go install 安装的 Golang 应用程序,可以使用 gup 命令,非常方便。

github.com/nao1215/gup @ GitHub

gup: go installしたバイナリの一括アップデートコマンド(仕様と今後) @ Zenn

TL; DR (北産業) 簡而言之

    1. 通过 `debug.ReadBuildInfo` 可以在构建时获取 git 标签。

示例如果在 git tag 等中标记版本,则可以在应用程序被 `go install` 安装时与存储库的版本保持一致(不包括 `go build`)。

main.go
package main

import (
“flag”
“fmt”
“runtime/debug”
)

// Version 是应用程序在构建时通过 `-ldflags` 传递的版本信息。
var Version string

func main() {
var versionFlag = flag.Bool(“version”, false, “”)

flag.Parse()

if *versionFlag {
// 用于 “go build” 时的版本兼容性(传统方式,需要使用 LDFLAGS)
if Version != “” {
fmt.Println(Version)

return
}

// 用于 “go install” 时的版本兼容性
if buildInfo, ok := debug.ReadBuildInfo(); ok {
// 从克隆的 VCS 的最新标签获取,因此在本地的情况下会默认设置为 “(devel)”。
fmt.Println(buildInfo.Main.Version)

return
}

fmt.Println(“(unknown)”)

return
}

fmt.Println(“Hello, world!”)
}

示例存储库:https://github.com/KEINOS/go-version-opt-example/ @ GitHub

尝试在线使用 `go install` 安装上述内容并查看版本显示结果 @ paiza.IO

必需条件

在 git 或其他 VCS 中,用 “vX.Y.Z” 格式给版本标签打上标签。
将源代码适应模块模式。(放置 go.mod 和 go.sum)

只有在使用 `go install` 安装包时才会生效。因此,用于生成发布二进制文件或测试的 `go build` 不会生效。使用 `go build`,通常还是需要指定 LDFLAGS 选项(例如 `go build -ldflags=”-X main.Version=$(git describe –tags)”`)来构建基础内容。(在 Go 1.18 中可能会有改进)

兼容的 Go 版本

对于在 go.mod 中设置为 1.16 或更高版本的包来说较好。

如果 go.mod 是 1.17,则可以确保兼容性,因此推荐使用。

? 这个机制的关键是使用在Go 1.12中实现的debug.readBuildInfo()。readBuildInfo()会返回在构建时嵌入的调试信息对象,其中的obj.Main.Version字段存储了main.go文件的最终标签(默认为(devel))。在示例中,我们将此字段用于Version变量为空的情况。然而,实际上这取决于Go的模块模式和go install命令。因此,在考虑仍然习惯通过go get -u安装包作为二进制文件(而不是使用go install)的用户时,我认为在go.mod中将版本设置为1.17以上并使用这种方法是可靠的。(由于Go 1.17要求使用go install命令)

技巧

git タグによるバージョン情報の取得コマンド
git describe –tag

git のコミット ID の取得コマンド
git rev-parse –short HEAD

バージョン情報をビルド時に渡す例
TAG_APP=$(git describe –tag)
REV_APP=$(git rev-parse –short HEAD)
VER_APP=”${TAG_APP}+${REV_APP}”

go build -ldflags=”-s -w -extldflags \”-static\” -X ‘main.versionApp=${VER_APP}'”

文献引用

ReadBuildInfo() | debug | runtime @ pkg.go.dev
#29228: runtime/debug: document BuildInfo.Main.Version == “(devel)” | Issue | golang @ GitHub
#29814: cmd/go: use version control to discover the main module’s version? | Issue | golang @ GitHub
#172: Add go1.12 versioning support | Pull Request | golang-migrate @ GitHub

bannerAds