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;