From b79735d82e4c1b1b95d1f9a01883592c2079f95f Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Wed, 11 Nov 2026 15:35:15 +0100 Subject: [PATCH 1/4] Repo guards check repolist, not just RPMs; PeaZip skips when any flavor exists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Laptop run (YuKu, existing machine) exposed two fresh-install blind spots: 1. Terra add failed on a machine that already HAD the repo but not a queryable terra-release RPM — bootstrapping --repofrompath over an existing repo id collides. New repo_enabled() checks dnf repolist (the source of truth); add_terra_repo and add_rpmfusion_repo now skip when the repo is configured OR the release RPM present. 2. PeaZip tailoring tried gtk3 over an existing peazip-qt5: all UI flavors ship /usr/bin/peazip and file-conflict, transaction died. Any installed flavor (qt5/qt6/gtk3/gtk2) now wins and the section skips with the flavor named. Harness: laptop sim (repo configured, peazip-qt5 present) -> zero bootstrap calls, PeaZip skipped; fresh machine -> terra bootstraps + gtk3 installs; re-run -> skip via repolist; peazip-qt6 + hyprland -> skip; unattended/piped green. --- lib/common.sh | 17 +++++++++++++---- setup.sh | 32 +++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/lib/common.sh b/lib/common.sh index 990146f..307ee52 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -283,9 +283,17 @@ install_group_any() { #------------------------------------------ # Third-party repos #------------------------------------------ +# True when a repo id is CONFIGURED, whatever installed it. This is the +# reliable source of truth: a machine can have the repo without the +# -release RPM (hand-added .repo file) — and bootstrapping over an existing +# repo id via --repofrompath collides and fails (laptop-proven). +repo_enabled() { + dnf repolist --all 2>/dev/null | awk '{print $1}' | grep -qx "$1" +} + add_terra_repo() { - if pkg_installed terra-release; then - ok "Terra repository already installed." + if pkg_installed terra-release || repo_enabled terra; then + ok "Terra repository already present." return 0 fi info "Adding Terra repository (Fyra Labs)..." @@ -299,8 +307,9 @@ add_terra_repo() { add_rpmfusion_repo() { local rel rel=$(rpm -E %fedora) - if pkg_installed rpmfusion-free-release rpmfusion-nonfree-release; then - ok "RPM Fusion already installed." + if pkg_installed rpmfusion-free-release rpmfusion-nonfree-release \ + || { repo_enabled rpmfusion-free && repo_enabled rpmfusion-nonfree; }; then + ok "RPM Fusion already present." return 0 fi info "Enabling RPM Fusion (free + nonfree) for Fedora ${rel}..." diff --git a/setup.sh b/setup.sh index 49867b6..3f48b95 100755 --- a/setup.sh +++ b/setup.sh @@ -639,16 +639,30 @@ rule # --- 8.1 PeaZip: toolkit variant follows the session (Qt6 for Qt-ish # environments, GTK3 for the rest) --- info "Tailoring toolkits for DE=$DE / TWM=$TWM..." -if [[ "$DE" == "plasma" || "$TWM" == "hyprland" ]]; then - peazip_pkgs="peazip-common peazip-qt6" + +# First: is ANY PeaZip flavor already installed? The UI flavors all ship +# /usr/bin/peazip and file-conflict with each other — installing gtk3 over +# an existing qt5 dies mid-transaction (laptop-proven). Any present flavor +# wins; skipping is correct. +peazip_existing="" +local_v="" +for local_v in peazip-qt5 peazip-qt6 peazip-gtk3 peazip-gtk2; do + pkg_installed "$local_v" && peazip_existing="$local_v" +done +if [[ -n "$peazip_existing" ]]; then + ok "PeaZip already present ($peazip_existing) - skipping." else - # XFCE, GNOME, Niri, MangoWC, chadwm: lightweight/generic toolkits - peazip_pkgs="peazip-common peazip-gtk3" -fi -# shellcheck disable=SC2086 -if ! install_packages $peazip_pkgs; then - color_red " Failed: $peazip_pkgs" - color_red " (continuing — PeaZip is a convenience, not a dependency)" + if [[ "$DE" == "plasma" || "$TWM" == "hyprland" ]]; then + peazip_pkgs="peazip-common peazip-qt6" + else + # XFCE, GNOME, Niri, MangoWC, chadwm: lightweight/generic toolkits + peazip_pkgs="peazip-common peazip-gtk3" + fi + # shellcheck disable=SC2086 + if ! install_packages $peazip_pkgs; then + color_red " Failed: $peazip_pkgs" + color_red " (continuing — PeaZip is a convenience, not a dependency)" + fi fi pause_if_debug -- 2.47.3 From 4e0dad3483e49ebae36e2bf881c0bf366b6d7a1e Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Wed, 11 Nov 2026 15:38:57 +0100 Subject: [PATCH 2/4] PeaZip: swap to the wanted flavor when an incompatible one is detected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per YuKu: instead of skipping when an older flavor is present, SWAP it to the environment-appropriate one (dnf swap -y old new). Atomic — if the swap fails, the existing flavor stays and the run continues with a warning (the safe outcome). Right flavor already present -> no-op; fresh machine -> plain install. Verified: qt5+niri -> swap to gtk3 (your laptop scenario); qt6+hyprland -> no-op; forced swap failure -> warn + keep qt5; fresh -> gtk3. --- setup.sh | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/setup.sh b/setup.sh index 3f48b95..6372db7 100755 --- a/setup.sh +++ b/setup.sh @@ -640,29 +640,41 @@ rule # environments, GTK3 for the rest) --- info "Tailoring toolkits for DE=$DE / TWM=$TWM..." -# First: is ANY PeaZip flavor already installed? The UI flavors all ship -# /usr/bin/peazip and file-conflict with each other — installing gtk3 over -# an existing qt5 dies mid-transaction (laptop-proven). Any present flavor -# wins; skipping is correct. +# The UI flavors all ship /usr/bin/peazip and file-conflict with each +# other — installing gtk3 over an existing qt5 dies mid-transaction +# (laptop-proven). Behaviors: +# no flavor -> install the environment-appropriate one +# right flavor -> nothing to do +# OTHER flavor -> dnf SWAP to the wanted one (atomic: on failure the +# existing flavor stays, which is the safe outcome) +if [[ "$DE" == "plasma" || "$TWM" == "hyprland" ]]; then + peazip_wanted="peazip-qt6" +else + # XFCE, GNOME, Niri, MangoWC, chadwm: lightweight/generic toolkits + peazip_wanted="peazip-gtk3" +fi peazip_existing="" local_v="" for local_v in peazip-qt5 peazip-qt6 peazip-gtk3 peazip-gtk2; do pkg_installed "$local_v" && peazip_existing="$local_v" done -if [[ -n "$peazip_existing" ]]; then - ok "PeaZip already present ($peazip_existing) - skipping." -else - if [[ "$DE" == "plasma" || "$TWM" == "hyprland" ]]; then - peazip_pkgs="peazip-common peazip-qt6" - else - # XFCE, GNOME, Niri, MangoWC, chadwm: lightweight/generic toolkits - peazip_pkgs="peazip-common peazip-gtk3" - fi + +if [[ -z "$peazip_existing" ]]; then # shellcheck disable=SC2086 - if ! install_packages $peazip_pkgs; then - color_red " Failed: $peazip_pkgs" + if ! install_packages peazip-common "$peazip_wanted"; then + color_red " Failed: peazip-common $peazip_wanted" color_red " (continuing — PeaZip is a convenience, not a dependency)" fi +elif [[ "$peazip_existing" == "$peazip_wanted" ]]; then + ok "PeaZip already present ($peazip_existing)." +else + info "PeaZip $peazip_existing does not match this environment — swapping to $peazip_wanted..." + if ui_quiet_run "Swapping PeaZip: $peazip_existing -> $peazip_wanted" \ + sudo dnf swap -y "$peazip_existing" "$peazip_wanted"; then + ok "PeaZip swapped to $peazip_wanted." + else + warn "Swap failed — keeping the existing $peazip_existing (fully functional)." + fi fi pause_if_debug -- 2.47.3 From 1586e10df1641282d6e7fa982b9975a5fce75789 Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Wed, 11 Nov 2026 15:42:49 +0100 Subject: [PATCH 3/4] SilentSDDM install: quiet like everything else The theme's own install.sh runs dnf for its dependencies and its output flooded the screen raw (laptop-proven: the last wall of text left in the run). Now wrapped in ui_quiet_run: live block line with the current dependency, summary count after, full output in the setup log, red + tail on failure. Unattended/piped runs keep plain output. pipefail still suspended around the yes| pipe (inherited at subshell fork). --- setup.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/setup.sh b/setup.sh index 6372db7..d37489d 100755 --- a/setup.sh +++ b/setup.sh @@ -762,9 +762,13 @@ if pkg_installed sddm; then if [[ -f "$REPO_DIR/install.sh" ]]; then # yes | install.sh: the installer prompts; SIGPIPE from 'yes' would - # read as a crash under pipefail, so suspend it for this one command + # read as a crash under pipefail, so suspend it for this one command. + # pipefail state is inherited by the ui_quiet_run subshell at fork. + # The theme's own dnf dependency flood goes to the log like every + # other transaction (laptop-proven it was the last raw wall left). set +o pipefail - if ( cd "$REPO_DIR" && yes | ./install.sh ); then + if ui_quiet_run "Installing SilentSDDM theme" \ + bash -c 'cd "$1" && yes | ./install.sh' _ "$REPO_DIR"; then ok "SilentSDDM theme installed." else color_red " Failed: SilentSDDM installer (continuing; SDDM keeps its default theme)" -- 2.47.3 From ee1082945266c6275123fd5d008a036b5a6fc715 Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Wed, 11 Nov 2026 15:46:45 +0100 Subject: [PATCH 4/4] Cosmetic: ANSI line wipe; hide (0 packages) on idempotent re-runs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two nits from YuKu's laptop paste: the 100-space line wipe left a visible gap before short summaries (now ANSI EL: \r\033[K, no residue), and '(0 packages)' printed when nothing new was installed (idempotent re-run / theme deps all present) — the count parenthetical is now omitted when zero. --- lib/common.sh | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/common.sh b/lib/common.sh index 307ee52..75484bf 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -173,18 +173,26 @@ ui_quiet_run() { local rc=0 wait "$pid" || rc=$? - printf '\r%*s\r' 100 '' >&2 + # ANSI erase-line: wipes the live line without leaving trailing spaces + # (a 100-space wipe left a visible gap when the summary was shorter) + printf '\r\033[K' >&2 if (( rc == 0 )); then n=$(sed -n "$((before+1)),\$p" "$log" 2>/dev/null | grep -ac '^Installing' || true) - local plural="s" - (( n == 1 )) && plural="" + local count_txt="" + if (( n > 0 )); then + local plural="s" + (( n == 1 )) && plural="" + count_txt=" (${n} package${plural})" + fi + # n == 0 means nothing new was installed (idempotent re-run / + # deps already present): print the message without a count. if (( depth == 256 )); then - printf '\033[48;5;34m \033[0m %s (%s package%s)\n' "$msg" "$n" "$plural" >&2 + printf '\033[48;5;34m \033[0m %s%s\n' "$msg" "$count_txt" >&2 elif (( depth == 16 )); then - printf '\033[42m \033[0m %s (%s package%s)\n' "$msg" "$n" "$plural" >&2 + printf '\033[42m \033[0m %s%s\n' "$msg" "$count_txt" >&2 else - ok "$msg (${n} package${plural})" + ok "$msg${count_txt}" fi return 0 else -- 2.47.3