diff --git a/scripts/setup/machine-setup/lib/dev.sh b/scripts/setup/machine-setup/lib/dev.sh index dfa1cc51..22f5f61c 100644 --- a/scripts/setup/machine-setup/lib/dev.sh +++ b/scripts/setup/machine-setup/lib/dev.sh @@ -62,3 +62,40 @@ ask_required() { done printf -v "$__var" '%s' "$answer" } + +# ----------------------------------------------------------------------------- +# Shell +# ----------------------------------------------------------------------------- +# +# ── One starship config, not two ── +# +# The platform deploys scripts/setup/starship.toml into every member's home +# (os-user-shell.ts), and the comment there calls it "the prompt config the +# owner's own install uses — one file, both audiences". That was not true: the +# original machine script wrote a DIFFERENT config inline, so the owner got one +# prompt and every member got another. This deploys the same file the platform +# does, which makes the comment true rather than aspirational. +# +# It lives one directory up because it is shared with the platform, not owned by +# this script. +STARSHIP_SRC="${STARSHIP_SRC:-$SCRIPT_DIR/../starship.toml}" + +user_login_shell() { getent passwd "$USERNAME" | cut -d: -f7; } + +oh_my_zsh_installed() { [[ -d "${USER_HOME}/.oh-my-zsh" ]]; } + +install_oh_my_zsh() { + # The installer refuses to run unattended over an existing install, so this is + # only ever called when there is none. + sudo -H -u "$USERNAME" sh -c \ + "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended >/dev/null 2>&1 +} + +# `chsh` is what actually changes the login shell. Asked separately from +# installing zsh, because having a shell available and being handed it at every +# login are different decisions. +set_login_shell() { + local shell="$1" + grep -qxF "$shell" /etc/shells || echo "$shell" >>/etc/shells + chsh -s "$shell" "$USERNAME" +} diff --git a/scripts/setup/machine-setup/lib/files.sh b/scripts/setup/machine-setup/lib/files.sh index 3046e883..17f41e9d 100644 --- a/scripts/setup/machine-setup/lib/files.sh +++ b/scripts/setup/machine-setup/lib/files.sh @@ -30,6 +30,12 @@ MACHINE_SETUP_FILES_LOADED=1 # Converging when there is nothing to lose and keeping what the user wrote when # there is. The third case prints how to take ours, so the choice stays with # them. +# +# NOTE for callers: 1 and 2 are outcomes, not failures — but they are still +# non-zero, so calling this as a plain command under `set -e` ends the script +# before the result can be read. Always capture it: +# +# install_config "$src" "$dest" "$user" && rc=0 || rc=$? install_config() { local src="$1" dest="$2" owner="$3" diff --git a/scripts/setup/machine-setup/machine-setup.sh b/scripts/setup/machine-setup/machine-setup.sh index 6f64c212..7bb4efff 100755 --- a/scripts/setup/machine-setup/machine-setup.sh +++ b/scripts/setup/machine-setup/machine-setup.sh @@ -1753,13 +1753,113 @@ if ! skip; then step_ok fi +# ============================================================================= +# 23. Shell +# ============================================================================= +# +# zsh, oh-my-zsh, the starship prompt, and the dotfiles that go with them. The +# .tmux.conf lives here rather than in user creation, where the original put it +# only because that is where $USER_HOME first exists. + +step "Shell" +if ! skip; then + SHELL_NOW="$(user_login_shell)" + + echo "" + info "Shell — what ${USERNAME} gets at every login" + echo " login shell: ${SHELL_NOW}" + echo " zsh: $(command -v zsh &>/dev/null && echo 'installed' || echo 'not installed')" + echo " oh-my-zsh: $(oh_my_zsh_installed && echo 'installed' || echo 'not installed')" + echo " starship: $(command -v starship &>/dev/null && echo 'installed' || echo 'not installed')" + + # ── zsh and oh-my-zsh ── + if ! command -v zsh &>/dev/null || ! oh_my_zsh_installed; then + echo "" + echo " oh-my-zsh is a configuration framework for zsh: completions, a" + echo " plugin system, and sensible history behaviour out of the box." + if confirm "Install zsh and oh-my-zsh?"; then + command -v zsh &>/dev/null || pkg_install_now zsh + if ! oh_my_zsh_installed; then + install_oh_my_zsh + oh_my_zsh_installed && ok "oh-my-zsh installed" || warn "oh-my-zsh did not install" + fi + SUMMARY+=("Shell: zsh and oh-my-zsh installed") + else + warn "skipped by request" + SUMMARY+=("Shell: SKIPPED by request") + fi + fi + + # ── the login shell, asked separately ── + # + # Having zsh on the machine and being handed it at every login are different + # decisions, and the original made the second one silently. + if command -v zsh &>/dev/null && [[ "$SHELL_NOW" != *zsh ]]; then + echo "" + echo " ${USERNAME}'s login shell is ${SHELL_NOW}. Changing it to zsh takes" + echo " effect at the next login, and does not affect this session." + if confirm "Make zsh the login shell?"; then + set_login_shell "$(command -v zsh)" + ok "login shell is now $(user_login_shell)" + SUMMARY+=("Shell: login shell set to zsh") + else + warn "left as ${SHELL_NOW}" + SUMMARY+=("Shell: login shell left as ${SHELL_NOW}") + fi + fi + + # ── dotfiles, none of which overwrite ── + if id "$USERNAME" &>/dev/null; then + echo "" + info " shell configuration" + + # The prompt config the platform also deploys to every member. install_config + # keeps whatever is already there if it differs. + if [[ -r "$STARSHIP_SRC" ]]; then + # && / || rather than a bare call: 2 means "kept yours", which is an + # outcome and not a failure, but is still non-zero and would end the run. + install_config "$STARSHIP_SRC" "${USER_HOME}/.config/starship.toml" "$USERNAME" && RC=0 || RC=$? + case $RC in + 0) ok "starship config installed — the same one members get" ;; + 1) echo " starship config already matches" ;; + esac + fi + + if [[ -r "$SCRIPT_DIR/.tmux.conf" ]]; then + install_config "$SCRIPT_DIR/.tmux.conf" "${USER_HOME}/.tmux.conf" "$USERNAME" && RC=0 || RC=$? + case $RC in + 0) ok "tmux config installed" ;; + 1) echo " tmux config already matches" ;; + esac + fi + + # Marker-wrapped, so a second run recognises its own work instead of adding + # it again. The original appended this unguarded on every pass. + if command -v starship &>/dev/null; then + ZSHRC="${USER_HOME}/.zshrc" + touch "$ZSHRC" + chown "$USERNAME:$USERNAME" "$ZSHRC" + if append_once "$ZSHRC" starship <<'EOF' +eval "$(starship init zsh)" +EOF + then + ok "starship added to .zshrc" + else + echo " starship already in .zshrc" + fi + fi + SUMMARY+=("Shell: prompt and dotfiles in place") + fi + step_ok +fi + # ============================================================================= # NOT PORTED YET # ============================================================================= # # Sections still to move across from scripts/setup-old/setup-ubuntu.sh, in order: # -# zsh + prompt (incl. .tmux.conf) · neovim · js runtimes · +# neovim · js runtimes · # dev tools · ufw · zshrc # # And one that is new rather than ported, to come last of all: