linux-updater: background system updates with history and rollback for any major distro - #389
linux-updater: background system updates with history and rollback for any major distro#389UmedjonBA wants to merge 5 commits into
Conversation
2580fb2 to
93a3972
Compare
Multi-distro system updater grown out of arch-updater: background updates with a live log tail and progress, an update-history strip with rollback, panel-managed ignore lists, and one-click fixes for missing system setup. The engine is distro-neutral; per-manager backends (pacman, dnf, apt, zypper, xbps, PackageKit as the generic fallback) declare capabilities the UI honors, and the right backend is picked from /etc/os-release. Command layers of the non-Arch backends are verified in containers against recorded fixtures; the plugin is fully exercised on Arch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
93a3972 to
8f50bb8
Compare
The thumbnail generator was not used.
The background command separates repository refresh, ignore setup, and the upgrade with If hold or lock setup fails, packages the user explicitly ignored can still be upgraded. Gate the upgrade on successful refresh and ignore
The dependency metadata does not account for every external command spawned by the plugin. Examples include Repository policy requires external commands to be declared in
The Testing status says every backend parser runs against recorded fixtures in CI-able tests, but the PR contains no fixtures or parser |
|
Appreciate the transparency about the relation to #384, and generalizing the engine across distros is genuinely impressive work. Alongside the review that already blocked this on the dependency accounting, the fail-open hold/lock ordering, and the testing-status claim. I want to flag a separate point that those fixes won't resolve on their own. #384 is still an open discussion, not a rejected one. The two structural points I raised there aren't arch-updater-specific, they're about the design of the background-update engine itself:
Since this PR explicitly reuses that same engine, both concerns carry over directly; across six backends now instead of one. That's not a smaller surface than #384, it's a considerably larger one: every backend ( So even once the already-flagged blocking items are fixed, I'd rather we settle the direction on #384 before this moves further. If "background-only, terminal demoted to fallback" isn't acceptable for |
Review items: - Gate apt/zypper/xbps upgrades on successful refresh and hold/lock setup (&&, fail closed) while keeping the cleanup unconditional; regression-tested in tests/run.sh. - Declare every spawned external command in plugin.toml dependencies and document them under README Requirements. - Ship the parser fixtures (fixtures/) and the test harness (tests/run.sh) the Testing status section refers to, and state their CI status precisely. Also, ported from the arch-updater plugin: - update_mode setting: background (default) or terminal-window updates sharing the same log/progress/history; terminal runs are exempt from the stale-log timeout, and their history entries are verified against installed versions so declined packages are not recorded. - Opt-in activity graph of pending-update counts across recent checks. - Fixes: startup race between run-resume and the auto-check, version constraints stripped from rollback dependency lists, flatpak ignore filtering and progress counting in both modes, no terminal retry offered after a failed rollback, polkit hint hidden in terminal mode. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@Reiling-Jeff Thanks for taking the time on this, and for laying out why the two concerns carry over to every backend rather than just the pacman one. I'm working on both sides: the blocking items here, and the design points you raised on #384. I agree they shouldn't be settled twice, so the answer that comes out of #384 is the one I'll apply across all backends here. One practical note: I can't push the update right now. GitHub is having an ongoing incident today (Pull Requests, Actions, Git operations and the API are all degraded — https://www.githubstatus.com), so my pushes keep failing. As soon as it clears I'll send the update. |
Their parsers key on localized text (apt's '[upgradable from: ...]', pkcon's severity words); a non-English locale would count zero updates. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Opt-in extra sources beyond the system manager: global npm, cargo (via cargo-update), pip (check-only, PEP 668), RubyGems, Snap and Homebrew ride along with the check and the update run, honor the plugin ignore list, and roll back per item where their manager has a mechanism (npm/gem/cargo reinstall the recorded version, snap reverts, Flatpak pins the full commit recorded at check time). - Rollback grew two roads: apt from the archive cache (per package and per run, epoch-encoded filenames, probe greys gone entries) and dnf per-package downgrade while the old version is in a repo (cache-only repoquery probe reports the reason before the attempt). - The plugin ignore list is now honored on the PackageKit backend too (explicit pending-minus-ignored package list). - A failing secondary source (AUR mirror down, registry unreachable) no longer aborts the check: it is reported under the headline and the remaining sources are still checked. - Settings that change what a check would count invalidate the last result instead of showing stale numbers; LC_ALL=C pinned wherever output is parsed; scoped npm names accepted in the ignore list without reaching the native backend's hold path. - Version 1.0.0: first public release starts at a clean major. - Fixtures recorded from real containers (node:22, ruby:3.3, rust:1, python:3.12, ubuntu:24.04, fedora:41); the README Testing status section spells out what was verified where, and that snap/brew parsers are from documented formats only.
|
Thanks for the thorough review — all four points addressed, plus a feature/fix round ported from my arch-updater plugin. 1 (blocking, fail-open holds/locks): fixed. 2 (blocking, dependencies): fixed. 3 (non-blocking, testing claim): fixed by shipping the artifacts. The recorded fixtures ( 0 (blocking, thumbnail): regenerated with the thumbnail generator; the checklist item in the PR description is now checked. Also in this push, ported from arch-updater 2.4.0 with multi-backend adaptations:
And a feature round on top — the version is 1.0.0, since this is the plugin's first public release:
|
|
@Reiling-Jeff Both of your structural points are implemented in the update that just landed here, not just promised: update_mode makes the terminal run a first-class mode (every update opens in a terminal window where prompts work as usual — with the log, progress bar and history still working through tee), and terminal runs are exempt from the stale-log timeout for exactly the reason you gave — an interactive prompt held open for an hour is not a stuck process. The launcher also exposes both one-shot actions (update in terminal / update in background), so neither mode is demoted to a fallback. The history entry of a terminal run is verified against the installed versions afterwards, so packages declined at a prompt are not recorded as updated. Happy to continue the direction discussion on #392 — but for this engine the answer is already "both modes, user's choice", applied uniformly across all backends. |
|
---Hey @UmedjonBA, appreciate the work here, the multi-distro backend logic looks solid, but I want to flag the direction before this goes further. When I raised scope concerns on #384/#392, I wasn't saying the background-update/history/rollback work doesn't belong in arch-updater, quite the opposite, we've been iterating on exactly that together and it's close to landing. What I meant was narrower: keep that PR focused on Arch instead of also growing pacman-specific code into a generic abstraction in the same diff. Spinning up linux-updater as a separate plugin that re-implements the same background/history/rollback engine for pacman, dnf, apt, zypper, xbps, and PackageKit means we now have two plugins to keep in sync, two sets of bugs to fix twice, and users choosing between overlapping tools depending on their distro. That's not what I was asking for, and it undercuts the work we're doing on #392. If the goal is genuine multi-distro support, I'd much rather we get #392 merged as the Arch-focused baseline, then talk about factoring the shared engine (update runner, history/rollback, ignore management) out into something arch-updater and other distro plugins can both build on, rather than maintaining a parallel fork. Can we hold off on pushing linux-updater forward until we've aligned on that, so we're not duplicating effort? |
|
@Reiling-Jeff I really like the Noctalia project and I'm glad to be contributing here. Are you on the project's Discord, and what's your handle there? GitHub comments aren't the most convenient way to talk — it'd be great to be able to ping you there if I have questions about the project. |
|
my discord tag is alreadyclaimed |
|
@Reiling-Jeff |
|
@UmedjonBA |
Plugin
umedbazarov/linux-updaterplugin.toml)What it does
A system updater for any major distribution, grown out of
arch-updater(relation disclosed below). One click updates the system in the background: polkit asks for the password, the panel shows a live tail of the update log with a progress bar, the run is fully non-interactive and detached (it survives a shell restart — the engine re-attaches to the log). Finished runs land on a history strip: one segment per run, click opens its package list, and where the distribution supports it packages or whole runs can be rolled back (two-click confirmation; the package manager itself refuses any transaction that would break dependencies). An expandable Ignored section unifies the plugin's own ignore list (editable from package rows) with the system's mechanisms (IgnorePkg,apt-mark hold), and the ignore list is honored during updates. When the system is missing a one-time setup piece — the polkit keep-authorization rule so one password covers a run, apt's list-refresh timers — the panel says so and offers a one-click, one-confirmation fix; nothing is changed silently.The engine is distro-neutral. Each package manager is a backend file (
backends/*.luau) declaring commands, parsers and a capability set the UI honors, so a backend without rollback simply shows no rollback buttons. The backend is picked from/etc/os-release(ID, thenID_LIKE— Manjaro and friends resolve to pacman), overridable in settings:[ignored]detection, download size, Arch news, cache-based per-package/per-run rollback with same-run dependencies,--ignore.dnf history undo(transaction id recorded after each run) plus per-packagednf downgradewhile the old version is still in a repo (a cache-only repoquery probe greys the button with the reason otherwise),needs-restarting,--exclude.apt list --upgradable(relies on the apt-daily timers; a self-check offers to enable them), holds applied for the duration of the transaction, per-package/per-run rollback from the apt archive cache (gone entries greyed out — Ubuntu cleans that cache routinely, Debian keeps it),/var/run/reboot-required.dupon Tumbleweed /upon Leap, locks for the ignore list,zypper needs-rebooting; rollback deliberately off (snapper is the right tool there).xbps-pkgdb; runit-aware (no systemd calls).Flatpak checking/updating works on every backend, and opt-in extra sources (global npm, cargo via cargo-update, pip [check-only — distribution Pythons are externally managed, PEP 668], RubyGems, Snap, Homebrew; each off by default and silently skipped when its tool is absent) ride along with the check and the update run, honor the ignore list, and roll back per item where their manager has a mechanism (npm/gem/cargo reinstall the recorded version,
snap revert, Flatpak pins the full commit recorded at check time). A secondary source that cannot be checked (an unreachable AUR mirror, a registry that is down) fails only itself: the remaining sources are still checked and the panel reports the failed one under the headline. NixOS is intentionally out of scope (nix-monitor already covers it); the backend interface is open for a Gentoo/other contribution. The README carries the full capability matrix and an honest Testing status section.External dependencies
Declared in
dependencies; only the entry matching the distribution is actually needed (the panel reports what is missing):pacman+pacman-contrib, ordnf+rpm, orapt-get+dpkg-query, orzypper+rpm, orxbps-install+xbps-pkgdb, orpkcon; plus POSIX base tools andpkexec; optionalparu/yay,flatpak,sudo,xdg-open,less, a terminal emulator; and, only when the matching extra source is enabled,npm/cargo-install-update/pip/gem/snap/brew.Full accounting: network access equals what the corresponding manual check/upgrade would contact, plus the Arch news feed on the pacman backend. Files are written only to the plugin data directory (
update.log,runs.json,ignore.json,news_state.json,run_meta.json,activity_state.jsonwhen the opt-in activity graph is on, staged polkit rule + install marker) — with one exception:/etc/polkit-1/rules.d/49-linux-updater-<pm>.rules, written bypkexec installonly after the user explicitly clicks the install button and authenticates. Spawned processes per backend are listed in eachbackends/*.luauheader and the README Notes. Package-manager configuration files are never edited; the ignore mechanisms used are the managers' own (hold/lock), applied and released around the transaction.Testing
Arch (pacman backend): fully exercised on a real system — background run including an AUR build (live log, progress, notification, auto re-check), per-package rollback from the cache and roll-forward, ignore/unignore, the polkit rule install button, history strip, engine resume mid-run.
dnf/apt/zypper/xbps/PackageKit: command layers exercised in podman containers on the real package managers — including the full
upgrade → dnf history undocycle and the per-packagednf downgrade+ probe on Fedora 41, apt hold semantics and the cache rollback (a curl+libcurl pair downgraded in one transaction) on Ubuntu 24.04, and PackageKit's explicit-list update leaving the "ignored" package untouched — with outputs recorded as fixtures; all parsers run against those fixtures in a test harness (luauCLI).Extra sources: full update → rollback cycles with the plugin's exact commands in node:22, ruby:3.3 and rust:1 containers; pip's listing in python:3.12; the Flatpak full-commit downgrade story on Ubuntu 24.04. Snap and Homebrew parsers are from documented formats only (snapd needs systemd, brew a full bootstrap) — stated in the README.
Not verified by anyone yet: live polkit dialogs / full UI on non-Arch distributions (containers cannot reproduce a polkit session), the dnf4 output branch, Debian deviations from Ubuntu, snap/brew against live tools. Non-Arch backends are labeled beta in the README; capability flags mean a gap degrades to a missing feature, not a broken system.
Tested on Niri
Tested on Hyprland
Tested on Sway
Tested on another compositor:
Noctalia version tested against: noctalia-git 5.0.0.r5274.gbf4da239d-1
Plugin API level: 9
Screenshots / Videos
In the plugin directory (also embedded in the README):
screenshots/panel.png(pending updates with the download estimate and the polkit-rule offer) andscreenshots/history.png(clean state with the update-history strip after an update → rollback → roll-forward cycle).Checklist
idafter the/inplugin.tomlexactly.plugin.toml,README.md,thumbnail.webp, andtranslations/en.json.README.mdfollows theREADME template, documents
every entry id and dependency, and includes exact panel IPC commands and launcher prefixes where applicable.
thumbnail.webpwith the thumbnail generator.versionfollows semver and is bumped in this PR;plugin_apiis the oldest API level this plugin requires.understand that language well enough to review and maintain it (no unreviewed machine/LLM translations).
catalog.toml; CI generates it.This PR ships
translations/en.jsononly.Code review attestation
Plugins run as trusted, unsandboxed Luau in the user's session. Confirm:
licensedeclared inplugin.toml.Relation to
arch-updater: this plugin generalizes the background-update engine I proposed foryuuto/arch-updaterin #384. If #384's feature part is not wanted there, this standalone plugin is the home for it; the bugfix commit of #384 stands on its own either way.A note on language: the author doesn't speak English and used AI assistance for this text and the review conversation to come. The plugin itself is tested as described above.
🤖 Generated with Claude Code