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:
@@ -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("dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=Hyprland")
|
||||||
hl.exec_cmd("systemctl --user start hyprland-session.target")
|
hl.exec_cmd("systemctl --user start hyprland-session.target")
|
||||||
|
|
||||||
-- Units: polkit prompts, wallpaper, launcher daemon, idle/lock.
|
-- Units: polkit prompts, wallpaper, launcher daemon, idle/lock. All four
|
||||||
hl.exec_cmd("systemctl --user start hyprpolkitagent.service hyprpaper.service vicinae.service hypridle.service")
|
-- 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.
|
-- The shell: bar, dock, overview, quick settings, notifications, capture.
|
||||||
-- No systemd unit ships with quickshell, so it runs as a compositor child.
|
-- No systemd unit ships with quickshell, so it runs as a compositor child.
|
||||||
|
|||||||
@@ -25,6 +25,14 @@ generated="$state_dir/hypridle.conf"
|
|||||||
dropin_dir="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/hypridle.service.d"
|
dropin_dir="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/hypridle.service.d"
|
||||||
dropin="$dropin_dir/panama.conf"
|
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() {
|
read_setting() {
|
||||||
local key="$1" fallback="$2"
|
local key="$1" fallback="$2"
|
||||||
[[ -r "$settings" ]] || { printf '%s' "$fallback"; return; }
|
[[ -r "$settings" ]] || { printf '%s' "$fallback"; return; }
|
||||||
@@ -53,6 +61,10 @@ generate() {
|
|||||||
load
|
load
|
||||||
mkdir -p "$state_dir"
|
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 '# Generated by panama-idle from %s\n' "$settings"
|
||||||
printf '# Do not edit: it is rewritten whenever the idle settings change.\n'
|
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 ' on-timeout = systemctl suspend\n'
|
||||||
printf '}\n'
|
printf '}\n'
|
||||||
fi
|
fi
|
||||||
} >"$generated.tmp"
|
} >"$generated_tmp"
|
||||||
|
|
||||||
mv "$generated.tmp" "$generated"
|
mv "$generated_tmp" "$generated"
|
||||||
|
generated_tmp=""
|
||||||
}
|
}
|
||||||
|
|
||||||
install_dropin() {
|
install_dropin() {
|
||||||
|
|||||||
@@ -49,10 +49,16 @@ gsettings set org.gnome.desktop.session idle-delay 0 2>/dev/null || true
|
|||||||
# still run: a missing optional package should not stop the dotfiles being
|
# still run: a missing optional package should not stop the dotfiles being
|
||||||
# linked. The summary at the end is what decides whether the install worked,
|
# linked. The summary at the end is what decides whether the install worked,
|
||||||
# because a failure scrolled past twenty minutes ago is a failure nobody saw.
|
# because a failure scrolled past twenty minutes ago is a failure nobody saw.
|
||||||
|
#
|
||||||
|
# Explicit order, not glob order: change-settings runs `vicinae theme set`,
|
||||||
|
# which needs both vicinae itself (installed by install-packages) and the
|
||||||
|
# theme files it selects among (symlinked into place by link-dotfiles). New
|
||||||
|
# scripts must be added here explicitly, or they will not run at all.
|
||||||
|
STAGES=(install-packages link-dotfiles change-settings link-vicinae-scripts)
|
||||||
failed=()
|
failed=()
|
||||||
for script in "$PANAMA_PATH"/setup/scripts/*; do
|
for stage in "${STAGES[@]}"; do
|
||||||
|
script="$PANAMA_PATH/setup/scripts/$stage"
|
||||||
[[ -x "$script" ]] || continue
|
[[ -x "$script" ]] || continue
|
||||||
stage="$(basename "$script")"
|
|
||||||
printf '\n=== %s ===\n' "$stage"
|
printf '\n=== %s ===\n' "$stage"
|
||||||
if ! "$script"; then
|
if ! "$script"; then
|
||||||
failed+=("$stage")
|
failed+=("$stage")
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ mokutil
|
|||||||
mozilla-openh264
|
mozilla-openh264
|
||||||
nautilus-extensions
|
nautilus-extensions
|
||||||
nautilus-python
|
nautilus-python
|
||||||
|
nextcloud-client
|
||||||
openssl-devel
|
openssl-devel
|
||||||
opus-devel
|
opus-devel
|
||||||
python3-dnf-plugin-versionlock
|
python3-dnf-plugin-versionlock
|
||||||
|
|||||||
@@ -2,3 +2,5 @@ org.gtk.Gtk3theme.adw-gtk3-dark
|
|||||||
io.github.Foldex.AdwSteamGtk
|
io.github.Foldex.AdwSteamGtk
|
||||||
com.bitwarden.desktop
|
com.bitwarden.desktop
|
||||||
app.bluebubbles.BlueBubbles
|
app.bluebubbles.BlueBubbles
|
||||||
|
org.mozilla.thunderbird_esr
|
||||||
|
io.missioncenter.MissionCenter
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ gpu-screen-recorder
|
|||||||
grim
|
grim
|
||||||
grimblast
|
grimblast
|
||||||
gtk-update-icon-cache
|
gtk-update-icon-cache
|
||||||
|
helium-browser-bin
|
||||||
hypridle
|
hypridle
|
||||||
hyprland
|
hyprland
|
||||||
hyprland-guiutils
|
hyprland-guiutils
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
# --- Helper functions ---
|
# --- Helper functions ---
|
||||||
log() { echo -e "\033[1;34m[INFO]\033[0m $*"; }
|
log() { echo -e "\033[1;34m[INFO]\033[0m $*"; }
|
||||||
exists() { command -v "$1" >/dev/null 2>&1; }
|
exists() { command -v "$1" >/dev/null 2>&1; }
|
||||||
@@ -10,33 +12,37 @@ LOCAL_BIN_PATH="$HOME/.local/bin"
|
|||||||
|
|
||||||
echo -e "\n--- Installing Repositories ---"
|
echo -e "\n--- Installing Repositories ---"
|
||||||
log "Installing RPM Fusion Free and Nonfree Repositories"
|
log "Installing RPM Fusion Free and Nonfree Repositories"
|
||||||
sudo dnf install -y https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm > /dev/null 2>&1
|
sudo dnf install -y https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm > /dev/null
|
||||||
log "Enabling Fedora Cisco OpenH264 Repository"
|
log "Enabling Fedora Cisco OpenH264 Repository"
|
||||||
sudo dnf config-manager setopt fedora-cisco-openh264.enabled=1
|
sudo dnf config-manager setopt fedora-cisco-openh264.enabled=1
|
||||||
log "Installing RPM Fusion AppStream Metadata"
|
log "Installing RPM Fusion AppStream Metadata"
|
||||||
sudo dnf update @core -y > /dev/null 2>&1
|
sudo dnf update @core -y > /dev/null
|
||||||
sudo dnf install -y rpmfusion-\*-appstream-data > /dev/null 2>&1
|
sudo dnf install -y rpmfusion-\*-appstream-data > /dev/null
|
||||||
log "Installing Terra Repository"
|
log "Installing Terra Repository"
|
||||||
sudo dnf install -y --nogpgcheck --repofrompath 'terra,https://repos.fyralabs.com/terra$releasever' terra-release > /dev/null 2>&1
|
sudo dnf install -y --nogpgcheck --repofrompath 'terra,https://repos.fyralabs.com/terra$releasever' terra-release > /dev/null
|
||||||
|
|
||||||
echo -e "\n--- Installing relevant packages ---"
|
echo -e "\n--- Installing relevant packages ---"
|
||||||
log "Updating all packages. This may take a while"
|
log "Updating all packages. This may take a while"
|
||||||
sudo dnf update -y --refresh > /dev/null 2>&1
|
sudo dnf update -y --refresh > /dev/null
|
||||||
|
|
||||||
log "Updating core, multimedia, and sound-and-video groups"
|
log "Updating core, multimedia, and sound-and-video groups"
|
||||||
|
# A trailing `&& sync` here previously meant a failing groupupdate was exempt
|
||||||
|
# from set -e (bash does not apply -e to the left side of a && list), so the
|
||||||
|
# failure went unreported. Sync unconditionally on its own line instead.
|
||||||
sudo dnf4 groupupdate -y 'core' 'multimedia' 'sound-and-video' \
|
sudo dnf4 groupupdate -y 'core' 'multimedia' 'sound-and-video' \
|
||||||
--setop='install_weak_deps=False' \
|
--setop='install_weak_deps=False' \
|
||||||
--exclude='PackageKit-gstreamer-plugin' \
|
--exclude='PackageKit-gstreamer-plugin' \
|
||||||
--allowerasing && sync > /dev/null 2>&1
|
--allowerasing > /dev/null
|
||||||
|
sync
|
||||||
log "Swapping ffmpeg-free for ffmpeg"
|
log "Swapping ffmpeg-free for ffmpeg"
|
||||||
sudo dnf swap -y 'ffmpeg-free' 'ffmpeg' --allowerasing > /dev/null 2>&1
|
sudo dnf swap -y 'ffmpeg-free' 'ffmpeg' --allowerasing > /dev/null
|
||||||
log "Swapping mesa-va-drivers for mesa-va-drivers-freeworld"
|
log "Swapping mesa-va-drivers for mesa-va-drivers-freeworld"
|
||||||
sudo dnf swap -y mesa-va-drivers mesa-va-drivers-freeworld > /dev/null 2>&1
|
sudo dnf swap -y mesa-va-drivers mesa-va-drivers-freeworld > /dev/null
|
||||||
log "Upgrading Multimedia group with optional packages"
|
log "Upgrading Multimedia group with optional packages"
|
||||||
sudo dnf4 group upgrade -y --with-optional Multimedia > /dev/null 2>&1
|
sudo dnf4 group upgrade -y --with-optional Multimedia > /dev/null
|
||||||
log "Installing GStreamer plugins (bad, good, base)"
|
log "Installing GStreamer plugins (bad, good, base)"
|
||||||
sudo dnf install -y gstreamer1-plugins-{bad-\*,good-\*,base} \
|
sudo dnf install -y gstreamer1-plugins-{bad-\*,good-\*,base} \
|
||||||
--exclude=gstreamer1-plugins-bad-free-devel > /dev/null 2>&1
|
--exclude=gstreamer1-plugins-bad-free-devel > /dev/null
|
||||||
|
|
||||||
# --- Install all initial packages ---
|
# --- Install all initial packages ---
|
||||||
PACKAGES_FILE="$PANAMA_PATH/setup/packages/initial-packages"
|
PACKAGES_FILE="$PANAMA_PATH/setup/packages/initial-packages"
|
||||||
@@ -45,12 +51,25 @@ if [[ -f "$PACKAGES_FILE" ]]; then
|
|||||||
log "Installing Initial Packages"
|
log "Installing Initial Packages"
|
||||||
echo -e "Includes the following packages:"
|
echo -e "Includes the following packages:"
|
||||||
echo -e "$(<"$PACKAGES_FILE")"
|
echo -e "$(<"$PACKAGES_FILE")"
|
||||||
sudo dnf install -y "$INITIAL_PACKAGES" > /dev/null 2>&1
|
sudo dnf install -y $INITIAL_PACKAGES > /dev/null
|
||||||
log "Initial packages installed!"
|
log "Initial packages installed!"
|
||||||
else
|
else
|
||||||
log "Package list was not in specified path: $PACKAGES_FILE"
|
log "Package list was not in specified path: $PACKAGES_FILE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# --- Install Desktop Packages ---
|
||||||
|
DESKTOP_FILE="$PANAMA_PATH/setup/packages/desktop-packages"
|
||||||
|
if [[ -f "$DESKTOP_FILE" ]]; then
|
||||||
|
DESKTOP_PACKAGES=$(tr "\n" " " <"$DESKTOP_FILE")
|
||||||
|
log "Installing Desktop Packages"
|
||||||
|
echo -e "Includes the following packages:"
|
||||||
|
echo -e "$(<"$DESKTOP_FILE")"
|
||||||
|
sudo dnf install -y $DESKTOP_PACKAGES > /dev/null
|
||||||
|
log "Desktop packages installed!"
|
||||||
|
else
|
||||||
|
log "Package list was not in specified path: $DESKTOP_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
# --- Install oh-my-posh if not already installed. ---
|
# --- Install oh-my-posh if not already installed. ---
|
||||||
mkdir -p "$LOCAL_BIN_PATH"
|
mkdir -p "$LOCAL_BIN_PATH"
|
||||||
if [[ -x "$LOCAL_BIN_PATH/oh-my-posh" ]]; then
|
if [[ -x "$LOCAL_BIN_PATH/oh-my-posh" ]]; then
|
||||||
@@ -67,7 +86,7 @@ if [[ -f "$DEV_FILE" ]]; then
|
|||||||
log "Installing Development Packages. Mostly for Neovim."
|
log "Installing Development Packages. Mostly for Neovim."
|
||||||
echo -e "Includes the following packages:"
|
echo -e "Includes the following packages:"
|
||||||
echo -e "$(<"$DEV_FILE")"
|
echo -e "$(<"$DEV_FILE")"
|
||||||
sudo dnf install -y $DEV_PACKAGES > /dev/null 2>&1
|
sudo dnf install -y $DEV_PACKAGES > /dev/null
|
||||||
log "Development packages installed!"
|
log "Development packages installed!"
|
||||||
else
|
else
|
||||||
log "Package list was not in specified path: $DEV_FILE"
|
log "Package list was not in specified path: $DEV_FILE"
|
||||||
@@ -78,12 +97,12 @@ fi
|
|||||||
HYPR_FILE="$PANAMA_PATH/setup/packages/hyprland-packages"
|
HYPR_FILE="$PANAMA_PATH/setup/packages/hyprland-packages"
|
||||||
if [[ -f "$HYPR_FILE" ]]; then
|
if [[ -f "$HYPR_FILE" ]]; then
|
||||||
log "Enabling Hyprland COPR"
|
log "Enabling Hyprland COPR"
|
||||||
sudo dnf copr enable -y lionheartp/Hyprland > /dev/null 2>&1
|
sudo dnf copr enable -y lionheartp/Hyprland > /dev/null
|
||||||
HYPR_PACKAGES=$(tr "\n" " " <"$HYPR_FILE")
|
HYPR_PACKAGES=$(tr "\n" " " <"$HYPR_FILE")
|
||||||
log "Installing Hyprland desktop packages"
|
log "Installing Hyprland desktop packages"
|
||||||
echo -e "Includes the following packages:"
|
echo -e "Includes the following packages:"
|
||||||
echo -e "$(<"$HYPR_FILE")"
|
echo -e "$(<"$HYPR_FILE")"
|
||||||
sudo dnf install -y --setopt=install_weak_deps=False $HYPR_PACKAGES > /dev/null 2>&1
|
sudo dnf install -y --setopt=install_weak_deps=False $HYPR_PACKAGES > /dev/null
|
||||||
log "Hyprland packages installed!"
|
log "Hyprland packages installed!"
|
||||||
else
|
else
|
||||||
log "Package list was not in specified path: $HYPR_FILE"
|
log "Package list was not in specified path: $HYPR_FILE"
|
||||||
@@ -96,3 +115,18 @@ else
|
|||||||
log "Installing Bun via curl..."
|
log "Installing Bun via curl..."
|
||||||
curl -fsSL https://bun.sh/install | bash > /dev/null 2>&1
|
curl -fsSL https://bun.sh/install | bash > /dev/null 2>&1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# --- Install Flatpak Packages ---
|
||||||
|
FLATPAK_FILE="$PANAMA_PATH/setup/packages/flatpak-packages"
|
||||||
|
if [[ -f "$FLATPAK_FILE" ]]; then
|
||||||
|
FLATPAK_PACKAGES=$(tr "\n" " " <"$FLATPAK_FILE")
|
||||||
|
log "Adding Flathub remote"
|
||||||
|
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo > /dev/null
|
||||||
|
log "Installing Flatpak Packages"
|
||||||
|
echo -e "Includes the following packages:"
|
||||||
|
echo -e "$(<"$FLATPAK_FILE")"
|
||||||
|
sudo flatpak install -y flathub $FLATPAK_PACKAGES > /dev/null
|
||||||
|
log "Flatpak packages installed!"
|
||||||
|
else
|
||||||
|
log "Package list was not in specified path: $FLATPAK_FILE"
|
||||||
|
fi
|
||||||
|
|||||||
@@ -63,6 +63,12 @@ for dir in "${dirs[@]}"; do
|
|||||||
if [ -d "$CONFIG/$dir" ]; then
|
if [ -d "$CONFIG/$dir" ]; then
|
||||||
mv "$CONFIG/$dir" "$PANAMA_OLD/$dir"
|
mv "$CONFIG/$dir" "$PANAMA_OLD/$dir"
|
||||||
log "Moved existing $dir config to $PANAMA_OLD/$dir"
|
log "Moved existing $dir config to $PANAMA_OLD/$dir"
|
||||||
|
# A regular file at this path (not a directory, not a symlink) is missed by
|
||||||
|
# the guards above, so `ln -s` below would fail with "File exists" -- back
|
||||||
|
# it up the same way.
|
||||||
|
elif [ -f "$CONFIG/$dir" ]; then
|
||||||
|
mv "$CONFIG/$dir" "$PANAMA_OLD/$dir"
|
||||||
|
log "Moved existing $dir file to $PANAMA_OLD/$dir"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create symlink
|
# Create symlink
|
||||||
|
|||||||
Reference in New Issue
Block a user