fix(shell): use single ~/.config/zsh/local.zsh for machine local
Replace the local/ directory of split env/login/interactive files with one always-on local.zsh sourced from .zshenv. Deploy migrates old fragments and never overwrites local.zsh.
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
# Install managed easyzsh shell layout into a home directory.
|
||||
# Overwrites: ~/.zshenv ~/.zshrc ~/.zprofile ~/.config/zsh/{env,interactive,login}
|
||||
# Never overwrites: ~/.config/zsh/local/** ~/.config/zshrc/** ~/.local/bin/**
|
||||
# Never overwrites: ~/.config/zsh/local.zsh ~/.config/zshrc/** ~/.local/bin/**
|
||||
#
|
||||
# Usage:
|
||||
# ./deploy.sh
|
||||
# ./deploy.sh --home /path/to/home
|
||||
# ./deploy.sh --migrate-zprofile # move existing ~/.zprofile body into login.local
|
||||
# ./deploy.sh --migrate-zprofile # fold pre-easyzsh ~/.zprofile into local.zsh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -41,6 +41,7 @@ if [[ ! -d "$TARGET_HOME" ]]; then
|
||||
fi
|
||||
|
||||
ZSH_CFG="${TARGET_HOME}/.config/zsh"
|
||||
LOCAL_ZSH="${ZSH_CFG}/local.zsh"
|
||||
ts=$(date +%Y%m%d-%H%M%S)
|
||||
|
||||
backup_file() {
|
||||
@@ -51,49 +52,83 @@ backup_file() {
|
||||
fi
|
||||
}
|
||||
|
||||
file_has_content() {
|
||||
[[ -f "$1" ]] && grep -q '[^[:space:]]' "$1"
|
||||
}
|
||||
|
||||
echo "Deploying easyzsh managed shell layout into $TARGET_HOME"
|
||||
|
||||
mkdir -p \
|
||||
"${ZSH_CFG}/env" \
|
||||
"${ZSH_CFG}/interactive" \
|
||||
"${ZSH_CFG}/login" \
|
||||
"${ZSH_CFG}/local" \
|
||||
"${TARGET_HOME}/.config/zshrc" \
|
||||
"${TARGET_HOME}/.cache/zsh" \
|
||||
"${TARGET_HOME}/.local/bin"
|
||||
|
||||
# Migrate legacy early env if present and new path missing.
|
||||
if [[ -f "${TARGET_HOME}/.config/zshenv.local" && ! -f "${ZSH_CFG}/local/env.local.zsh" ]]; then
|
||||
cp -Pp "${TARGET_HOME}/.config/zshenv.local" "${ZSH_CFG}/local/env.local.zsh"
|
||||
echo "Migrated ~/.config/zshenv.local -> ~/.config/zsh/local/env.local.zsh"
|
||||
# Migrate split local/* and legacy paths into ~/.config/zsh/local.zsh once.
|
||||
if [[ ! -f "$LOCAL_ZSH" ]]; then
|
||||
tmp=$(mktemp)
|
||||
: >"$tmp"
|
||||
if file_has_content "${TARGET_HOME}/.config/zshenv.local"; then
|
||||
cat "${TARGET_HOME}/.config/zshenv.local" >>"$tmp"
|
||||
printf '\n' >>"$tmp"
|
||||
fi
|
||||
if [[ -d "${ZSH_CFG}/local" ]]; then
|
||||
for part in env.local.zsh login.local.zsh interactive.local.zsh; do
|
||||
if file_has_content "${ZSH_CFG}/local/${part}"; then
|
||||
cat "${ZSH_CFG}/local/${part}" >>"$tmp"
|
||||
printf '\n' >>"$tmp"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if file_has_content "$tmp"; then
|
||||
# De-dup consecutive identical non-empty lines lightly by collapsing exact file repeats later if needed.
|
||||
cp "$tmp" "$LOCAL_ZSH"
|
||||
echo "Migrated machine-local fragments -> ~/.config/zsh/local.zsh"
|
||||
fi
|
||||
rm -f "$tmp"
|
||||
fi
|
||||
|
||||
# Optionally migrate existing zprofile body into login.local (strip redundant PATH).
|
||||
if [[ "$MIGRATE_ZPROFILE" -eq 1 ]]; then
|
||||
if [[ -f "${TARGET_HOME}/.zprofile" && ! -f "${ZSH_CFG}/local/login.local.zsh" ]]; then
|
||||
# Drop easyzsh stub lines and pipx ~/.local/bin PATH (now owned by env/00-path.zsh).
|
||||
# After migration (or if local.zsh already exists), drop obsolete split files.
|
||||
if [[ -d "${ZSH_CFG}/local" ]]; then
|
||||
rm -f \
|
||||
"${ZSH_CFG}/local/env.local.zsh" \
|
||||
"${ZSH_CFG}/local/login.local.zsh" \
|
||||
"${ZSH_CFG}/local/interactive.local.zsh" \
|
||||
"${ZSH_CFG}/local/env.local.zsh.example" \
|
||||
"${ZSH_CFG}/local/login.local.zsh.example" \
|
||||
"${ZSH_CFG}/local/interactive.local.zsh.example"
|
||||
rmdir "${ZSH_CFG}/local" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Fold a pre-easyzsh ~/.zprofile into local.zsh. Skip if already an easyzsh stub.
|
||||
if [[ "$MIGRATE_ZPROFILE" -eq 1 && -f "${TARGET_HOME}/.zprofile" ]]; then
|
||||
if grep -Fq 'easyzsh stub' "${TARGET_HOME}/.zprofile"; then
|
||||
echo "Skipping zprofile migration: already an easyzsh stub"
|
||||
elif [[ ! -f "$LOCAL_ZSH" ]]; then
|
||||
zprofile_extract=$(mktemp)
|
||||
awk '
|
||||
/^# easyzsh stub/ { next }
|
||||
/^EASYZSH_HOME=/ { next }
|
||||
/for _easyzsh_f in/ { skip=1 }
|
||||
skip && /unset _easyzsh_f/ { skip=0; next }
|
||||
skip { next }
|
||||
/login\.local\.zsh/ { next }
|
||||
/Created by `pipx`/ { skip_pipx=1; next }
|
||||
skip_pipx && /local\/bin/ { skip_pipx=0; next }
|
||||
skip_pipx { next }
|
||||
{ print }
|
||||
' "${TARGET_HOME}/.zprofile" > "${ZSH_CFG}/local/login.local.zsh"
|
||||
# Trim trailing blank lines noise if file became empty-ish
|
||||
if ! grep -q '[^[:space:]]' "${ZSH_CFG}/local/login.local.zsh"; then
|
||||
rm -f "${ZSH_CFG}/local/login.local.zsh"
|
||||
echo "Existing .zprofile had no login-local content after migration"
|
||||
else
|
||||
echo "Migrated ~/.zprofile body -> ~/.config/zsh/local/login.local.zsh"
|
||||
' "${TARGET_HOME}/.zprofile" >"$zprofile_extract"
|
||||
if file_has_content "$zprofile_extract"; then
|
||||
cp "$zprofile_extract" "$LOCAL_ZSH"
|
||||
echo "Migrated ~/.zprofile body -> ~/.config/zsh/local.zsh"
|
||||
fi
|
||||
rm -f "$zprofile_extract"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remove a broken local.zsh produced by an earlier stub-body migration.
|
||||
if [[ -f "$LOCAL_ZSH" ]] && grep -Fq 'local/login.local.zsh' "$LOCAL_ZSH" && ! grep -Eq 'cargo|OrbStack|MacPorts|Kiro|fnm' "$LOCAL_ZSH"; then
|
||||
backup_file "$LOCAL_ZSH"
|
||||
rm -f "$LOCAL_ZSH"
|
||||
echo "Removed broken stub residue from local.zsh"
|
||||
fi
|
||||
|
||||
backup_file "${TARGET_HOME}/.zshenv"
|
||||
backup_file "${TARGET_HOME}/.zshrc"
|
||||
backup_file "${TARGET_HOME}/.zprofile"
|
||||
@@ -102,25 +137,19 @@ install -m 644 "${ROOT}/.zshenv" "${TARGET_HOME}/.zshenv"
|
||||
install -m 644 "${ROOT}/.zshrc" "${TARGET_HOME}/.zshrc"
|
||||
install -m 644 "${ROOT}/.zprofile" "${TARGET_HOME}/.zprofile"
|
||||
|
||||
# Replace managed modules only (never touch local/).
|
||||
# Replace managed modules only (never touch local.zsh).
|
||||
rm -f "${ZSH_CFG}/env"/*.zsh
|
||||
rm -f "${ZSH_CFG}/interactive"/*.zsh
|
||||
rm -f "${ZSH_CFG}/login"/*.zsh
|
||||
install -m 644 "${ROOT}/config/env/"*.zsh "${ZSH_CFG}/env/"
|
||||
install -m 644 "${ROOT}/config/interactive/"*.zsh "${ZSH_CFG}/interactive/"
|
||||
# login may be empty of modules
|
||||
if compgen -G "${ROOT}/config/login/"*.zsh > /dev/null; then
|
||||
install -m 644 "${ROOT}/config/login/"*.zsh "${ZSH_CFG}/login/"
|
||||
fi
|
||||
|
||||
# Seed examples only when missing (never overwrite user locals).
|
||||
for example in env.local.zsh login.local.zsh interactive.local.zsh; do
|
||||
src="${ROOT}/local/${example}.example"
|
||||
dst="${ZSH_CFG}/local/${example}.example"
|
||||
if [[ -f "$src" ]]; then
|
||||
install -m 644 "$src" "$dst"
|
||||
fi
|
||||
done
|
||||
if [[ -f "${ROOT}/local.zsh.example" ]]; then
|
||||
install -m 644 "${ROOT}/local.zsh.example" "${ZSH_CFG}/local.zsh.example"
|
||||
fi
|
||||
|
||||
# Ensure intentional grok shim when the binary tree exists.
|
||||
if [[ -e "${TARGET_HOME}/.grok/bin/grok" ]]; then
|
||||
|
||||
Reference in New Issue
Block a user