Say which mesh-sdk version a program was built with, from the build info (issue 1355)
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
// Package sdkversion says which mesh-sdk version a program was built with (novox/hq ADR 0446 clause 4: a composition
|
||||
// check names its mesh-sdk version, so the controller and the assigner can be compared; ADR 0453 clause 1).
|
||||
//
|
||||
// The version is read from the build info, never kept by hand: a constant nobody bumps would report two different
|
||||
// SDKs as one. A program that imports the SDK reports the module's pinned (pseudo-)version, or its replacement's;
|
||||
// the SDK's own binaries and tests report "(devel)" with the stamped vcs.revision.
|
||||
package sdkversion
|
||||
|
||||
import (
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
// Module is the SDK's Go module path.
|
||||
const Module = "git.novox.be/novox/mesh-sdk/go"
|
||||
|
||||
// Version is the mesh-sdk version this binary was built with: "unknown" when the build carries no build info.
|
||||
func Version() string {
|
||||
bi, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
return "unknown"
|
||||
}
|
||||
return FromBuildInfo(bi)
|
||||
}
|
||||
|
||||
// FromBuildInfo reads the SDK's version out of a build info. A dependency replaced by another module version is that
|
||||
// version; replaced by a local path it is the path, never empty. When the SDK is the main module it is "(devel)",
|
||||
// followed by a space and the vcs.revision when the build stamped one. Without the SDK in the build it is "unknown".
|
||||
func FromBuildInfo(bi *debug.BuildInfo) string {
|
||||
if bi == nil {
|
||||
return "unknown"
|
||||
}
|
||||
if bi.Main.Path == Module {
|
||||
for _, s := range bi.Settings {
|
||||
if s.Key == "vcs.revision" && s.Value != "" {
|
||||
return "(devel) " + s.Value
|
||||
}
|
||||
}
|
||||
return "(devel)"
|
||||
}
|
||||
for _, d := range bi.Deps {
|
||||
if d == nil || d.Path != Module {
|
||||
continue
|
||||
}
|
||||
if r := d.Replace; r != nil {
|
||||
if r.Version != "" {
|
||||
return r.Version
|
||||
}
|
||||
if r.Path != "" {
|
||||
return r.Path
|
||||
}
|
||||
}
|
||||
if d.Version != "" {
|
||||
return d.Version
|
||||
}
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package sdkversion
|
||||
|
||||
import (
|
||||
"runtime/debug"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const sdkPath = "git.novox.be/novox/mesh-sdk/go"
|
||||
|
||||
// The build infos are constructed in the shape runtime/debug.ReadBuildInfo gives a binary that imports the SDK
|
||||
// (go.mod pins like mesh-controller's v0.1.14-0.20261019091011-aa68b67389c9).
|
||||
func TestAPinnedDependencyIsItsPseudoVersion(t *testing.T) {
|
||||
bi := &debug.BuildInfo{Main: debug.Module{Path: "github.com/novox/mesh-controller", Version: "(devel)"},
|
||||
Deps: []*debug.Module{{Path: "example.org/other", Version: "v1.0.0"}, {Path: sdkPath, Version: "v0.1.14-0.20261019091011-aa68b67389c9"}}}
|
||||
if got := FromBuildInfo(bi); got != "v0.1.14-0.20261019091011-aa68b67389c9" {
|
||||
t.Fatalf("got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAReplacedDependencyIsTheReplacement(t *testing.T) {
|
||||
bi := &debug.BuildInfo{Main: debug.Module{Path: "x"}, Deps: []*debug.Module{{Path: sdkPath, Version: "v0.1.14",
|
||||
Replace: &debug.Module{Path: sdkPath, Version: "v0.2.0-0.20261020000000-abcdef123456"}}}}
|
||||
if got := FromBuildInfo(bi); got != "v0.2.0-0.20261020000000-abcdef123456" {
|
||||
t.Fatalf("got %q", got)
|
||||
}
|
||||
local := &debug.BuildInfo{Main: debug.Module{Path: "x"}, Deps: []*debug.Module{{Path: sdkPath, Version: "v0.1.14",
|
||||
Replace: &debug.Module{Path: "../mesh-sdk/go"}}}}
|
||||
if got := FromBuildInfo(local); got != "../mesh-sdk/go" {
|
||||
t.Fatalf("a local replacement: got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTheMainModuleIsDevelWithItsRevision(t *testing.T) {
|
||||
bi := &debug.BuildInfo{Main: debug.Module{Path: sdkPath, Version: "(devel)"},
|
||||
Settings: []debug.BuildSetting{{Key: "vcs", Value: "git"}, {Key: "vcs.revision", Value: "5786ba190c69bcee983223dbbc149bfb18fe01ed"}}}
|
||||
if got := FromBuildInfo(bi); got != "(devel) 5786ba190c69bcee983223dbbc149bfb18fe01ed" {
|
||||
t.Fatalf("got %q", got)
|
||||
}
|
||||
bare := &debug.BuildInfo{Main: debug.Module{Path: sdkPath, Version: "(devel)"}}
|
||||
if got := FromBuildInfo(bare); got != "(devel)" {
|
||||
t.Fatalf("no stamp: got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoBuildInfoIsUnknown(t *testing.T) {
|
||||
if got := FromBuildInfo(nil); got != "unknown" {
|
||||
t.Fatalf("got %q", got)
|
||||
}
|
||||
if got := FromBuildInfo(&debug.BuildInfo{Main: debug.Module{Path: "x"}}); got != "unknown" {
|
||||
t.Fatalf("an SDK-less binary: got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionIsNeverEmpty(t *testing.T) {
|
||||
if Version() == "" {
|
||||
t.Fatal("empty")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user