From 55b66a137392d8a2084c0ea819d44a36765e93eb Mon Sep 17 00:00:00 2001 From: alvinlollo Date: Sun, 11 Oct 2026 17:38:11 +1100 Subject: [PATCH] fix(installer): Survive copytoram, keep ISO repos, default to fish - install_pacstrap: fall back to the live system's pacman -Q when the medium's pkglist is gone (copytoram unmounts bootmnt), and die on an empty list instead of pacstrapping only the essentials. - screen_disk: find the live medium via archisosearchuuid when bootmnt is unmounted, and hide whole-disk sources (empty PKNAME). - install_cachyos_repo: put [cachyos] ahead of [core] like the ISO build and add [chaotic-aur], so chaotic packages keep updating. - install_user: create the user with fish; the 'none' login manager now autostarts Hyprland via ~/.config/fish/conf.d/alvin-hyprland.fish. Co-Authored-By: Claude Opus 5.5 --- airootfs/usr/local/bin/alvin-install | 134 +++++++++++++++++++-------- 1 file changed, 93 insertions(+), 41 deletions(-) diff --git a/airootfs/usr/local/bin/alvin-install b/airootfs/usr/local/bin/alvin-install index 4185844..d796ddf 100755 --- a/airootfs/usr/local/bin/alvin-install +++ b/airootfs/usr/local/bin/alvin-install @@ -320,11 +320,20 @@ screen_disk() { header "Select Installation Disk" echo "" - local live_dev="" + # The boot medium: the bootmnt source, or - when copytoram unmounted it - + # the device carrying the archisosearchuuid= volume. A whole-disk source + # (hybrid ISO, sr0) has no PKNAME and is itself the disk to hide. + local live_dev="" src="" pk="" search_uuid="" if [[ -d /run/archiso/bootmnt ]]; then - local src src=$(findmnt -no SOURCE /run/archiso/bootmnt 2>/dev/null || true) - [[ -n "$src" ]] && live_dev="/dev/$(lsblk -no PKNAME "$src" 2>/dev/null | head -n1)" + fi + if [[ -z "$src" ]]; then + search_uuid=$(sed -n 's/.*archisosearchuuid=\([^[:space:]]*\).*/\1/p' /proc/cmdline) + [[ -n "$search_uuid" ]] && src=$(blkid -U "$search_uuid" 2>/dev/null || true) + fi + if [[ -n "$src" ]]; then + pk=$(lsblk -no PKNAME "$src" 2>/dev/null | head -n1 || true) + live_dev="/dev/${pk:-$(basename "$src")}" fi local disks=() @@ -650,36 +659,47 @@ install_pacstrap() { local pkgs=() local dropped=() local filter_ok=false + local -a src_lines=() + # The medium's pkglist comes from `pacman -Q` at build time: lines are + # "name version". With copytoram the boot medium is unmounted and the + # file is gone - the live system's own `pacman -Q` is the same data. if [[ -f "$pkglist" ]]; then - # The medium's pkglist comes from `pacman -Q`: lines are "name version". - # Parse only the first field, then drop names not resolvable in the live - # session's repos (e.g. local-aur packages are not configured there). - info "Syncing package databases for resolvability check..." - if run_logged -s dot "pacman -Syy failed (resolvability check)" \ - pacman -Syy --noconfirm; then - declare -A available=() - local db_line - while IFS= read -r db_line; do - [[ -n "$db_line" ]] && available["$db_line"]=1 - done < <(pacman -Slq 2>>"$LOG" || true) - (( ${#available[@]} > 0 )) && filter_ok=true - else - warn "pacman -Syy failed (output above) — installing without resolvability filter." - fi - - local line pkg - while IFS= read -r line; do - [[ -z "$line" ]] && continue - pkg=${line%% *} - skip "$pkg" && continue - if $filter_ok && [[ -z "${available[$pkg]:-}" ]]; then - dropped+=("$pkg") - continue - fi - pkgs+=("$pkg") - done < "$pkglist" + mapfile -t src_lines < "$pkglist" + else + warn "${pkglist} not found (copytoram?) - using the live system's package list." + log "Pacstrap: ${pkglist} missing, falling back to pacman -Q" + mapfile -t src_lines < <(pacman -Q 2>>"$LOG" || true) fi + (( ${#src_lines[@]} > 0 )) \ + || die "No package list: ${pkglist} is missing and pacman -Q returned nothing." + + # Parse only the first field, then drop names not resolvable in the + # live session's repos (incl. [local-aur] = /opt/localrepo). + info "Syncing package databases for resolvability check..." + if run_logged -s dot "pacman -Syy failed (resolvability check)" \ + pacman -Syy --noconfirm; then + declare -A available=() + local db_line + while IFS= read -r db_line; do + [[ -n "$db_line" ]] && available["$db_line"]=1 + done < <(pacman -Slq 2>>"$LOG" || true) + (( ${#available[@]} > 0 )) && filter_ok=true + else + warn "pacman -Syy failed (output above) — installing without resolvability filter." + fi + + local line pkg + while IFS= read -r line; do + [[ -z "$line" ]] && continue + pkg=${line%% *} + skip "$pkg" && continue + if $filter_ok && [[ -z "${available[$pkg]:-}" ]]; then + dropped+=("$pkg") + continue + fi + pkgs+=("$pkg") + done < <(printf '%s\n' "${src_lines[@]}") if (( ${#dropped[@]} > 0 )); then warn "Skipped ${#dropped[@]} pkglist package(s) not found in configured repos:" @@ -729,14 +749,24 @@ install_fstab() { } install_cachyos_repo() { - info "Configuring CachyOS repository..." + info "Configuring CachyOS and chaotic-aur repositories..." + local conf="${TARGET}/etc/pacman.conf" - if ! grep -q '\[cachyos\]' "${TARGET}/etc/pacman.conf" 2>/dev/null; then - cat >> "${TARGET}/etc/pacman.conf" <<'REPO' - -[cachyos] -Include = /etc/pacman.d/cachyos-mirrorlist -REPO + # Same order as the ISO build (pacman.conf): cachyos ahead of [core], so + # packages in both keep resolving to the cachyos builds pacstrap + # installed instead of flipping to extra on the first -Syu. + if ! grep -q '^\[cachyos\]' "$conf" 2>/dev/null; then + if grep -q '^\[core\]' "$conf"; then + sed -i '0,/^\[core\]/s//[cachyos]\nInclude = \/etc\/pacman.d\/cachyos-mirrorlist\n\n[core]/' "$conf" + else + printf '\n[cachyos]\nInclude = /etc/pacman.d/cachyos-mirrorlist\n' >> "$conf" + fi + fi + # chaotic-aur packages (yay, ...) came from the ISO - without the repo + # they turn foreign and never update. + if ! grep -q '^\[chaotic-aur\]' "$conf" 2>/dev/null \ + && [[ -f "${TARGET}/etc/pacman.d/chaotic-mirrorlist" ]]; then + printf '\n[chaotic-aur]\nInclude = /etc/pacman.d/chaotic-mirrorlist\n' >> "$conf" fi # [local-aur] lives only on the live medium (file:///opt/localrepo). The @@ -745,7 +775,7 @@ REPO # but drop it anyway in case that ever changes. sed -i '/^\[local-aur\]$/,/^$/d' "${TARGET}/etc/pacman.conf" 2>/dev/null || true - ok "CachyOS repo configured." + ok "CachyOS + chaotic-aur repos configured." } install_timezone() { @@ -819,7 +849,12 @@ install_user() { cp -rT /etc/skel "${TARGET}/etc/skel" - arch-chroot "$TARGET" useradd -m -G wheel -s /bin/bash "$USERNAME" + # fish is the default shell (skel ships its config); bash only if the + # target somehow lacks it, so the account is never left without a shell. + local user_shell="/usr/bin/fish" + [[ -x "${TARGET}${user_shell}" ]] || user_shell="/bin/bash" + arch-chroot "$TARGET" useradd -m -G wheel -s "$user_shell" "$USERNAME" + log "User shell: ${user_shell}" printf '%s:%s\n' "$USERNAME" "$PASS" | arch-chroot "$TARGET" chpasswd @@ -1770,8 +1805,25 @@ install_none_profile() { profile="${home_in_target}/.zprofile" ;; *fish) - warn "fish is the login shell - skipping tty autostart; run 'Hyprland' after login." - log "tty profile: skipped (fish shell)" + # conf.d is sourced automatically on every start. This runs after + # install_end4_dots, so end-4's rsync --delete of ~/.config/fish + # cannot remove it. + local fish_cfg="${TARGET}${home_in_target}/.config/fish" + if grep -rqsE 'start-hyprland|exec Hyprland|auto-Hypr' \ + "${fish_cfg}/config.fish" "${fish_cfg}/conf.d"; then + log "tty profile: fish config already launches Hyprland - skipped" + return 0 + fi + mkdir -p "${fish_cfg}/conf.d" + cat > "${fish_cfg}/conf.d/alvin-hyprland.fish" <<'FISH' +# alvin-install: start Hyprland on tty1 (pam_systemd sets XDG_VTNR). +if status is-login; and test -z "$WAYLAND_DISPLAY"; and test "$XDG_VTNR" = 1 + exec Hyprland +end +FISH + chown -R "$owner" "${fish_cfg}/conf.d" 2>/dev/null || true + ok "tty login will start Hyprland via ~/.config/fish/conf.d/alvin-hyprland.fish." + log "tty profile: fish conf.d/alvin-hyprland.fish (exec Hyprland on VT1)" return 0 ;; *)