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}