diff --git a/docs/release-notes/unreleased.md b/docs/release-notes/unreleased.md index 90c07fae..027120d7 100644 --- a/docs/release-notes/unreleased.md +++ b/docs/release-notes/unreleased.md @@ -61,3 +61,7 @@ https://keepachangelog.com/en/1.1.0/ --- - **`4.0.0-B4` — a non-interactive install no longer removes a package it conflicts with because another package in the batch names itself.** Some AUR packages declare `provides` and `conflicts` on their own name (`cbonsai` does). sysforge read that as a drop-in replacing the installed copy and passed `--ask=4`, which pacman applies to every conflict question in the transaction. An `update` that rebuilt `cbonsai` alongside an unrelated conflicting package then removed the installed side without asking, instead of stopping. A package no longer counts as replacing itself, so only a real drop-in (`replaces`, or `conflicts` plus `provides` naming another installed package) gets the auto-confirm. Found by `45-interactive` in CI. + +--- + +- **`4.0.0-B6` — `update --versions` reports a new repo kernel again when the kernel is renamed.** With `[kernel] source = "repo"` and a local name such as `pkgname = "linux-sysforge"`, sysforge looked up the renamed package in pacman's sync database, which only carries `linux`. The lookup found nothing and the kernel was left out, so a pending 7.2.9 → 7.2.11 never appeared in `update --versions` or in the reminder at the end of `update`. The check now falls back to the stock name the build records (`origin_pkgbase`), the same name `run kernel` already uses to pick which repo version to build. diff --git a/sysforge/update.py b/sysforge/update.py index 7ad941a9..116f1ba6 100644 --- a/sysforge/update.py +++ b/sysforge/update.py @@ -604,7 +604,9 @@ def _detect_stage_owned_updates( # The walk's exclusion and the pin's lifecycle stay untouched — # syncing stage-owned sources from `update` is exactly the # double-processing the owner_stage skip exists to prevent. - hit = _stage_owned_repo_advisory(pkgbase, pkgnames, all_installed, owner) + hit = _stage_owned_repo_advisory( + pkgbase, pkgnames, all_installed, owner, + origin=entry.get("origin_pkgbase")) if hit is not None: installed_ver, candidate_ver = hit advisories.append((pkgbase, installed_ver, candidate_ver, owner)) @@ -624,7 +626,7 @@ def _detect_stage_owned_updates( def _stage_owned_repo_advisory( pkgbase: str, pkgnames: list[str], all_installed: dict[str, str], - owner: str = "", + owner: str = "", origin: str | None = None, ) -> tuple[str, str] | None: """Sync-DB candidate for a stage-owned ``source = "repo"`` pkgbase. @@ -633,6 +635,11 @@ def _stage_owned_repo_advisory( unresolvable name, a package the sync DB does not know, or a vercmp failure omits the advisory rather than raising — this path is advisory only and must never fail an update run (3.0.0-B1). + + ``origin`` is the stock upstream base of a locally renamed build (the + kernel's ``linux`` → ``linux-sysforge``): the sync DB knows only that + name, so a miss on the renamed one retries it, as the repo pin does + (2.1.0-B12). Without it a renamed kernel never advised (4.0.0-B6). """ from sysforge.primitives.pacman import get_pacman_sync_version from sysforge.primitives.version import vercmp @@ -645,6 +652,8 @@ def _stage_owned_repo_advisory( continue try: candidate_ver = get_pacman_sync_version(name) + if not candidate_ver and origin and origin != name: + candidate_ver = get_pacman_sync_version(origin) except Exception: # noqa: S112 — advisory only, skip on probe failure continue if not candidate_ver: diff --git a/sysforge/update_version.py b/sysforge/update_version.py index 5fa2e9f6..676ecac8 100644 --- a/sysforge/update_version.py +++ b/sysforge/update_version.py @@ -216,8 +216,8 @@ def _check_one_pkgbase( # For a coexist-renamed package the entry's ``pkgbase`` carries the # renamed value (e.g. ``llvm-sysforge``), but the RPC cache is keyed by # the stock upstream base — so fall back to ``origin_pkgbase`` when the - # renamed base misses. This is the sole read of origin_pkgbase in the - # update path; the rest of the correlation flows through pkgbuild_dir. + # renamed base misses. This is the per-pkgbase check's only read of + # origin_pkgbase; the rest of the correlation flows through pkgbuild_dir. rpc_ver = rpc_version_by_base.get(pkgbase) if not rpc_ver: origin = entry.get("origin_pkgbase") diff --git a/tests/test_update.py b/tests/test_update.py index 54eca1d9..440cb72c 100644 --- a/tests/test_update.py +++ b/tests/test_update.py @@ -763,6 +763,28 @@ def test_detect_stage_owned_repo_unknown_to_sync_db_is_silent(monkeypatch): assert out == [] +def test_detect_stage_owned_repo_renamed_kernel_queries_origin(monkeypatch): + """4.0.0-B6: a repo-sourced kernel renamed locally (`linux` → `linux-sysforge`) + is unknown to the sync DB under its renamed name, so the advisory went + silent and `update --versions` hid a pending 7.2.9 → 7.2.11. Fall back to + ``origin_pkgbase``, the name the repo pin itself queries (2.1.0-B12).""" + import sysforge.update as up + import sysforge.primitives.pacman as pac + sync_db = {"linux": "7.2.11.arch1-1"} + monkeypatch.setattr(pac, "get_pacman_sync_version", sync_db.get) + + entry = {"owner_stage": "kernel", "source": "repo", + "pkgbase": "linux-sysforge", "origin_pkgbase": "linux"} + out = up._detect_stage_owned_updates( + {"linux-sysforge": dict(entry), "linux-sysforge-headers": dict(entry)}, + all_installed={"linux-sysforge": "7.2.9.arch1-1", + "linux-sysforge-headers": "7.2.9.arch1-1"}, + sync_failures={}, rpc_version_by_base={}, pacman_updates_map=None, + skip_sync_check=False, offline=False, + ) + assert out == [("linux-sysforge", "7.2.9.arch1-1", "7.2.11.arch1-1", "kernel")] + + def test_detect_stage_owned_aur_still_uses_rpc_path(monkeypatch): """3.0.0-B1 fixes the repo origin only: AUR-sourced stage-owned packages get their upstream version from RPC without a sync, so they keep running