diff --git a/version/version.go b/version/version.go new file mode 100644 index 0000000..855cccc --- /dev/null +++ b/version/version.go @@ -0,0 +1,124 @@ +package version + +import ( + "fmt" + "runtime" + "runtime/debug" + "strings" + + "github.com/prometheus/client_golang/prometheus" + "github.com/spf13/cobra" + "go.ntppool.org/common/logger" + "golang.org/x/mod/semver" +) + +// VERSION has the current software version (set in the build process) +var VERSION string +var buildTime string +var gitVersion string +var gitModified bool + +var info Info + +type Info struct { + Version string `json:",omitempty"` + GitRev string `json:",omitempty"` + BuildTime string `json:",omitempty"` +} + +func init() { + + info.BuildTime = buildTime + info.GitRev = gitVersion + + if len(VERSION) == 0 { + VERSION = "dev-snapshot" + } else { + if !strings.HasPrefix(VERSION, "v") { + VERSION = "v" + VERSION + } + if !semver.IsValid(VERSION) { + logger.Setup().Warn("invalid version number", "version", VERSION) + } + } + if bi, ok := debug.ReadBuildInfo(); ok { + for _, h := range bi.Settings { + // logger.Setup().Info("build info", "k", h.Key, "v", h.Value) + switch h.Key { + case "vcs.time": + buildTime = h.Value + info.BuildTime = h.Value + case "vcs.revision": + // https://blog.carlmjohnson.net/post/2023/golang-git-hash-how-to/ + // todo: use BuildInfo.Main.Version if revision is empty + gitVersion = h.Value + info.GitRev = h.Value + case "vcs.modified": + if h.Value == "true" { + gitModified = true + } + } + } + } + + info.Version = VERSION + + Version() +} + +func VersionCmd(name string) *cobra.Command { + versionCmd := &cobra.Command{ + Use: "version", + Short: "Print version and build information", + Run: func(cmd *cobra.Command, args []string) { + ver := Version() + fmt.Printf("%s %s\n", name, ver) + }, + } + return versionCmd +} + +func RegisterMetric(registry prometheus.Registerer) { + buildInfo := prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "build_info", + Help: "Build information", + }, + []string{"version"}, + ) + registry.MustRegister(buildInfo) + buildInfo.WithLabelValues(Version()).Set(1) +} + +var v string + +func VersionInfo() Info { + return info +} + +func Version() string { + if len(v) > 0 { + return v + } + extra := []string{} + if len(buildTime) > 0 { + extra = append(extra, buildTime) + } + extra = append(extra, runtime.Version()) + + v := VERSION + if len(gitVersion) > 0 { + g := gitVersion + if len(g) > 7 { + g = g[0:7] + } + v += "/" + g + if gitModified { + v += "-M" + } + + } + + v = fmt.Sprintf("%s (%s)", v, strings.Join(extra, ", ")) + return v +}