box-updates: was Ubuntu zurückhält, zählt nicht als Update
User 25.09.: 5 Pakete, die Ubuntu gestaffelt verteilt (phasing), standen als Update da, obwohl apt-get upgrade sie gar nicht einspielt – das Betriebssystem wurde nie grün. Gezählt wird jetzt, was die Simulation von apt-get upgrade wirklich einspielen würde; Zurückgehaltenes steht nur noch als Hinweis da. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
54a3649d5e
commit
2784c0ea32
@@ -103,14 +103,18 @@ def _installed_engine_build() -> int | None:
|
||||
|
||||
|
||||
def _os_upgradable() -> int:
|
||||
"""Wie viele Pakete `apt-get upgrade` jetzt wirklich einspielen würde (die Zeilen „Inst“ der Simulation). Nicht
|
||||
mitgezählt ist, was Ubuntu gestaffelt verteilt (phasing) oder zurückhält (kept back) — sonst stand das
|
||||
Betriebssystem nie auf „aktuell“ (25.09.2026: 5 Pakete, die das Update gar nicht einspielen durfte).
|
||||
LC_ALL=C: englische Ausgabe, damit „Inst“ auch auf einer deutschen Box so heißt."""
|
||||
try:
|
||||
# LC_ALL=C erzwingt englische apt-Ausgabe ("[upgradable from: ...]") — sonst zählt
|
||||
# grep auf einer deutschen Box ("[aktualisierbar von:]") nichts und meldet faelschlich 0.
|
||||
out = subprocess.run(
|
||||
["bash", "-c", "LC_ALL=C apt list --upgradable 2>/dev/null | grep -c upgradable || true"],
|
||||
capture_output=True, text=True, timeout=10)
|
||||
out = subprocess.run(["bash", "-c", "LC_ALL=C apt-get -s upgrade 2>/dev/null"],
|
||||
capture_output=True, text=True, timeout=60)
|
||||
if out.returncode != 0:
|
||||
PRUEF_FEHLER["os"] = f"Paketliste nicht lesbar (apt-get endete mit {out.returncode})"
|
||||
return 0
|
||||
PRUEF_FEHLER["os"] = None
|
||||
return int((out.stdout or "0").strip() or 0)
|
||||
return sum(1 for zeile in (out.stdout or "").splitlines() if zeile.startswith("Inst "))
|
||||
except Exception as exc:
|
||||
PRUEF_FEHLER["os"] = f"Paketliste nicht lesbar ({exc.__class__.__name__})"
|
||||
return 0
|
||||
@@ -347,8 +351,11 @@ def os_update_details() -> dict:
|
||||
out_pkgs.append({"name": m.group(1), "candidate": m.group(2),
|
||||
"current": m.group(3).strip()})
|
||||
out_pkgs.sort(key=lambda p: p["name"])
|
||||
return {"kind": "os", "count": len(out_pkgs), "packages": out_pkgs,
|
||||
"held_back": _os_held_back()}
|
||||
# Was Ubuntu zurückhält, spielt das Update nicht ein — es steht getrennt da, nicht in der Liste und der Zahl.
|
||||
held = _os_held_back()
|
||||
zurueck = {p["name"] for p in held}
|
||||
out_pkgs = [p for p in out_pkgs if p["name"] not in zurueck]
|
||||
return {"kind": "os", "count": len(out_pkgs), "packages": out_pkgs, "held_back": held}
|
||||
except Exception as exc:
|
||||
return {"kind": "os", "count": len(out_pkgs), "packages": out_pkgs, "error": str(exc)}
|
||||
|
||||
|
||||
@@ -119,3 +119,43 @@ def test_update_per_knopf_landet_im_verlauf(monkeypatch):
|
||||
zeilen.clear()
|
||||
maintenance._update_im_verlauf({**job, "abschluss_daten": {}})
|
||||
assert zeilen == []
|
||||
|
||||
|
||||
SIMULATION = """NOTE: This is only a simulation!
|
||||
apt-get needs root privileges for real execution.
|
||||
Reading package lists...
|
||||
Calculating upgrade...
|
||||
The following upgrades have been deferred due to phasing:
|
||||
python3-distupgrade python3-software-properties rust-coreutils
|
||||
The following packages have been kept back:
|
||||
ubuntu-release-upgrader-core
|
||||
The following packages will be upgraded:
|
||||
libssl3t64 openssl
|
||||
2 upgraded, 0 newly installed, 0 to remove and 4 not upgraded.
|
||||
Inst libssl3t64 [3.5.0-1ubuntu1] (3.5.0-1ubuntu2 Ubuntu:26.04/resolute-updates [amd64])
|
||||
Inst openssl [3.5.0-1ubuntu1] (3.5.0-1ubuntu2 Ubuntu:26.04/resolute-updates [amd64])
|
||||
Conf libssl3t64 (3.5.0-1ubuntu2 Ubuntu:26.04/resolute-updates [amd64])
|
||||
Conf openssl (3.5.0-1ubuntu2 Ubuntu:26.04/resolute-updates [amd64])
|
||||
"""
|
||||
|
||||
|
||||
def test_zurueckgehaltene_pakete_sind_kein_update(monkeypatch):
|
||||
"""25.09.2026: 5 Pakete, die Ubuntu gestaffelt verteilt, hielten das Betriebssystem ewig auf „neu“."""
|
||||
liste = ("Listing...\n"
|
||||
"libssl3t64/resolute-updates 3.5.0-1ubuntu2 amd64 [upgradable from: 3.5.0-1ubuntu1]\n"
|
||||
"openssl/resolute-updates 3.5.0-1ubuntu2 amd64 [upgradable from: 3.5.0-1ubuntu1]\n"
|
||||
"rust-coreutils/resolute-updates 0.10.0-1ubuntu2 amd64 [upgradable from: 0.8.0-0ubuntu3]\n"
|
||||
"ubuntu-release-upgrader-core/resolute-updates 1:26.04.25 all [upgradable from: 1:26.04.23]\n")
|
||||
|
||||
def run(befehl, **kw):
|
||||
text = SIMULATION if "apt-get -s upgrade" in befehl[-1] else liste
|
||||
return subprocess.CompletedProcess(befehl, 0, stdout=text, stderr="")
|
||||
|
||||
monkeypatch.setattr(maintenance.subprocess, "run", run)
|
||||
assert maintenance._os_upgradable() == 2
|
||||
details = maintenance.os_update_details()
|
||||
assert [p["name"] for p in details["packages"]] == ["libssl3t64", "openssl"] and details["count"] == 2
|
||||
assert {p["name"]: p["reason"] for p in details["held_back"]}["rust-coreutils"] == "phasing"
|
||||
monkeypatch.setattr(maintenance.subprocess, "run",
|
||||
lambda befehl, **kw: subprocess.CompletedProcess(befehl, 100, stdout="", stderr=""))
|
||||
assert maintenance._os_upgradable() == 0 and "Paketliste nicht lesbar" in maintenance.PRUEF_FEHLER["os"]
|
||||
|
||||
Reference in New Issue
Block a user