#!/usr/bin/env bash # 30-shell-zsh — zsh + oh-my-zsh + plugins, set as default shell, drop our config. step_name="shell-zsh" step_desc="zsh + oh-my-zsh + plugins, set default shell, ship config" step_run="run_zsh" # All paths resolve against the config TARGET (set by 05-create-user). # NOTE: we deliberately do NOT honor an inherited $ZSH env var — oh-my-zsh exports # ZSH when it loads, so a setup.sh run from an omz-equipped shell would otherwise # pin these to the *old* home (e.g. /root) while the chown step retargets to the # *new* user, mis-owning the wrong tree (the 'insecure completion dirs' bug). ZSH="$TARGET_HOME/.oh-my-zsh" ZSH_CUSTOM="$ZSH/custom" ZDOTDIR_TARGET="$TARGET_HOME/.config/zsh" run_zsh() { log "installing zsh + oh-my-zsh" _install_zsh _install_omz _install_plugins _chown_target_tree _ship_config _set_default_shell if [[ "$TARGET_USER" != "$USER" ]]; then log "zsh ready. Start it as $TARGET_USER: sudo -iu $TARGET_USER" else ok "zsh ready — start it with: exec zsh" fi } _chown_target_tree() { # when running as root for a created user, make omz + plugins + config owned by them if [[ "$TARGET_USER" == "$USER" ]]; then return; fi local grp; grp="$(id -gn "$TARGET_USER" 2>/dev/null || echo "$TARGET_USER")" chown -R "$TARGET_USER:$grp" "$ZSH" "$ZDOTDIR_TARGET" "$TARGET_HOME/.zshrc" 2>/dev/null || true } _install_zsh() { if command -v zsh >/dev/null 2>&1; then ok "zsh already installed"; return; fi case "$DISTRO" in arch) sudo_ pacman -Sy --noconfirm --needed zsh ;; debian) sudo_ apt-get install -y zsh ;; esac } _install_omz() { if [[ -d "$ZSH/.git" ]]; then ok "oh-my-zsh already present"; return; fi # clone directly (skip the upstream installer so we keep .zshrc under our control) rm -rf "$ZSH" git clone --depth=1 https://github.com/ohmyzsh/ohmyzsh.git "$ZSH" ok "oh-my-zsh cloned to $ZSH" } _install_plugins() { mkdir -p "$ZSH_CUSTOM/plugins" _clone_plugin zsh-users/zsh-autosuggestions "$ZSH_CUSTOM/plugins/zsh-autosuggestions" _clone_plugin zsh-users/zsh-syntax-highlighting "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" _clone_plugin zsh-users/zsh-completions "$ZSH_CUSTOM/plugins/zsh-completions" _clone_plugin zsh-users/zsh-history-substring-search "$ZSH_CUSTOM/plugins/history-substring-search" _clone_plugin Aloxaf/fzf-tab "$ZSH_CUSTOM/plugins/fzf-tab" } _clone_plugin() { # repo dest local repo="$1" dest="$2" if [[ -d "$dest/.git" ]]; then return; fi git clone --depth=1 "https://github.com/$repo.git" "$dest" \ || warn "failed to clone $repo" } _ship_config() { log "shipping zsh config to $ZDOTDIR_TARGET" mkdir -p "$ZDOTDIR_TARGET" local f for f in zshrc aliases.zsh functions.zsh path.zsh plugins.zsh; do local src="$BOOT_DIR/config/zsh/$f" [[ -f "$src" ]] || continue local dst="$ZDOTDIR_TARGET/$f" [[ -f "$dst" ]] && cp "$dst" "${dst}.bak.$(date +%Y%m%d-%H%M%S)" cp "$src" "$dst" done # aliases-extras.zsh is user-owned: only seed it if absent if [[ ! -f "$ZDOTDIR_TARGET/aliases-extras.zsh" ]]; then cp "$BOOT_DIR/config/zsh/aliases-extras.zsh" "$ZDOTDIR_TARGET/aliases-extras.zsh" fi # ~/.zshrc shim that loads our real config via ZDOTDIR local shim="$TARGET_HOME/.zshrc" if ! grep -q 'BOOTSTRAP ZDOTDIR' "$shim" 2>/dev/null; then cat >> "$shim" <<'EOF' # BOOTSTRAP ZDOTDIR — real config lives in ~/.config/zsh export ZDOTDIR="${ZDOTDIR:-$HOME/.config/zsh}" [[ -f "$ZDOTDIR/zshrc" ]] && source "$ZDOTDIR/zshrc" EOF fi # ensure the whole shipped tree is owned by the target user if [[ "$TARGET_USER" != "$USER" ]]; then chown -R "$TARGET_USER:$(id -gn "$TARGET_USER" 2>/dev/null || echo "$TARGET_USER")" "$ZDOTDIR_TARGET" "$shim" fi ok "zsh config installed ($ZDOTDIR_TARGET) + $shim shim" } _set_default_shell() { local zsh_bin; zsh_bin="$(command -v zsh || true)" [[ -z "$zsh_bin" ]] && { warn "zsh not on PATH — skipping chsh"; return; } # ensure listed in /etc/shells if ! grep -qx "$zsh_bin" /etc/shells 2>/dev/null; then echo "$zsh_bin" | sudo_ tee -a /etc/shells >/dev/null fi if [[ "$(getent passwd "$TARGET_USER" | cut -d: -f7)" != "$zsh_bin" ]]; then if yn "Set zsh as default login shell for $TARGET_USER?" y; then sudo_ chsh -s "$zsh_bin" "$TARGET_USER" && ok "default shell set to zsh for $TARGET_USER" else warn "zsh not set as default — run 'chsh -s $zsh_bin' for $TARGET_USER' later" fi else ok "zsh already the default shell for $TARGET_USER" fi }