diff --git a/cmd/build.go b/cmd/build.go index 76b40e5a08..ac8b1b632b 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -2,11 +2,12 @@ package cmd // import "github.com/quay/clair/v4/cmd" import ( - "bytes" - "context" - "os/exec" + "runtime" "runtime/debug" - "time" + "strings" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" ) // Injected via git-export(1). See that man page and gitattributes(5). @@ -17,50 +18,81 @@ const ( revision = `$Format:%h (%cI)$` ) +var versionInfo = promauto.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: "clair", + Subsystem: "cmd", + Name: "version_info", + Help: "Version information.", + }, + []string{ + "claircore_version", + "goversion", + "modified", + "revision", + "version", + }, +) + func init() { + meta := prometheus.Labels{ + "claircore_version": "", + "goversion": runtime.Version(), + "modified": "", + "revision": "", + "version": "", + } + info, infoOK := debug.ReadBuildInfo() + var vcs []string + var core string + if infoOK { + // If not OK, built without modules? Weird. + for _, s := range info.Settings { + switch s.Key { + case `vcs.revision`: + meta["revision"] = s.Value + vcs = append(vcs, `rev`, s.Value) + case `vcs.modified`: + meta["modified"] = s.Value + if s.Value == `true` { + vcs = append(vcs, `(dirty)`) + } + } + } + // If we can read out the current binary's debug info, find the + // claircore version. + for _, m := range info.Deps { + if m.Path != "github.com/quay/claircore" { + continue + } + core = m.Version + if m.Replace != nil && m.Replace.Version != m.Version { + core = m.Replace.Version + } + } + meta["claircore_version"] = core + } + switch { case Version != "": // Had our version injected at build: do nothing. case len(describe) > 0 && describe[0] != '$': Version = describe case revision[0] == '$': - // This is a helper for development. In production, we shouldn't assume - // that the process is running in a git repository or that git is - // installed. This is quite possibly wrong if run from the wrong working - // directory. Version = `(random source build)` - ctx, done := context.WithTimeout(context.Background(), 5*time.Second) - defer done() - if _, err := exec.LookPath("git"); err != nil { - // Couldn't find a git binary: do nothing. - break - } - if err := exec.CommandContext(ctx, "git", "rev-parse", "--show-toplevel").Run(); err != nil { - // Couldn't find a git repository: do nothing. + if len(vcs) == 0 { + // A `go run` invocation, perhaps. break } - out, err := exec.CommandContext(ctx, "git", "describe").Output() - if err != nil { - // Couldn't describe the current commit: do nothing. - break - } - Version = string(bytes.TrimSpace(out)) + Version = strings.Join(vcs, " ") default: Version = revision } - - // If we can read out the current binary's debug info, append the claircore - // version if there was a replacement. - if info, ok := debug.ReadBuildInfo(); ok { - for _, m := range info.Deps { - if m.Path != "github.com/quay/claircore" { - continue - } - if m.Replace != nil && m.Replace.Version != m.Version { - Version += " (claircore " + m.Replace.Version + ")" - } - } + meta["version"] = Version + if core != "" { + Version += " (claircore " + core + ")" } + versionInfo.With(meta).Set(1) } // Version is a version string, injected at release time for release builds.