feat(version): 第18条 显示版本与内部版本解耦(V/A 双系)

- config 新增 displayVersion 注入变量(默认 1.0.0):GetDisplayVersion/
  GetMasterDisplayVersion(V)/GetAgentDisplayVersion(A),以后升版只改注入值
- ParseDisplayVersion/CompareDisplayVersion:三段数值比较,个位进位规则
  (1.0.9<1.1.0) 天然成立;不可解析(dev 标签/3.7.0-agent.1)返回 ok=false
- 显示位切换:dist 注入 X_UI_CUR_VER、-v、TG 报告 → V 系;
  agent 遥测 agentVersion → A 系;节点行 A 系原样显示、老 agent 沿用
  "agent " 前缀兼容
- 内部流不动:GetBaseVersion/GetPanelVersion 及其比较/订阅/远端状态
  消费方保持原样,传统节点更新判定与徽标行为不变
This commit is contained in:
Muse
2026-10-22 13:01:50 +00:00
parent e5f39ed20b
commit 1edb8f71da
7 changed files with 186 additions and 5 deletions
+97
View File
@@ -35,6 +35,13 @@ var (
buildCommit string
buildDate string
buildVersion string
// displayVersion is this fork's own user-facing release number ("1.0.0"
// in "V1.0.0" / "A1.0.0"), injected via `-ldflags -X` by release builds.
// It is deliberately separate from buildVersion (the upstream-shaped
// internal version): display surfaces (panel header, node list, agent
// telemetry) read the V/A display version, while internal comparisons
// and advertisements keep using GetBaseVersion/GetPanelVersion.
displayVersion string
)
// LogLevel represents the logging level for the application.
@@ -103,6 +110,96 @@ func GetPanelVersion() string {
return "dev+" + commit
}
// defaultDisplayVersion is the display version reported when a build does
// not inject one (plain `go build` / `go run`).
const defaultDisplayVersion = "1.0.0"
// GetDisplayVersion returns the bare numeric display version ("1.0.0"):
// the injected display version when the build provided one, else the
// default. Display versions advance in single-digit carry steps
// (1.0.9 -> 1.1.0 -> ... -> 1.9.9 -> 2.0.0); each segment stays 0-9.
func GetDisplayVersion() string {
if v := strings.TrimSpace(displayVersion); v != "" {
return v
}
return defaultDisplayVersion
}
// GetMasterDisplayVersion is the master's display version ("V1.0.0"),
// shown in the panel's version slot.
func GetMasterDisplayVersion() string {
return "V" + GetDisplayVersion()
}
// GetAgentDisplayVersion is the agent's display version ("A1.0.0"),
// reported in agent telemetry and shown on agent node rows.
func GetAgentDisplayVersion() string {
return "A" + GetDisplayVersion()
}
// ParseDisplayVersion parses a display version into its three numeric
// segments. It accepts the bare form ("1.0.0") and the letter-prefixed
// display forms ("V1.0.0", "A1.0.0", "v1.0.0"). Anything else — dev labels,
// suffixed builds like "3.7.0-agent.1", wrong segment counts, non-numeric
// segments — reports ok=false so callers can fall back instead of guessing.
func ParseDisplayVersion(s string) (parts [3]int, ok bool) {
s = strings.TrimSpace(s)
if parsed, good := parseDisplayParts(s); good {
return parsed, true
}
// Retry once without a single leading display letter (V/A, any case).
if len(s) > 1 && (s[0] == 'V' || s[0] == 'v' || s[0] == 'A' || s[0] == 'a') {
if parsed, good := parseDisplayParts(s[1:]); good {
return parsed, true
}
}
return [3]int{}, false
}
func parseDisplayParts(s string) ([3]int, bool) {
var parts [3]int
segs := strings.Split(s, ".")
if len(segs) != 3 {
return parts, false
}
for i, seg := range segs {
if seg == "" {
return parts, false
}
for _, r := range seg {
if r < '0' || r > '9' {
return parts, false
}
}
n, err := strconv.Atoi(seg)
if err != nil {
return parts, false
}
parts[i] = n
}
return parts, true
}
// CompareDisplayVersion compares two display versions segment by segment
// (numeric, so the single-digit carry rule 1.0.9 < 1.1.0 holds naturally).
// ok=false when either side is not a parseable display version.
func CompareDisplayVersion(a, b string) (cmp int, ok bool) {
pa, okA := ParseDisplayVersion(a)
pb, okB := ParseDisplayVersion(b)
if !okA || !okB {
return 0, false
}
for i := range 3 {
if pa[i] != pb[i] {
if pa[i] < pb[i] {
return -1, true
}
return 1, true
}
}
return 0, true
}
// GetLogLevel returns the current logging level based on environment variables or defaults to Info.
func GetLogLevel() LogLevel {
if IsDebug() {