v221 ③ update check: fall back to raw version when display is unparseable
displayUpdateFields returned avail=false whenever the running build's display version could not be compared (the VV2.1.0 double-letter builds), so the panel swallowed a real update prompt and the native updater refused to run. displayUpdateFieldsFor now takes the current display/raw versions as inputs and, when the display comparison cannot judge, compares the latest tag against the raw base version with the same tolerant display parser — unparseable raw base yields false. (Not isNewerVersion: on this fork's uppercase-V tags it degrades to string inequality, which would phantom-report an update on form difference alone.) Parseable display versions keep the segment rule untouched. Regression tests cover the VV scenario in both raw forms.
This commit is contained in:
@@ -164,13 +164,38 @@ func (s *PanelService) GetUpdateInfo() (*PanelUpdateInfo, error) {
|
||||
// display version. An unparseable tag (not a V-series release) yields ""
|
||||
// so the UI falls back to the raw fields.
|
||||
func displayUpdateFields(latestTag string) (string, bool) {
|
||||
return displayUpdateFieldsFor(latestTag, config.GetMasterDisplayVersion(), config.GetBaseVersion())
|
||||
}
|
||||
|
||||
// displayUpdateFieldsFor is displayUpdateFields with the running
|
||||
// build's versions as inputs. When the DISPLAY comparison cannot
|
||||
// judge — the running build's display version is itself unparseable,
|
||||
// the "VV2.1.0" double-letter builds — the verdict falls back to the
|
||||
// raw version comparison instead of reporting "no update": the
|
||||
// display path used to swallow a real update entirely (the panel
|
||||
// showed no prompt while /releases/latest happily served the newer
|
||||
// tag, and the native updater refused to run). A parseable display
|
||||
// version keeps the segment rule exactly as before.
|
||||
func displayUpdateFieldsFor(latestTag, currentDisplay, currentRaw string) (string, bool) {
|
||||
parts, ok := config.ParseDisplayVersion(latestTag)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
disp := fmt.Sprintf("V%d.%d.%d", parts[0], parts[1], parts[2])
|
||||
cmp, ok := config.CompareDisplayVersion(disp, config.GetMasterDisplayVersion())
|
||||
return disp, ok && cmp > 0
|
||||
cmp, ok := config.CompareDisplayVersion(disp, currentDisplay)
|
||||
if !ok {
|
||||
// Raw fallback: judge the latest tag against the running
|
||||
// build's raw base version, parsed with the same tolerant
|
||||
// display parser (bare and V/A forms both parse). An
|
||||
// unparseable raw base yields no verdict → false. This is
|
||||
// deliberately NOT isNewerVersion: on this fork's uppercase-V
|
||||
// tags that helper degrades to string inequality (its
|
||||
// normalizer strips only a lowercase "v"), which would report
|
||||
// a phantom update whenever latest merely differs in form.
|
||||
rawCmp, rawOk := config.CompareDisplayVersion(disp, currentRaw)
|
||||
return disp, rawOk && rawCmp > 0
|
||||
}
|
||||
return disp, cmp > 0
|
||||
}
|
||||
|
||||
// devChannelActive reports whether self-update should track the rolling dev
|
||||
|
||||
@@ -25,6 +25,42 @@ func TestDisplayUpdateFields(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// V2.2.1 ③: when the running build's display version is unparseable
|
||||
// (the "VV2.1.0" double-letter builds), the display comparison cannot
|
||||
// judge and the verdict must fall back to the raw version comparison
|
||||
// instead of swallowing the update. A parseable display version keeps
|
||||
// the segment rule — the raw string plays no part there.
|
||||
func TestDisplayUpdateFieldsForFallback(t *testing.T) {
|
||||
// Unparseable display "VV2.1.0", newer latest → available via raw.
|
||||
if disp, avail := displayUpdateFieldsFor("V2.2.0", "VV2.1.0", "2.1.0"); disp != "V2.2.0" || !avail {
|
||||
t.Fatalf("VV display, newer latest = %q, %v; want V2.2.0, true", disp, avail)
|
||||
}
|
||||
// Unparseable display, latest equal to the raw base → not
|
||||
// available, in both raw forms (bare and V-prefixed).
|
||||
if disp, avail := displayUpdateFieldsFor("V2.1.0", "VV2.1.0", "2.1.0"); disp != "V2.1.0" || avail {
|
||||
t.Fatalf("VV display, same latest (bare raw) = %q, %v; want V2.1.0, false", disp, avail)
|
||||
}
|
||||
if _, avail := displayUpdateFieldsFor("V2.1.0", "VV2.1.0", "V2.1.0"); avail {
|
||||
t.Fatal("VV display, same latest (V raw) must not report an update")
|
||||
}
|
||||
// Unparseable display AND unparseable raw base → no verdict, false.
|
||||
if _, avail := displayUpdateFieldsFor("V2.2.0", "VV2.1.0", "3.7.0-agent.1"); avail {
|
||||
t.Fatal("unparseable raw base must yield no update verdict")
|
||||
}
|
||||
// Parseable display: segment rule decides, raw base is ignored
|
||||
// even when it disagrees.
|
||||
if disp, avail := displayUpdateFieldsFor("V2.2.0", "V2.1.0", "9.9.9"); disp != "V2.2.0" || !avail {
|
||||
t.Fatalf("parseable display, newer = %q, %v; want V2.2.0, true", disp, avail)
|
||||
}
|
||||
if _, avail := displayUpdateFieldsFor("V2.1.0", "V2.1.0", "1.0.0"); avail {
|
||||
t.Fatal("parseable display, equal versions must not report an update (raw base must not leak in)")
|
||||
}
|
||||
// Unparseable latest tag still yields "" so the UI uses raw fields.
|
||||
if disp, avail := displayUpdateFieldsFor("3.7.0-agent.1", "VV2.1.0", "2.1.0"); disp != "" || avail {
|
||||
t.Fatalf("legacy tag = %q, %v; want empty, false", disp, avail)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceUnitFromCgroup(t *testing.T) {
|
||||
content := "0::/system.slice/x-ui.service\n"
|
||||
if got := serviceUnitFromCgroup(content); got != "x-ui" {
|
||||
|
||||
Reference in New Issue
Block a user