Migrate to runtime/debug.BuildInfo for most VCS information

This commit is contained in:
Patrick Pacher 2024-03-26 10:10:38 +01:00
parent 704e9e256c
commit ff5e461b84
2 changed files with 65 additions and 66 deletions

View file

@ -5,34 +5,32 @@ import (
"fmt" "fmt"
"os" "os"
"runtime" "runtime"
"runtime/debug"
"strings" "strings"
"sync"
) )
var ( var (
name = "[NAME]" name string
version = "[version unknown]" version = "dev build"
commit = "[commit unknown]" buildSource = "[source unknown]"
license = "[license unknown]" license = "[license unknown]"
buildOptions = "[options unknown]"
buildUser = "[user unknown]"
buildHost = "[host unknown]"
buildDate = "[date unknown]"
buildSource = "[source unknown]"
compareVersion bool info *Info
loadInfo sync.Once
) )
// Info holds the programs meta information. // Info holds the programs meta information.
type Info struct { type Info struct {
Name string Name string
Version string Version string
License string License string
Commit string Commit string
BuildOptions string Time string
BuildUser string Source string
BuildHost string Dirty bool
BuildDate string
BuildSource string debug.BuildInfo
} }
// Set sets meta information via the main routine. This should be the first thing your program calls. // Set sets meta information via the main routine. This should be the first thing your program calls.
@ -40,47 +38,56 @@ func Set(setName string, setVersion string, setLicenseName string, compareVersio
name = setName name = setName
version = setVersion version = setVersion
license = setLicenseName license = setLicenseName
compareVersion = compareVersionToTag
} }
// GetInfo returns all the meta information about the program. // GetInfo returns all the meta information about the program.
func GetInfo() *Info { func GetInfo() *Info {
return &Info{ loadInfo.Do(func() {
Name: name, buildInfo, _ := debug.ReadBuildInfo()
Version: version, buildSettings := make(map[string]string)
Commit: commit, for _, setting := range buildInfo.Settings {
License: license, buildSettings[setting.Key] = setting.Value
BuildOptions: buildOptions, }
BuildUser: buildUser,
BuildHost: buildHost, info = &Info{
BuildDate: buildDate, Name: name,
BuildSource: buildSource, Version: version,
} License: license,
BuildInfo: *buildInfo,
Source: buildSource,
Commit: buildSettings["vcs.revision"],
Time: buildSettings["vcs.time"],
Dirty: buildSettings["vcs.modified"] == "true",
}
})
return info
} }
// Version returns the short version string. // Version returns the short version string.
func Version() string { func Version() string {
if !compareVersion || strings.HasPrefix(commit, fmt.Sprintf("tags/v%s-0-", version)) { info := GetInfo()
return version
if info.Dirty {
return version + "*"
} }
return version + "*"
return version
} }
// FullVersion returns the full and detailed version string. // FullVersion returns the full and detailed version string.
func FullVersion() string { func FullVersion() string {
s := "" info := GetInfo()
if !compareVersion || strings.HasPrefix(commit, fmt.Sprintf("tags/v%s-0-", version)) {
s += fmt.Sprintf("%s\nversion %s\n", name, version) builder := new(strings.Builder)
} else {
s += fmt.Sprintf("%s\ndevelopment build, built on top version %s\n", name, version) builder.WriteString(fmt.Sprintf("%s\nversion %s\n", info.Name, Version()))
} builder.WriteString(fmt.Sprintf("\ncommit %s\n", info.Commit))
s += fmt.Sprintf("\ncommit %s\n", commit) builder.WriteString(fmt.Sprintf("built with %s (%s) %s/%s\n", runtime.Version(), runtime.Compiler, runtime.GOOS, runtime.GOARCH))
s += fmt.Sprintf("built with %s (%s) %s/%s\n", runtime.Version(), runtime.Compiler, runtime.GOOS, runtime.GOARCH) builder.WriteString(fmt.Sprintf(" on %s\n", info.Time))
s += fmt.Sprintf(" using options %s\n", strings.ReplaceAll(buildOptions, "§", " ")) builder.WriteString(fmt.Sprintf("\nLicensed under the %s license.\nThe source code is available here: %s", license, info.Source))
s += fmt.Sprintf(" by %s@%s\n", buildUser, buildHost)
s += fmt.Sprintf(" on %s\n", buildDate) return builder.String()
s += fmt.Sprintf("\nLicensed under the %s license.\nThe source code is available here: %s", license, buildSource)
return s
} }
// CheckVersion checks if the metadata is ok. // CheckVersion checks if the metadata is ok.
@ -95,14 +102,9 @@ func CheckVersion() error {
if name == "[NAME]" { if name == "[NAME]" {
return errors.New("must call SetInfo() before calling CheckVersion()") return errors.New("must call SetInfo() before calling CheckVersion()")
} }
if version == "[version unknown]" || if version == "[version unknown]" ||
commit == "[commit unknown]" || license == "[license unknown]" {
license == "[license unknown]" ||
buildOptions == "[options unknown]" ||
buildUser == "[user unknown]" ||
buildHost == "[host unknown]" ||
buildDate == "[date unknown]" ||
buildSource == "[source unknown]" {
return errors.New("please build using the supplied build script.\n$ ./build {main.go|...}") return errors.New("please build using the supplied build script.\n$ ./build {main.go|...}")
} }
} }

View file

@ -15,18 +15,15 @@ func registerInfoMetric() error {
_, err := NewGauge( _, err := NewGauge(
"info", "info",
map[string]string{ map[string]string{
"version": checkUnknown(meta.Version), "version": checkUnknown(meta.Version),
"commit": checkUnknown(meta.Commit), "commit": checkUnknown(meta.Commit),
"build_options": checkUnknown(meta.BuildOptions), "build_date": checkUnknown(meta.Time),
"build_user": checkUnknown(meta.BuildUser), "build_source": checkUnknown(meta.Source),
"build_host": checkUnknown(meta.BuildHost), "go_os": runtime.GOOS,
"build_date": checkUnknown(meta.BuildDate), "go_arch": runtime.GOARCH,
"build_source": checkUnknown(meta.BuildSource), "go_version": runtime.Version(),
"go_os": runtime.GOOS, "go_compiler": runtime.Compiler,
"go_arch": runtime.GOARCH, "comment": commentOption(),
"go_version": runtime.Version(),
"go_compiler": runtime.Compiler,
"comment": commentOption(),
}, },
func() float64 { func() float64 {
// Report as 0 the first time in order to detect (re)starts. // Report as 0 the first time in order to detect (re)starts.