Fix the install pipeline and an idle-lock startup race

The initial package list was quoted into a single bogus dnf argument
and every dnf error was discarded, so a fresh install silently skipped
most of it. Two package lists were never wired into the pipeline at
all, and change-settings ran before install-packages, so the vicinae
theme step was permanently skipped. Fixed the ordering, the quoting,
and stopped swallowing errors.

Separately, hypridle could start with its WAYLAND_DISPLAY condition
unmet if it raced the env-publish call, silently never starting --
and it's the only listener for the logind Lock signal. Made the start
wait on the environment synchronously. panama-idle also wrote its
generated config to a fixed temp path with no locking, so concurrent
applies could interleave into a corrupt file; switched to mktemp plus
an atomic mv.

Claude-Session: https://claude.ai/code/session_01E6TJUAh41HaP25MVHWkhRZ
This commit is contained in:
Gabriel Brown
2026-08-18 21:22:52 -04:00
parent c37ca3baee
commit 70d8d32ee2
8 changed files with 91 additions and 20 deletions
+10 -2
View File
@@ -23,8 +23,16 @@ hl.on("hyprland.start", function()
hl.exec_cmd("dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=Hyprland")
hl.exec_cmd("systemctl --user start hyprland-session.target")
-- Units: polkit prompts, wallpaper, launcher daemon, idle/lock.
hl.exec_cmd("systemctl --user start hyprpolkitagent.service hyprpaper.service vicinae.service hypridle.service")
-- Units: polkit prompts, wallpaper, launcher daemon, idle/lock. All four
-- carry `ConditionEnvironment=WAYLAND_DISPLAY`, and hl.exec_cmd fires
-- commands without waiting for them to finish, so the dbus-update call
-- above racing this one is not safe to assume complete -- a lost race
-- leaves the Condition unmet and the unit silently never starts (exit 0,
-- no error). hypridle is the only listener for the logind Lock signal,
-- so that failure mode is "lock-session goes to nobody". Re-import
-- synchronously in the same shell invocation first so the Condition
-- always sees it, regardless of how the dbus-update call above scheduled.
hl.exec_cmd("systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP && systemctl --user start hyprpolkitagent.service hyprpaper.service vicinae.service hypridle.service")
-- The shell: bar, dock, overview, quick settings, notifications, capture.
-- No systemd unit ships with quickshell, so it runs as a compositor child.
+15 -2
View File
@@ -25,6 +25,14 @@ generated="$state_dir/hypridle.conf"
dropin_dir="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/hypridle.service.d"
dropin="$dropin_dir/panama.conf"
# Set by generate() to the mktemp path it is currently writing, so concurrent
# invocations (e.g. rapid settings changes each spawning `apply`) never share
# a tmp file and interleave writes into a corrupt hypridle.conf. Cleared once
# the atomic mv below lands, so this is a no-op on a normal exit.
generated_tmp=""
cleanup() { rm -f "$generated_tmp" 2>/dev/null || true; }
trap cleanup EXIT
read_setting() {
local key="$1" fallback="$2"
[[ -r "$settings" ]] || { printf '%s' "$fallback"; return; }
@@ -53,6 +61,10 @@ generate() {
load
mkdir -p "$state_dir"
# Unique per invocation, in the same directory as the destination so the
# final mv is an atomic same-filesystem rename rather than a copy.
generated_tmp="$(mktemp "$generated.XXXXXX")"
{
printf '# Generated by panama-idle from %s\n' "$settings"
printf '# Do not edit: it is rewritten whenever the idle settings change.\n'
@@ -91,9 +103,10 @@ generate() {
printf ' on-timeout = systemctl suspend\n'
printf '}\n'
fi
} >"$generated.tmp"
} >"$generated_tmp"
mv "$generated.tmp" "$generated"
mv "$generated_tmp" "$generated"
generated_tmp=""
}
install_dropin() {