Files
headscale/hscontrol/types/version.go
2025-09-12 11:47:31 +02:00

82 lines
1.7 KiB
Go

package types
import (
"fmt"
"runtime"
"runtime/debug"
"strings"
"sync"
)
type GoInfo struct {
Version string `json:"version"`
OS string `json:"os"`
Arch string `json:"arch"`
}
type VersionInfo struct {
Version string `json:"version"`
Commit string `json:"commit"`
BuildTime string `json:"buildTime"`
Go GoInfo `json:"go"`
Dirty bool `json:"dirty"`
}
func (v *VersionInfo) String() string {
var sb strings.Builder
version := v.Version
if v.Dirty && !strings.Contains(version, "dirty") {
version += "-dirty"
}
sb.WriteString(fmt.Sprintf("headscale version %s\n", version))
sb.WriteString(fmt.Sprintf("commit: %s\n", v.Commit))
sb.WriteString(fmt.Sprintf("build time: %s\n", v.BuildTime))
sb.WriteString(fmt.Sprintf("built with: %s %s/%s\n", v.Go.Version, v.Go.OS, v.Go.Arch))
return sb.String()
}
var buildInfo = sync.OnceValues(func() (*debug.BuildInfo, bool) {
return debug.ReadBuildInfo()
})
var GetVersionInfo = sync.OnceValue(func() *VersionInfo {
info := &VersionInfo{
Version: "dev",
Commit: "unknown",
BuildTime: "unknown",
Go: GoInfo{
Version: runtime.Version(),
OS: runtime.GOOS,
Arch: runtime.GOARCH,
},
Dirty: false,
}
buildInfo, ok := buildInfo()
if !ok {
return info
}
// Extract version from module path or main version
if buildInfo.Main.Version != "" && buildInfo.Main.Version != "(devel)" {
info.Version = buildInfo.Main.Version
}
// Extract build settings
for _, setting := range buildInfo.Settings {
switch setting.Key {
case "vcs.revision":
info.Commit = setting.Value
case "vcs.modified":
info.Dirty = setting.Value == "true"
case "vcs.time":
info.BuildTime = setting.Value
}
}
return info
})