From 0281b06154c6f242841dc67b3639e229da1ec6aa Mon Sep 17 00:00:00 2001 From: Jeremy McClure Date: Wed, 29 Jul 2026 11:55:14 -0400 Subject: [PATCH] zsh: make bootstrap verbose + timeout PM availability checks (fix hang on AlmaLinux) The bootstrap silently suppressed all output, so the user saw the banner then an apparent hang. Root cause on AlmaLinux: the cold 'dnf list available' metadata check could stall for minutes on a slow/unreachable dnf mirror, and nothing was visible or bounded. - Wrap apt/dnf/pacman availability checks in 'timeout 20' so a slow mirror fails through to the next installer instead of hanging - Remove >/dev/null 2>&1 suppression so real installs (cargo compiles, dnf progress) are visible as progress, not an apparent hang - Emit a one-line status per step: ok already present ... checking package managers dnf not available (or metadata check timed out) curl installing from binary cargo (may take a few minutes to compile) git cloning FAIL could not install; skipping - Apply the same timeout+verbose pattern to the git-delta block - Add progress + FAIL lines to the fastfetch/eza/github clones --- zsh/zshrc-bootstrap.zsh | 86 ++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/zsh/zshrc-bootstrap.zsh b/zsh/zshrc-bootstrap.zsh index b10a86d..b7ae900 100644 --- a/zsh/zshrc-bootstrap.zsh +++ b/zsh/zshrc-bootstrap.zsh @@ -41,34 +41,56 @@ mkdir -p "$HOME/.local/bin" mkdir -p "$ZSH_CONFIG" path+=("$HOME/.local/bin") +# Package availability checks can hang on slow/unreachable mirrors (cold dnf +# metadata, apt update, pacman -Sy). Wrap them in a 20s timeout so the bootstrap +# never stalls the shell; a timed-out check just falls through to the next PM +# or to the binary installers below. Verbose output so real builds (cargo) and +# slow installs are visible as progress instead of an apparent hang. for p in git starship fzf eza rsync lazydocker fastfetch tmux bat zoxide; do - command -v $p >/dev/null && continue + if command -v $p >/dev/null; then + echo " ok $p (already installed)" + continue + fi + echo " ... $p (checking package managers)" if command -v brew >/dev/null; then - echo "Installing $p using brew" && brew install $p && continue + echo " brew installing $p" && brew install $p && continue fi - if command -v apt >/dev/null && apt-cache show $p >/dev/null 2>&1; then - echo "Installing $p using Apt" && sudo apt install $p -y && continue + if command -v apt >/dev/null; then + if timeout 20 apt-cache show $p >/dev/null 2>&1; then + echo " apt installing $p" && sudo apt install -y $p && continue + else + echo " apt $p not available (or metadata check timed out)" + fi fi - if command -v dnf >/dev/null && dnf list available $p >/dev/null 2>&1; then - echo "Installing $p using dnf" && sudo dnf install $p -y && continue + if command -v dnf >/dev/null; then + if timeout 20 dnf list available $p >/dev/null 2>&1; then + echo " dnf installing $p" && sudo dnf install -y $p && continue + else + echo " dnf $p not available (or metadata check timed out)" + fi fi - if command -v pacman >/dev/null && pacman -Si $p >/dev/null 2>&1; then - echo "Installing $p using pacman" && sudo pacman -Sy --noconfirm $p && continue + if command -v pacman >/dev/null; then + if timeout 20 pacman -Si $p >/dev/null 2>&1; then + echo " pacman installing $p" && sudo pacman -Sy --noconfirm $p && continue + else + echo " pacman $p not available (or metadata check timed out)" + fi fi if command -v cargo >/dev/null; then - echo "Installing $p using cargo" && cargo install $p --locked && continue + echo " cargo installing $p (may take a few minutes to compile)" && cargo install $p --locked && continue fi + echo " FAIL could not install $p by any method; skipping" done if ! command -v starship >/dev/null; then - echo "Installing starship binary..." && \ - curl -fsSL --connect-timeout 5 --max-time 30 https://starship.rs/install.sh | sh -s -- -b ~/.local/bin -y >/dev/null 2>&1 + echo " curl installing starship binary" + curl -fsSL --connect-timeout 5 --max-time 30 https://starship.rs/install.sh | sh -s -- -b ~/.local/bin -y fi if ! command -v lazydocker >/dev/null; then - echo "Installing lazydocker binary..." && \ + echo " curl installing lazydocker binary" curl -fsSL --connect-timeout 5 --max-time 30 https://raw.githubusercontent.com/jesseduffield/lazydocker/master/scripts/install_update_linux.sh | \ - DIR=$HOME/.local/bin bash >/dev/null 2>&1 + DIR=$HOME/.local/bin bash fi # Debian/Ubuntu ships bat as 'batcat' and fd as 'fdfind'; symlink to the @@ -84,16 +106,19 @@ fi # binary is 'delta' (name mismatch vs the install loop above), so install via the # same PM cascade using the real package name. Used by zshrc as GIT_PAGER. if ! command -v delta >/dev/null; then + echo " ... delta (checking package managers, package name is 'git-delta')" if command -v brew >/dev/null; then - echo "Installing git-delta using brew" && brew install git-delta - elif command -v apt >/dev/null && apt-cache show git-delta >/dev/null 2>&1; then - echo "Installing git-delta using Apt" && sudo apt install git-delta -y - elif command -v dnf >/dev/null && dnf list available git-delta >/dev/null 2>&1; then - echo "Installing git-delta using dnf" && sudo dnf install git-delta -y - elif command -v pacman >/dev/null && pacman -Si git-delta >/dev/null 2>&1; then - echo "Installing git-delta using pacman" && sudo pacman -Sy --noconfirm git-delta + echo " brew installing git-delta" && brew install git-delta + elif command -v apt >/dev/null && timeout 20 apt-cache show git-delta >/dev/null 2>&1; then + echo " apt installing git-delta" && sudo apt install -y git-delta + elif command -v dnf >/dev/null && timeout 20 dnf list available git-delta >/dev/null 2>&1; then + echo " dnf installing git-delta" && sudo dnf install -y git-delta + elif command -v pacman >/dev/null && timeout 20 pacman -Si git-delta >/dev/null 2>&1; then + echo " pacman installing git-delta" && sudo pacman -Sy --noconfirm git-delta elif command -v cargo >/dev/null; then - echo "Installing git-delta using cargo" && cargo install git-delta --locked + echo " cargo installing git-delta (may take a few minutes to compile)" && cargo install git-delta --locked + else + echo " FAIL could not install delta; skipping" fi fi @@ -106,6 +131,7 @@ esac if [[ -n $target_fast && -n $target_eza ]]; then if ! command -v fastfetch >/dev/null; then + echo " curl installing fastfetch (github release tarball)" if curl -fsSL --connect-timeout 5 --max-time 30 -o /tmp/fastfetch.tar.gz \ "https://github.com/fastfetch-cli/fastfetch/releases/latest/download/fastfetch-${target_fast}.tar.gz" \ && tar -xzf /tmp/fastfetch.tar.gz -C /tmp 2>/dev/null; then @@ -119,16 +145,19 @@ if [[ -n $target_fast && -n $target_eza ]]; then rm -rf "$ffdir" /tmp/fastfetch.tar.gz else rm -f /tmp/fastfetch.tar.gz + echo " FAIL could not download/extract fastfetch; skipping" fi fi if ! command -v eza >/dev/null; then + echo " curl installing eza (github release tarball)" if curl -fsSL --connect-timeout 5 --max-time 30 -o /tmp/eza.tar.gz \ "https://github.com/eza-community/eza/releases/latest/download/eza_${target_eza}.tar.gz" \ && tar -xzf /tmp/eza.tar.gz -C "$HOME/.local/bin/" 2>/dev/null; then chmod +x "$HOME/.local/bin/eza" else - echo "Warning: failed to download eza" >&2 + rm -f /tmp/eza.tar.gz + echo " FAIL could not download/extract eza; skipping" fi rm -f /tmp/eza.tar.gz fi @@ -136,9 +165,12 @@ fi mkdir -p "$HOME/.config/zsh" -[ ! -d $OHMYZSH ] && \ +if [ ! -d "$OHMYZSH" ]; then + echo " git cloning oh-my-zsh" GIT_TERMINAL_PROMPT=0 git -c http.lowSpeedLimit=1000 -c http.lowSpeedTime=10 \ - clone --depth=1 https://github.com/ohmyzsh/ohmyzsh.git $OHMYZSH + clone --depth=1 https://github.com/ohmyzsh/ohmyzsh.git $OHMYZSH || \ + echo " FAIL could not clone oh-my-zsh" +fi for plug in \ "zsh-autosuggestions|https://github.com/zsh-users/zsh-autosuggestions" \ @@ -148,9 +180,11 @@ do name="${plug%%|*}" url="${plug##*|}" dir="$OHMYZSH_CUSTOM/plugins/$name" - [[ ! -d "$dir" ]] && \ + if [[ ! -d "$dir" ]]; then + echo " git cloning $name" GIT_TERMINAL_PROMPT=0 git -c http.lowSpeedLimit=1000 -c http.lowSpeedTime=10 \ - clone "$url" "$dir" 2>/dev/null + clone "$url" "$dir" 2>/dev/null || echo " FAIL could not clone $name" + fi done # Cleanup