diff --git a/info/version.go b/info/version.go index caae3462..6d4e99a7 100644 --- a/info/version.go +++ b/info/version.go @@ -5,34 +5,32 @@ import ( "fmt" "os" "runtime" + "runtime/debug" "strings" + "sync" ) var ( - name = "[NAME]" - version = "[version unknown]" - commit = "[commit unknown]" - license = "[license unknown]" - buildOptions = "[options unknown]" - buildUser = "[user unknown]" - buildHost = "[host unknown]" - buildDate = "[date unknown]" - buildSource = "[source unknown]" - - compareVersion bool + name string + version = "dev build" + buildSource = "[source unknown]" + license = "[license unknown]" + + info *Info + loadInfo sync.Once ) // Info holds the programs meta information. type Info struct { - Name string - Version string - License string - Commit string - BuildOptions string - BuildUser string - BuildHost string - BuildDate string - BuildSource string + Name string + Version string + License string + Commit string + Time string + Source string + Dirty bool + + debug.BuildInfo } // 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 version = setVersion license = setLicenseName - compareVersion = compareVersionToTag } // GetInfo returns all the meta information about the program. func GetInfo() *Info { - return &Info{ - Name: name, - Version: version, - Commit: commit, - License: license, - BuildOptions: buildOptions, - BuildUser: buildUser, - BuildHost: buildHost, - BuildDate: buildDate, - BuildSource: buildSource, - } + loadInfo.Do(func() { + buildInfo, _ := debug.ReadBuildInfo() + buildSettings := make(map[string]string) + for _, setting := range buildInfo.Settings { + buildSettings[setting.Key] = setting.Value + } + + info = &Info{ + Name: name, + 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. func Version() string { - if !compareVersion || strings.HasPrefix(commit, fmt.Sprintf("tags/v%s-0-", version)) { - return version + info := GetInfo() + + if info.Dirty { + return version + "*" } - return version + "*" + + return version } // FullVersion returns the full and detailed version string. func FullVersion() string { - s := "" - if !compareVersion || strings.HasPrefix(commit, fmt.Sprintf("tags/v%s-0-", version)) { - s += fmt.Sprintf("%s\nversion %s\n", name, version) - } else { - s += fmt.Sprintf("%s\ndevelopment build, built on top version %s\n", name, version) - } - s += fmt.Sprintf("\ncommit %s\n", commit) - s += fmt.Sprintf("built with %s (%s) %s/%s\n", runtime.Version(), runtime.Compiler, runtime.GOOS, runtime.GOARCH) - s += fmt.Sprintf(" using options %s\n", strings.ReplaceAll(buildOptions, "ยง", " ")) - s += fmt.Sprintf(" by %s@%s\n", buildUser, buildHost) - s += fmt.Sprintf(" on %s\n", buildDate) - s += fmt.Sprintf("\nLicensed under the %s license.\nThe source code is available here: %s", license, buildSource) - return s + info := GetInfo() + + builder := new(strings.Builder) + + builder.WriteString(fmt.Sprintf("%s\nversion %s\n", info.Name, Version())) + builder.WriteString(fmt.Sprintf("\ncommit %s\n", info.Commit)) + builder.WriteString(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)) + builder.WriteString(fmt.Sprintf("\nLicensed under the %s license.\nThe source code is available here: %s", license, info.Source)) + + return builder.String() } // CheckVersion checks if the metadata is ok. @@ -92,17 +99,11 @@ func CheckVersion() error { return nil // testing on windows default: // check version information - if name == "[NAME]" { + if name == "[NAME]" || license == "[license unknown]" { return errors.New("must call SetInfo() before calling CheckVersion()") } - if version == "[version unknown]" || - commit == "[commit unknown]" || - license == "[license unknown]" || - buildOptions == "[options unknown]" || - buildUser == "[user unknown]" || - buildHost == "[host unknown]" || - buildDate == "[date unknown]" || - buildSource == "[source unknown]" { + + if version == "[version unknown]" { return errors.New("please build using the supplied build script.\n$ ./build {main.go|...}") } } diff --git a/metrics/metrics_info.go b/metrics/metrics_info.go index 9e94bbda..81dfd3e4 100644 --- a/metrics/metrics_info.go +++ b/metrics/metrics_info.go @@ -15,18 +15,15 @@ func registerInfoMetric() error { _, err := NewGauge( "info", map[string]string{ - "version": checkUnknown(meta.Version), - "commit": checkUnknown(meta.Commit), - "build_options": checkUnknown(meta.BuildOptions), - "build_user": checkUnknown(meta.BuildUser), - "build_host": checkUnknown(meta.BuildHost), - "build_date": checkUnknown(meta.BuildDate), - "build_source": checkUnknown(meta.BuildSource), - "go_os": runtime.GOOS, - "go_arch": runtime.GOARCH, - "go_version": runtime.Version(), - "go_compiler": runtime.Compiler, - "comment": commentOption(), + "version": checkUnknown(meta.Version), + "commit": checkUnknown(meta.Commit), + "build_date": checkUnknown(meta.Time), + "build_source": checkUnknown(meta.Source), + "go_os": runtime.GOOS, + "go_arch": runtime.GOARCH, + "go_version": runtime.Version(), + "go_compiler": runtime.Compiler, + "comment": commentOption(), }, func() float64 { // Report as 0 the first time in order to detect (re)starts.