version.go

 1package version
 2
 3import (
 4	"os"
 5	"runtime/debug"
 6	"strconv"
 7)
 8
 9// Build-time parameters set via -ldflags.
10
11var (
12	Version = "devel"
13	Commit  = "unknown"
14	// BuildID is a unique identifier for this build. For release builds it
15	// equals Commit; for development builds (go run / go build without
16	// ldflags) it is derived from the executable's modification time, which
17	// changes on every recompilation.
18	BuildID = ""
19)
20
21// A user may install crush using `go install github.com/charmbracelet/crush@latest`.
22// without -ldflags, in which case the version above is unset. As a workaround
23// we use the embedded build version that *is* set when using `go install` (and
24// is only set for `go install` and not for `go build`).
25func init() {
26	info, ok := debug.ReadBuildInfo()
27	if ok {
28		mainVersion := info.Main.Version
29		if mainVersion != "" && mainVersion != "(devel)" {
30			Version = mainVersion
31		}
32	}
33
34	// Derive BuildID when not set via ldflags.
35	if BuildID == "" {
36		BuildID = deriveBuildID()
37	}
38}
39
40// deriveBuildID uses the running executable's modification time as a unique
41// build fingerprint. This changes on every recompilation (including `go run`),
42// making it reliable for detecting stale servers during development.
43func deriveBuildID() string {
44	exe, err := os.Executable()
45	if err != nil {
46		return "unknown"
47	}
48	fi, err := os.Stat(exe)
49	if err != nil {
50		return "unknown"
51	}
52	return strconv.FormatInt(fi.ModTime().UnixNano(), 36)
53}