Files
Tai GrootandChristian Rocha 9e126c27da fix: detect stale server during development with BuildID
The version check compared Version strings, but during development both
client and server report "devel" — so stale servers were never restarted.

BuildID is now derived from the executable's modification time, which
changes on every recompilation (including go run). The server exposes it
via /v1/version and the client checks both Version and BuildID match.

Assisted-by: Crush:AWS Claude Opus 4.6
2026-05-14 15:32:41 -04:00

54 lines
1.4 KiB
Go

package version
import (
"os"
"runtime/debug"
"strconv"
)
// Build-time parameters set via -ldflags.
var (
Version = "devel"
Commit = "unknown"
// BuildID is a unique identifier for this build. For release builds it
// equals Commit; for development builds (go run / go build without
// ldflags) it is derived from the executable's modification time, which
// changes on every recompilation.
BuildID = ""
)
// A user may install crush using `go install github.com/charmbracelet/crush@latest`.
// without -ldflags, in which case the version above is unset. As a workaround
// we use the embedded build version that *is* set when using `go install` (and
// is only set for `go install` and not for `go build`).
func init() {
info, ok := debug.ReadBuildInfo()
if ok {
mainVersion := info.Main.Version
if mainVersion != "" && mainVersion != "(devel)" {
Version = mainVersion
}
}
// Derive BuildID when not set via ldflags.
if BuildID == "" {
BuildID = deriveBuildID()
}
}
// deriveBuildID uses the running executable's modification time as a unique
// build fingerprint. This changes on every recompilation (including `go run`),
// making it reliable for detecting stale servers during development.
func deriveBuildID() string {
exe, err := os.Executable()
if err != nil {
return "unknown"
}
fi, err := os.Stat(exe)
if err != nil {
return "unknown"
}
return strconv.FormatInt(fi.ModTime().UnixNano(), 36)
}