From a15f019c17e66444b3fc236543c89f8331f181a1 Mon Sep 17 00:00:00 2001 From: Gabriel Brown Date: Wed, 19 Aug 2026 18:24:30 -0400 Subject: [PATCH] Offer automatic package downloads, now that the machinery is installed The page had a row for the case where dnf-automatic is absent and nothing for the case where it is present, so installing it made the setting disappear rather than appear. The switch enables downloading only, which is the shipped default and the right one to keep: a machine that installs packages unattended can reboot into a kernel nobody chose. Downloading ahead of time is what makes the install quick when someone does choose it, and the row says exactly that rather than implying updates apply themselves. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L --- .../modules/settings/UpdatesPage.qml | 15 +++++++++++-- config/dot/quickshell/scripts/panama-updates | 21 ++++++++++++++++++- config/dot/quickshell/services/Updates.qml | 8 +++++++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/config/dot/quickshell/modules/settings/UpdatesPage.qml b/config/dot/quickshell/modules/settings/UpdatesPage.qml index d584dc6..3501712 100644 --- a/config/dot/quickshell/modules/settings/UpdatesPage.qml +++ b/config/dot/quickshell/modules/settings/UpdatesPage.qml @@ -245,8 +245,19 @@ SettingsPage { onTriggered: Updates.apply("firmware") } - // Reported rather than offered. dnf-automatic is a package this machine - // does not have, and installing software is not a settings action. + // Offered only when the machinery exists. When it does not, this says + // so rather than showing a switch that could not do anything -- + // installing software is not a settings action. + SwitchRow { + visible: Updates.automatic?.dnfAutomaticAvailable === true + label: "Download package updates automatically" + detail: "Fetches them in the background each morning so installing is quick. It does not install them: a machine that updates packages unattended can reboot into a kernel nobody chose." + checked: Updates.automatic?.dnfAutomaticEnabled === true + enabled: !Updates.busy + divider: false + onToggled: value => Updates.setAutomaticDnf(value) + } + TextRow { visible: Updates.automatic?.dnfAutomaticAvailable === false label: "Automatic package updates" diff --git a/config/dot/quickshell/scripts/panama-updates b/config/dot/quickshell/scripts/panama-updates index 91093e7..76295db 100755 --- a/config/dot/quickshell/scripts/panama-updates +++ b/config/dot/quickshell/scripts/panama-updates @@ -256,6 +256,23 @@ def apply(source: str) -> dict: raise BoundaryError("That is not an update source.") +def set_auto_dnf(enabled: bool) -> None: + """Enable the packaging timer, which DOWNLOADS updates but does not apply them. + + That is the shipped default (apply_updates = no) and it is the right one to + leave alone: a machine that installs packages unattended can reboot into a + kernel nobody chose. Downloading ahead of time makes the install quick when + someone does choose it. + """ + state = automatic_state() + if not state["dnfAutomaticAvailable"]: + raise BoundaryError("Automatic package updates are not installed.") + action = ["enable", "--now"] if enabled else ["disable", "--now"] + result = run(["pkexec", "systemctl", *action, "dnf5-automatic.timer"], timeout=120) + if result.returncode != 0: + raise BoundaryError(_refusal(result, "Automatic package updates could not be changed.")) + + def set_auto_flatpak(enabled: bool) -> None: action = ["enable", "--now"] if enabled else ["disable", "--now"] result = run(["systemctl", "--user", *action, FLATPAK_TIMER], timeout=60) @@ -294,10 +311,12 @@ def main(arguments: list[str]) -> int: return 0 if len(arguments) == 2 and arguments[0] == "set-auto-flatpak": set_auto_flatpak(arguments[1] == "true") + elif len(arguments) == 2 and arguments[0] == "set-auto-dnf": + set_auto_dnf(arguments[1] == "true") else: raise BoundaryError( "Usage: panama-updates snapshot | check | apply dnf|flatpak|firmware | " - "set-auto-flatpak true|false") + "set-auto-flatpak true|false | set-auto-dnf true|false") except BoundaryError as error: state = snapshot() state["error"] = str(error) diff --git a/config/dot/quickshell/services/Updates.qml b/config/dot/quickshell/services/Updates.qml index 8b7055e..76c1eea 100644 --- a/config/dot/quickshell/services/Updates.qml +++ b/config/dot/quickshell/services/Updates.qml @@ -106,6 +106,14 @@ Singleton { applyProcess.running = true; } + function setAutomaticDnf(enabled: bool): void { + if (applyProcess.running) + return; + root.lastError = ""; + applyProcess.command = [root.helperPath, "set-auto-dnf", enabled ? "true" : "false"]; + applyProcess.running = true; + } + function setAutomaticFlatpak(enabled: bool): void { if (applyProcess.running) return;