From a24a27fff61df87e0bb6fa83e2af7c3918eb1275 Mon Sep 17 00:00:00 2001 From: The_miro Date: Mon, 13 Jul 2026 14:27:12 +0200 Subject: [PATCH] fix(archiso): source dotfiles from a single live-env clone, not skel-only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dotfiles clone used to land directly in /mnt/etc/skel, gated solely by clone_skel_dotfiles. That meant run_tui=YES + clone_skel_dotfiles=NO cloned nothing anywhere, so tui-install.sh (which only exists inside the repo, not in the embedded live-ISO scripts) had nothing to run and the TUI step always failed. Clone the repo once into the live environment ($HOME/Dotfiles) whenever either toggle is YES, then serve both the skel copy and — as a fallback right before the TUI runs — a direct copy into the new user's home from that single clone, no extra network fetch needed. arch-autoinstall.sh's skel clone also moved out of the chroot heredoc so it can share the same live clone. When clone_skel_dotfiles=NO, the fallback copy in the new user's home is transient: after tui-install.sh finishes, materialize every symlink that shell-setup.sh/hyprlua/hyprland/niri point into ~/Dotfiles (shell rc's, nvim/starship/alot/yazi/spotify-tui configs, config-updater scripts) into real copies, then remove the checkout — so declining skel persistence doesn't leave a system full of dangling symlinks. --- setup/arch-autoinstall.sh | 111 +++++++++++++++++++++++++---- setup/archbaseos-guided-install.sh | 89 +++++++++++++++++++---- 2 files changed, 175 insertions(+), 25 deletions(-) diff --git a/setup/arch-autoinstall.sh b/setup/arch-autoinstall.sh index 900eb6f..86ce8f1 100755 --- a/setup/arch-autoinstall.sh +++ b/setup/arch-autoinstall.sh @@ -532,6 +532,58 @@ fi # outside the chroot, so env vars must be in the environment, not inline. export HOSTNAME USERNAME USERPASS ROOT_PART KERNEL FIDO_ROOT FIDO_USER ENCRYPT_DISK KEYMAP RUN_TUI CLONE_SKEL_DOTFILES +############################################ +# DOTFILES CLONE (live environment, with retry) +############################################ +# The live ISO only embeds the top-level installer scripts (see build.sh) — +# tui-install.sh, its modules/, and desktopenvs/ configs exist only inside the +# full repo. Clone it ONCE into the live environment whenever either RUN_TUI +# or CLONE_SKEL_DOTFILES is YES, so both consumers below (the skel copy, and +# the fallback copy straight into the new user's home when skel is skipped +# but the TUI still needs to run) are served from one clone instead of each +# needing its own network fetch — and so a bare install genuinely fetches +# nothing at all. Done here (outside the chroot) because a clone made inside +# the chroot heredoc lives only under /mnt and can't be reused for the skel +# copy that must happen before useradd -m runs inside that same heredoc. +LIVE_DOTFILES_DIR="$HOME/Dotfiles" +if [[ "${CLONE_SKEL_DOTFILES^^}" == "YES" || "${RUN_TUI^^}" == "YES" ]]; then + echo "Cloning dotfiles into the live environment ($LIVE_DOTFILES_DIR)..." + _clone_ok=false + while ! $_clone_ok; do + if [[ -d "$LIVE_DOTFILES_DIR/.git" ]]; then + _clone_ok=true + elif git clone https://git.abdelbaki.eu/The_miro/Dotfiles.git "$LIVE_DOTFILES_DIR"; then + _clone_ok=true + else + if $AF_MODE; then + echo "Warning: dotfiles clone failed — continuing without dotfiles." + RUN_TUI="NO"; CLONE_SKEL_DOTFILES="NO" + _clone_ok=true + else + read -rp "Clone failed — retry? [y/N]: " _retry + [[ "${_retry,,}" == "y" ]] || { echo "Skipping dotfiles — clone manually after first boot."; RUN_TUI="NO"; CLONE_SKEL_DOTFILES="NO"; _clone_ok=true; } + fi + fi + done +fi + +############################################ +# DOTFILES CLONE TO SKEL (local copy from the live clone, gated by its own toggle) +############################################ +# Independent of RUN_TUI: declining this means the new user gets a bare +# /etc/skel (system defaults) rather than a clone of the dotfiles repo sitting +# in their home directory. Copy (not clone) before entering the chroot so +# useradd -m inside will copy Dotfiles to the new user's home — no network +# needed here since the live clone above already has it. +if [[ "${CLONE_SKEL_DOTFILES^^}" == "YES" ]]; then + echo "Copying dotfiles into /mnt/etc/skel..." + mkdir -p /mnt/etc/skel + cp -r "$LIVE_DOTFILES_DIR" /mnt/etc/skel/Dotfiles + mkdir -p /mnt/etc/skel/{Desktop,Documents,Downloads,Music,Pictures,Public,Templates,Videos} +else + echo "Skipping dotfiles clone to skel — clone_skel_dotfiles=NO." +fi + ############################################ # CHROOT CONFIGURATION ############################################ @@ -566,18 +618,9 @@ systemctl enable sshd sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config echo "root:${USERPASS}" | chpasswd -# Populate /etc/skel before user creation so useradd -m copies everything. -# Gated by its own toggle, independent of RUN_TUI: declining it means the new -# user gets a bare /etc/skel (system defaults) instead of a clone of the -# dotfiles repo sitting in their home directory. -if [[ "${CLONE_SKEL_DOTFILES^^}" == "YES" ]]; then - echo "Cloning dotfiles into /etc/skel..." - git clone https://git.abdelbaki.eu/The_miro/Dotfiles.git /etc/skel/Dotfiles \ - || echo "Warning: dotfiles clone failed — clone manually after first boot." - mkdir -p /etc/skel/{Desktop,Documents,Downloads,Music,Pictures,Public,Templates,Videos} -else - echo "Skipping dotfiles clone — clone_skel_dotfiles=NO." -fi +# /etc/skel was already populated (or intentionally left bare) from the live +# environment's dotfiles clone before this chroot — see "DOTFILES CLONE TO +# SKEL" above. # User # -m: create home dir (from /etc/skel above); -G wheel: add to sudoers group. @@ -692,6 +735,24 @@ if [[ "$FIDO_USER" == "YES" ]]; then echo "FIDO2 key enrolled for $USERNAME." fi +############################################ +# ENSURE ~/Dotfiles EXISTS FOR THE TUI (fallback when skel didn't provide it) +############################################ +# tui-install.sh is invoked below at /home/$USERNAME/Dotfiles/setup/tui-install.sh. +# That path only exists already if CLONE_SKEL_DOTFILES put Dotfiles in /etc/skel +# (copied into the new home by useradd -m inside the chroot). When that toggle +# was NO but RUN_TUI is YES, copy the live clone straight into the new user's +# home now so the TUI has something to run — this is what makes the two +# toggles genuinely independent instead of RUN_TUI silently depending on +# CLONE_SKEL_DOTFILES. +if [[ "${RUN_TUI^^}" == "YES" && ! -d "/mnt/home/${USERNAME}/Dotfiles" ]]; then + echo "Copying dotfiles into /home/${USERNAME} for the TUI (not persisted to skel)..." + cp -r "$LIVE_DOTFILES_DIR" "/mnt/home/${USERNAME}/Dotfiles" + _NEWUID=$(arch-chroot /mnt id -u "$USERNAME" 2>/dev/null || echo "1000") + _NEWGID=$(arch-chroot /mnt id -g "$USERNAME" 2>/dev/null || echo "1000") + chown -R "${_NEWUID}:${_NEWGID}" "/mnt/home/${USERNAME}/Dotfiles" +fi + ############################################ # DOTFILES TUI SETUP (in-chroot, optional) ############################################ @@ -718,6 +779,26 @@ if [[ "${RUN_TUI^^}" == "YES" ]]; then bash "/home/${USERNAME}/Dotfiles/setup/tui-install.sh" \ || echo "Warning: tui-install exited with errors — check ~/dotfiles-install.log in the new system." + # If clone_skel_dotfiles was declined, ~/Dotfiles only exists because of the + # fallback copy earlier and should not be left on disk. But shell-setup.sh + # and the hyprlua/hyprland/niri DE modules symlink several files straight + # into it (.bashrc/.zshrc/.vimrc, starship/nvim/alot/yazi/spotify-tui + # configs, config-updater scripts) — deleting the checkout as-is would + # leave those as dangling links. Materialize each such symlink into a real + # copy of its target first, then remove the checkout. + if [[ "${CLONE_SKEL_DOTFILES^^}" != "YES" ]]; then + echo "Materializing dotfiles symlinks and removing the transient ~/Dotfiles checkout..." + arch-chroot /mnt runuser -u "${USERNAME}" -- bash -c ' + find "$HOME" -maxdepth 3 -type l 2>/dev/null | while IFS= read -r link; do + target=$(readlink -f "$link") || continue + case "$target" in + "$HOME"/Dotfiles/*) rm -f "$link"; cp -r "$target" "$link" ;; + esac + done + rm -rf "$HOME/Dotfiles" + ' + fi + # Remove the temporary no-password sudoers drop-in after setup is done. arch-chroot /mnt rm -f /etc/sudoers.d/99-setup-nopasswd fi @@ -775,4 +856,10 @@ if [[ "${RUN_TUI^^}" != "YES" ]]; then echo "Bare install — no dotfiles were cloned. To set up dotfiles/DE later, run:" echo " git clone https://git.abdelbaki.eu/The_miro/Dotfiles.git ~/Dotfiles && ~/Dotfiles/setup/tui-install.sh" fi +elif [[ "${CLONE_SKEL_DOTFILES^^}" != "YES" ]]; then + echo + echo "~/Dotfiles was used to run setup and then removed (clone_skel_dotfiles=NO)." + echo "Configured files were copied in place, so nothing is broken — but re-clone" + echo "the repo if you want to edit dotfiles or pull updates:" + echo " git clone https://git.abdelbaki.eu/The_miro/Dotfiles.git ~/Dotfiles" fi diff --git a/setup/archbaseos-guided-install.sh b/setup/archbaseos-guided-install.sh index caa0aeb..e9328b4 100755 --- a/setup/archbaseos-guided-install.sh +++ b/setup/archbaseos-guided-install.sh @@ -512,33 +512,53 @@ if $AF_MODE; then fi ############################################ -# DOTFILES CLONE TO SKEL (with retry, gated by its own toggle) +# DOTFILES CLONE (live environment, with retry) ############################################ -# Independent of RUN_TUI: declining this means the new user gets a bare -# /etc/skel (system defaults) rather than a clone of the dotfiles repo sitting -# in their home directory. -# Clone before entering the chroot so useradd -m inside will copy Dotfiles to -# the new user's home. Interactive retry is available so a transient network -# failure doesn't silently leave the system without dotfiles. -if [[ "${CLONE_SKEL_DOTFILES^^}" == "YES" ]]; then - echo "Cloning dotfiles into /mnt/etc/skel..." +# The live ISO only embeds the top-level installer scripts (see build.sh) — +# tui-install.sh, its modules/, and desktopenvs/ configs exist only inside the +# full repo. Clone it ONCE into the live environment whenever either RUN_TUI +# or CLONE_SKEL_DOTFILES is YES, so both consumers below (the skel copy, and +# the fallback copy straight into the new user's home when skel is skipped +# but the TUI still needs to run) are served from one clone instead of each +# needing its own network fetch — and so a bare install genuinely fetches +# nothing at all. +LIVE_DOTFILES_DIR="$HOME/Dotfiles" +if [[ "${CLONE_SKEL_DOTFILES^^}" == "YES" || "${RUN_TUI^^}" == "YES" ]]; then + echo "Cloning dotfiles into the live environment ($LIVE_DOTFILES_DIR)..." _clone_ok=false while ! $_clone_ok; do - if git clone https://git.abdelbaki.eu/The_miro/Dotfiles.git /mnt/etc/skel/Dotfiles; then - mkdir -p /mnt/etc/skel/{Desktop,Documents,Downloads,Music,Pictures,Public,Templates,Videos} + if [[ -d "$LIVE_DOTFILES_DIR/.git" ]]; then + _clone_ok=true + elif git clone https://git.abdelbaki.eu/The_miro/Dotfiles.git "$LIVE_DOTFILES_DIR"; then _clone_ok=true else if $AF_MODE; then echo "Warning: dotfiles clone failed — continuing without dotfiles." + RUN_TUI="NO"; CLONE_SKEL_DOTFILES="NO" _clone_ok=true else read -rp "Clone failed — retry? [y/N]: " _retry - [[ "${_retry,,}" == "y" ]] || { echo "Skipping dotfiles — clone manually after first boot."; _clone_ok=true; } + [[ "${_retry,,}" == "y" ]] || { echo "Skipping dotfiles — clone manually after first boot."; RUN_TUI="NO"; CLONE_SKEL_DOTFILES="NO"; _clone_ok=true; } fi fi done +fi + +############################################ +# DOTFILES CLONE TO SKEL (local copy from the live clone, gated by its own toggle) +############################################ +# Independent of RUN_TUI: declining this means the new user gets a bare +# /etc/skel (system defaults) rather than a clone of the dotfiles repo sitting +# in their home directory. Copy (not clone) before entering the chroot so +# useradd -m inside will copy Dotfiles to the new user's home — no network +# needed here since the live clone above already has it. +if [[ "${CLONE_SKEL_DOTFILES^^}" == "YES" ]]; then + echo "Copying dotfiles into /mnt/etc/skel..." + mkdir -p /mnt/etc/skel + cp -r "$LIVE_DOTFILES_DIR" /mnt/etc/skel/Dotfiles + mkdir -p /mnt/etc/skel/{Desktop,Documents,Downloads,Music,Pictures,Public,Templates,Videos} else - echo "Skipping dotfiles clone — clone_skel_dotfiles=NO." + echo "Skipping dotfiles clone to skel — clone_skel_dotfiles=NO." fi ############################################ @@ -691,6 +711,23 @@ if [[ "$ENABLE_FIDO_USER" == "YES" ]]; then echo "FIDO2 key enrolled for $USERNAME." fi +############################################ +# ENSURE ~/Dotfiles EXISTS FOR THE TUI (fallback when skel didn't provide it) +############################################ +# tui-install.sh is invoked below at /home/$USERNAME/Dotfiles/setup/tui-install.sh. +# That path only exists already if CLONE_SKEL_DOTFILES put Dotfiles in /etc/skel +# (copied into the new home by useradd -m earlier). When that toggle was NO but +# RUN_TUI is YES, copy the live clone straight into the new user's home now so +# the TUI has something to run — this is what makes the two toggles genuinely +# independent instead of RUN_TUI silently depending on CLONE_SKEL_DOTFILES. +if [[ "${RUN_TUI^^}" == "YES" && ! -d "/mnt/home/${USERNAME}/Dotfiles" ]]; then + echo "Copying dotfiles into /home/${USERNAME} for the TUI (not persisted to skel)..." + cp -r "$LIVE_DOTFILES_DIR" "/mnt/home/${USERNAME}/Dotfiles" + _NEWUID=$(arch-chroot /mnt id -u "$USERNAME" 2>/dev/null || echo "1000") + _NEWGID=$(arch-chroot /mnt id -g "$USERNAME" 2>/dev/null || echo "1000") + chown -R "${_NEWUID}:${_NEWGID}" "/mnt/home/${USERNAME}/Dotfiles" +fi + ############################################ # DOTFILES SETUP (in-chroot, optional) ############################################ @@ -715,6 +752,26 @@ if [[ "${_DO_TUI^^}" == "YES" ]]; then bash "/home/${USERNAME}/Dotfiles/setup/tui-install.sh" \ || echo "Warning: tui-install exited with errors — check ~/dotfiles-install.log in the new system." + # If clone_skel_dotfiles was declined, ~/Dotfiles only exists because of the + # fallback copy above and should not be left on disk. But shell-setup.sh and + # the hyprlua/hyprland/niri DE modules symlink several files straight into + # it (.bashrc/.zshrc/.vimrc, starship/nvim/alot/yazi/spotify-tui configs, + # config-updater scripts) — deleting the checkout as-is would leave those + # as dangling links. Materialize each such symlink into a real copy of its + # target first, then remove the checkout. + if [[ "${CLONE_SKEL_DOTFILES^^}" != "YES" ]]; then + echo "Materializing dotfiles symlinks and removing the transient ~/Dotfiles checkout..." + arch-chroot /mnt runuser -u "${USERNAME}" -- bash -c ' + find "$HOME" -maxdepth 3 -type l 2>/dev/null | while IFS= read -r link; do + target=$(readlink -f "$link") || continue + case "$target" in + "$HOME"/Dotfiles/*) rm -f "$link"; cp -r "$target" "$link" ;; + esac + done + rm -rf "$HOME/Dotfiles" + ' + fi + # Remove the temporary no-password sudoers drop-in after setup completes. arch-chroot /mnt rm -f /etc/sudoers.d/99-setup-nopasswd fi @@ -739,6 +796,12 @@ if [[ "${_DO_TUI^^}" != "YES" ]]; then echo "Bare install — no dotfiles were cloned. To set up dotfiles/DE later, run:" echo " git clone https://git.abdelbaki.eu/The_miro/Dotfiles.git ~/Dotfiles && ~/Dotfiles/setup/tui-install.sh" fi +elif [[ "${CLONE_SKEL_DOTFILES^^}" != "YES" ]]; then + echo + echo "~/Dotfiles was used to run setup and then removed (clone_skel_dotfiles=NO)." + echo "Configured files were copied in place, so nothing is broken — but re-clone" + echo "the repo if you want to edit dotfiles or pull updates:" + echo " git clone https://git.abdelbaki.eu/The_miro/Dotfiles.git ~/Dotfiles" fi if [[ "$ENCRYPT_DISK" == "YES" ]]; then echo