Commit Graph
37 Commits
Author SHA1 Message Date
yuri 1869743d4a Merge pull request 'Quiet dnf + live ASCII progress (recovered from orphaned PR #7)' (#8) from feat/quiet-dnf-recovered into main 2026-10-27 19:49:51 +01:00
yuri 3e23ce1210 Merge pull request 'gum TUI with plain-text fallback' (#6) from feat/gum-tui into main 2026-10-27 19:49:14 +01:00
Pathfinder 4cf680b854 ASCII-only spinner frames and output (VM locale rendered braille as garbage)
The braille spinner frames and the em-dash separator are multibyte
UTF-8; on the VM session they rendered as changing random letters, not
a spinner. Frames are now the classic | / - \ cycle, the separator is
':', and the two user-facing info lines that carried em-dashes are
ASCII too. Verified under LANG=C LC_ALL=C in a pty: zero non-ASCII
bytes in the entire output.
2026-10-27 19:42:30 +01:00
Pathfinder 0050f3a4a8 Prime sudo up front (sudo -v) — password prompt no longer lands mid-line
First sudo call of the session printed its password prompt straight
into the live progress line: 'Installing (optional): gum[sudo]
password for yuri:' (VM screenshot). sudo -v asks once, on a clean
screen, right after the banner; the timestamp refreshes on every later
sudo use, so one prompt covers the whole run.
2026-10-27 19:37:20 +01:00
Pathfinder a54f14018e Live progress line instead of gum spin (VM: frozen block, 'looks hung')
gum spin rendered static on the real VM during long transactions.
ui_quiet_run now draws its own line: braille spinner frame + the
package dnf is currently working on (from the transaction log), at
150ms ticks. Works without gum (pure bash), gated on interactive
terminal, not on gum.

set -e + pipefail bug found via pty trace: the first tick races the
child's first log line, grep exits 1 (no match) and pipefail turns the
whole substitution nonzero, killing the script silently at the first
frame. || true on the substitution pipeline fixes it.
2026-10-27 19:31:22 +01:00
Pathfinder 9dd1ecada8 Quiet dnf transactions: spinner + one-line summary, log on failure
ui_quiet_run wraps every install_packages/install_optional/group
install/remove and the system update: while gum is available and the
run is interactive, dnf output is hidden behind a spinner, then a
single 'Installing: <pkgs> (N packages)' line. Full output is appended
to $SETUP_DNF_LOG (/tmp/fedora-setup-dnf-<uid>.log); on failure the
last 20 lines print in red so nothing is lost. Unattended and no-gum
runs keep plain full output (logs/cron contract).

Also: fallback ui_choose accepts 'x' to exit (muscle memory from the
old menu), fixed a stray stdout newline leaking into captured answers
(same class as the earlier '\nno' bug), fixed pluralization.

Harness: piped fallback, pty gum run incl. a failing VirtualBox pick
(red failure + log tail, menu survives, subsequent qemu install ok),
unattended regression.
2026-10-27 19:20:31 +01:00
Pathfinder c6e41cbf1e gum TUI with plain-text fallback (lib/ui.sh)
Interactive install gets styled menus, confirms, multi-select and a
spinner around the system update when gum is available (dnf install
gum, installed optionally in the base section); every prompt falls
back to the classic numbered/yn prompts otherwise, and --yes runs
stay 100% non-interactive.

Call sites moved to ui_choose/ui_confirm/ui_choose_multi/ui_run:
DE + TWM menus (defaults preserved: none/none), SELinux + dotfiles
questions, advanced-menu category + multi-select app picker, reboot
prompt. Dead ask_choice/ask_yes_no removed.

Two bugs caught by pty-based harness testing before shipping:
- stdout is a pipe inside $(ui_...), so have_gum must test stdin +
  /dev/tty, never -t 1 (gum would never have fired on a real term).
- fallback display output must go to >&2 — a stray newline on stdout
  made choice='\nno' and broke every case match.
2026-10-27 19:09:58 +01:00
yuri 2b58c4f788 Merge pull request 'libvirt group: gate on daemon/virt-manager, not the metapkg' (#5) from fix/libvirt-group-gate into main 2026-10-27 15:58:59 +01:00
Pathfinder f069026a7c libvirt group: check at summary time (final state) + OR-semantics gate
Fresh-VM timeline explained: on run 1 virt-manager installs AFTER the
niri module's prereq check ran (menu dispatch order), so the group add
was evaluated against a package state that did not include it yet. A
second run 'fixed' it — matching the observed behavior.

- New ensure_libvirt_group runs in the Summary section, seeing the FINAL
  package state; menu/module-time check kept as an early pass.
- pkg_installed is AND-semantics (all must be installed); the gate needs
  OR. New pkg_installed_any helper; both gates switched to it.
- Also fixed a set -e trap: '$done_any && ok' returned 1 (killing the
  script) when no optional tools were picked — replaced with an if.
All four gate cases harness-proven: virt-only, menu-pick, no-virt,
already-in-group.
2026-10-27 15:50:30 +01:00
Pathfinder df56379556 libvirt group gate: virt-manager alone justifies membership
Fresh-VM repro: user in yuri+wheel with virt-manager installed. Gate was
'pkg_installed libvirt', but virt-manager does NOT require the 'libvirt'
metapkg (verified vs F44 package page: requires libvirt-glib etc., client
side only) — so the usermod never fired.

Gate now: libvirt OR libvirt-daemon OR libvirt-daemon-driver-qemu OR
virt-manager packages, or an existing /usr/sbin/libvirtd binary.
2026-10-27 15:32:41 +01:00
yuri 847e76614a Merge pull request 'Polkit agent + libvirt group (fixes virt-manager connection failure)' (#4) from fix/polkit-agent-libvirt into main 2026-10-27 15:28:59 +01:00
Pathfinder c552b30112 Advanced menu libvirt wiring: use SUDO_USER fallback like session prereqs
usermod used $USER directly; under sudo $USER can be root. All other
user-scoped calls already use ${SUDO_USER:-$USER} — aligned. No hardcoded
usernames anywhere in the repo (verified by grep; only the dotfiles repo
URL, which is overridable via DOTFILES_REPO).
2026-10-27 15:19:08 +01:00
Pathfinder e99c60a073 Session prereqs: libvirt group membership when libvirt is installed
The error CHANGED on the VM: 'no polkit agent' -> 'access denied by
policy' — the agent unit works; polkit now denies because the user is
not in the libvirt group (fresh run without picking QEMU from the menu,
or no re-login after the pick).

install_session_prereqs now adds the user to the libvirt group whenever
libvirt is installed (idempotent via id -nG check), decoupled from the
advanced-menu choice. Applies after re-login.
2026-10-27 15:14:22 +01:00
Pathfinder 0814c5bde7 polkit agent via user systemd unit, not XDG autostart
Second VM failure: Fedora's polkit-kde .desktop carries
X-systemd-skip=true (and OnlyShowIn on some versions), so niri's
xdg-desktop-autostart.target skips the agent regardless — package
installed, agent dead, same error.

Stop fighting .desktop semantics: install a polkit-agent.service USER
unit (WantedBy=graphical-session.target, which niri/Hyprland/Mango all
bring up) with the Fedora kf6 binary path, pre-linked into
graphical-session.target.wants. Idempotent on both file and symlink.
2026-10-27 14:51:44 +01:00
Pathfinder 6a9941771a polkit-kde agent never starts in niri: strip OnlyShowIn=KDE
The VM error persisted with polkit-kde installed: the package's autostart
.desktop carries OnlyShowIn=KDE;, so XDG autostart (which niri honors via
xdg-desktop-autostart.target) skips the agent in a niri session. Package
present, agent never running — exactly the observed behavior.

install_session_prereqs now rewrites the .desktop without the OnlyShowIn
line in place (idempotent: only rewrites when the line is present).
2026-10-27 14:37:41 +01:00
Pathfinder dbf75d1239 qemu/libvirt belongs to the advanced menu, not the niri module
A clean-snapshot run showed qemu/virt-manager installed without choosing
it: PR #4 had embedded the install in the niri module. Removed from there
(zero virt packages in a plain niri run, harness-verified) and moved into
install_category_pkgs Virtualisation: picking qemu/virt-manager there now
also enables libvirtd and adds the user to the libvirt group.
2026-10-27 14:19:26 +01:00
Pathfinder eacceee296 polkit agent: polkit-gnome is orphaned/EPEL-only on F44; use polkit-kde
VM run failed: 'No match for argument: polkit-gnome'. polkit-gnome is
orphaned in Fedora (EPEL9 only). polkit-kde 6.6.4 is in F44 and ships its
agent's /etc/xdg/autostart .desktop itself, so the manual symlink wiring
is gone too — installing the package is the whole fix.
2026-10-27 14:07:49 +01:00
Pathfinder 8ca045de4a Polkit agent for compositor sessions; libvirt group for virt-manager
virt-manager on niri/Noctalia failed with 'authentication unavailable:
no polkit agent available to authenticate action org.libvirt.unix.manage'
- bare compositors ship no polkit agent, unlike GNOME/KDE.

Two fixes:
- install_session_prereqs installs polkit-gnome and wires its agent
  .desktop into /etc/xdg/autostart (paths overridable for testing).
- niri module optionally installs the qemu/libvirt stack, enables
  libvirtd, and adds the user to the libvirt group: members manage
  qemu:///system with no polkit prompt at all (the real fix; applies
  after re-login).
2026-10-27 14:01:31 +01:00
yuri fceeb57254 Merge pull request 'Package sections: always-on + advanced menu' (#3) from feat/package-sections into main 2026-10-27 13:57:39 +01:00
Pathfinder af4504fdbe Advanced menu: fix single-argument dnf call; failures warn instead of aborting
Root cause of the VM failures (both qemu-kvm AND VirtualBox showed 'No
match for argument: <entire list>'): picks were resolved into ONE quoted
string and passed to dnf as a single argument, so dnf searched for a
package literally named 'qemu-kvm libvirt virt-install ...'. Picks are
now word-split into separate package arguments.

Also, a failing install no longer kills the script (set -e abort): the
menu prints a red 'Installation failed' warning, notes the system is
unchanged, and drops back to the menu so another choice can be made.
Proven in harness: VBox failure (no match) followed by successful qemu
install in the same session, exit 0.
2026-10-27 13:39:28 +01:00
Pathfinder 5b7ed5ede9 Package sections: always-on categories + advanced menu installer
Section 6 'Always-installed packages': ALWAYS_PACKAGES array, one line per
category (first: Terminals with ghostty + ghostty-bash-completion). Every
entry installs on every run, no questions. Add a category by adding a line.

Section 7 'Advanced optional tools': menu-driven picker, data-driven —
ADV_CATEGORIES + ADV_<Category> arrays ('id:Label:pkgs...'). Ships
Virtualisation (qemu/kvm stack, VirtualBox) and Browsers (firefox,
chromium, google-chrome, brave; the latter two wire up their repos
automatically). Multi-select with comma-separated picks, invalid picks
warned and skipped, 'x' backs out, menu is skipped under --yes so
unattended runs never hang.

Bugs found by harness testing and fixed before shipping:
- ${!var} on an array name yields only element[0]: Browsers listed one
  entry. Now uses a nameref (declare -n).
- var assignment was lost in an edit: unbound-variable crash on the menu.
- --snapper=no was overwritten by the interactive default; explicit flags
  now always win.
2026-10-27 13:04:15 +01:00
yuri 525537c929 Merge pull request 'Dotfiles integration: modules/user/dotfiles.sh' (#2) from feat/dotfiles-integration into main 2026-10-27 12:49:54 +01:00
Pathfinder 3776dcb5a4 Snapper: no question on btrfs; vendor the SysGuides scripts
- On btrfs, snapshots + zstd compression now just happen (no prompt);
  --snapper=no remains the explicit opt-out.
- Vendor scripts/snapper-*.sh + config/snapper.actions from
  SysGuides/sysguides-snapper-fedora (MIT, upstream 0a28eb4) into
  vendor/snapper/ and install from there — no runtime clone of an
  external repo, and no dependency on exec bits (fixes the
  './install.sh: Permission denied' failure seen on the test VM).
- grub-btrfs still cloned at runtime from Antynea/grub-btrfs with the
  Fedora config applied; everything else is local now.
2026-10-27 12:37:18 +01:00
Pathfinder 47991727ff Add dotfiles integration module (fedora-dots)
New modules/user/dotfiles.sh behind a menu question ('Clone personal
dotfiles?', default no) and --dotfiles=yes|no flag.

Does a --bare clone of yuri/fedora-dots into ~/.cfg.git, checks the repo
out into $HOME with status.showUntrackedFiles=no, and handles an empty
repo gracefully (configures the alias, skips checkout). Existing
~/.cfg.git is left untouched (idempotent).

Fix proven in the harness: the module originally used a plain git clone,
which creates a working copy and breaks the git-dir alias — the same
failure YuKu hit manually; --bare is required.
Dispatch runs the dotfiles module before DE/TWM so configs are in place
when sessions are installed.
2026-10-27 12:25:13 +01:00
Pathfinder 80d9dccb61 niri module: noctalia now in Fedora repos, drop Terra dependency
noctalia 5.3.0 is in the Fedora 44 updates repo (confirmed on
packages.fedoraproject.org and by a fresh-install dnf install noctalia).
The niri module no longer calls add_terra_repo; Terra stays in the base
section and in the mango module, which is the only consumer left
(mangowc). README + comments updated.
2026-10-27 11:43:48 +01:00
Pathfinder aadead9f38 System settings: optional SELinux disable; btrfs snapper + zstd compression
New section between base and DE menus:
- 'Disable SELinux permanently?' — default no; writes SELINUX=disabled with a
  backup, warns about the security tradeoff.
- When / is btrfs: 'snapper + grub-btrfs + compression?' — default yes. Shows
  subvolume list + fstab, appends ,compress=zstd:1 to btrfs fstab entries that
  lack a compress= option (idempotent, fstab backed up), then runs the
  SysGuides sysguides-snapper-fedora installer (snapper root+home, grub-btrfs,
  DNF5 pre/post snapshot actions).
- Flags for unattended runs: --selinux=keep|disabled, --snapper=yes|no.
- Fix found by the harness: the flag initializers sat after the arg loop and
  wiped parsed values; --snapper=no was silently ignored. Initializers moved
  before the loop.
README + section renumbering updated.
2026-10-27 11:37:51 +01:00
Pathfinder 632a0267dd Hyprland: COPR fallback chain (solopasha has no F44 chroot)
On F44, 'dnf copr enable solopasha/hyprland' fails with 'Chroot not found':
verified via the Copr API, solopasha is rawhide-only right now. lionheartp/
Hyprland (solopasha fork, also ships noctalia packages) and hermitfeather/
hyprland both have fedora-44 chroots.

The module now tries lionheartp, hermitfeather, then solopasha, and aborts
with an actionable message if none has a chroot for this release. README
updated to name the chain, not a single repo.
2026-10-27 11:19:51 +01:00
Pathfinder 0939b228b6 Terra in base section; fix Hyprland via solopasha COPR
- Terra repo is added right after RPM Fusion in the base setup (it carries
  noctalia + mangowc). Modules keep calling add_terra_repo so they still
  work standalone; it is a no-op when terra-release is present.
- Hyprland was retired from the Fedora repos after F42 (dependency churn);
  the module could never resolve 'hyprland' on F44. It now enables the
  solopasha/hyprland COPR first — the de facto standard for F43/44 — and
  treats the accessory packages (hyprpaper/hyprlock/waybar/mako/wofi/
  xwayland-satellite) as optional so a name drift warns instead of aborting.
- README updated.
2026-10-27 11:14:21 +01:00
Pathfinder 1cd8d26d01 XFCE on SDDM; menu defaults to none for DE and TWM
- XFCE module installs/enables sddm instead of lightdm; one greeter across
  every session choice, no lightdm left anywhere.
- Interactive menus now default to 'none' for both DE and TWM (press Enter
  for no DE / no TWM). none+none is still refused by the existing guard.
- README and session.sh comments updated to match.
2026-10-27 11:06:50 +01:00
Pathfinder c443e4edf3 Restore restructured setup.sh (main was broken by 'corrections' merge)
The corrections commit replaced the lib/+modules/ entrypoint with the
older single-file version, reintroducing the DEBUG_MODE unbound-variable
crash, the unguarded clear, and TWM dispatch pointing at nonexistent
root-level scripts. lib/ and modules/ were orphaned.

Restores the tested restructured setup.sh + the SC2034 fix in lib/common.sh.
2026-10-27 10:30:17 +01:00
yuri 047eeebcc2 Merge branch 'feat/lib-modules' 2026-10-27 10:27:05 +01:00
Pathfinder 234bf8214e Restructure for bare Fedora: lib/ + modules/, DE selection restored
Splits setup.sh into lib/common.sh, lib/session.sh and seven modules
(3 DE, 4 TWM). Targets a bare Fedora 44+ install.

Fixes carried over from the first build:
- DEBUG_MODE was unbound under set -u, aborting the script at the version banner
- mangled 'echohttps://...' line left over from the starburst split
- set -e was missing entirely; --debug flag parsing restored
- unguarded 'clear' aborted the run without TERM
- $PRETTY_NAME unguarded under set -u
- modules were sourced, leaking shell options into the parent
- Flathub added twice (system-wide + per-user)
- no dnf5-plugins check before using 'dnf config-manager'
- no Fedora release gate
- /usr/share/xsessions assumed to exist when writing session entries
2026-10-27 10:15:04 +01:00
yuri b9c86feba5 corrections 2026-10-27 10:13:22 +01:00
yuri 4f59afbac1 first build 2026-10-27 10:02:13 +01:00
yuri 4a92f4af0c title change 2026-10-27 09:20:53 +01:00
yuri 6e887b8cdf first commit 2026-10-27 09:20:14 +01:00
yuri 82f97a0ed6 Initial commit 2026-10-27 09:16:49 +01:00