Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6799b3fd20 | ||
|
|
34d11b5aa4 |
No files matched your search
@@ -0,0 +1,7 @@
|
|||||||
|
# easyzsh: reapply always-on PATH after macOS path_helper
|
||||||
|
# Login shells only. /etc/zprofile runs path_helper after ~/.zshenv and puts
|
||||||
|
# Homebrew and system paths ahead of fnm, pyenv, and ~/.local/bin.
|
||||||
|
# ~/.zshenv prepends are idempotent, so re-sourcing restores that order.
|
||||||
|
if [[ -x /usr/libexec/path_helper ]]; then
|
||||||
|
. "${ZDOTDIR:-$HOME}/.zshenv"
|
||||||
|
fi
|
||||||
@@ -1,20 +1,23 @@
|
|||||||
# Always-on env for every zsh (interactive, login, agents, zsh -c).
|
# Always-on env for every zsh (interactive, login, agents, zsh -c).
|
||||||
# Machine-local overrides: ~/.config/zsh/local.zsh (never overwritten by deploy).
|
# Safe to re-source: macOS login shells run this again from ~/.zprofile after
|
||||||
|
# path_helper reorders PATH. Machine-local overrides: ~/.config/zsh/local.zsh.
|
||||||
|
|
||||||
|
typeset -U path
|
||||||
|
|
||||||
# Homebrew (macOS). cd /tmp so TCC-protected CWDs do not break brew shellenv.
|
# Homebrew (macOS). cd /tmp so TCC-protected CWDs do not break brew shellenv.
|
||||||
|
# Skip when already initialized (login re-apply, nested zsh).
|
||||||
|
if [[ -z "$HOMEBREW_PREFIX" ]]; then
|
||||||
if [[ -x /opt/homebrew/bin/brew ]]; then
|
if [[ -x /opt/homebrew/bin/brew ]]; then
|
||||||
eval "$(cd /tmp && /opt/homebrew/bin/brew shellenv)"
|
eval "$(cd /tmp && /opt/homebrew/bin/brew shellenv)"
|
||||||
elif [[ -x /usr/local/bin/brew ]]; then
|
elif [[ -x /usr/local/bin/brew ]]; then
|
||||||
eval "$(cd /tmp && /usr/local/bin/brew shellenv)"
|
eval "$(cd /tmp && /usr/local/bin/brew shellenv)"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# User-local binaries (pipx, uv tools, grok shim, …).
|
# User-local binaries (pipx, uv tools, grok shim, …).
|
||||||
# Do not put vendor trees like ~/.grok/bin on PATH wholesale (names like `agent` shadow tools).
|
# Do not put vendor trees like ~/.grok/bin on PATH wholesale (names like `agent` shadow tools).
|
||||||
if [[ -d "$HOME/.local/bin" ]]; then
|
if [[ -d "$HOME/.local/bin" ]]; then
|
||||||
case ":${PATH}:" in
|
path=("$HOME/.local/bin" ${path:#$HOME/.local/bin})
|
||||||
*":$HOME/.local/bin:"*) ;;
|
|
||||||
*) PATH="$HOME/.local/bin:${PATH}" ;;
|
|
||||||
esac
|
|
||||||
export PATH
|
export PATH
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -35,15 +35,18 @@ From a git checkout (shell stubs only):
|
|||||||
| Path | Role | Reinstall |
|
| Path | Role | Reinstall |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `~/.zshenv` | Always-on: Homebrew, `~/.local/bin`, `~/.config/zsh/*.zsh`, then `local.zsh` | Overwritten |
|
| `~/.zshenv` | Always-on: Homebrew, `~/.local/bin`, `~/.config/zsh/*.zsh`, then `local.zsh` | Overwritten |
|
||||||
|
| `~/.zprofile` | Login: re-apply `~/.zshenv` after macOS `path_helper` | Overwritten (extra login lines kept) |
|
||||||
| `~/.zshrc` | Interactive: omz, plugins, aliases, fzf, zoxide | Overwritten |
|
| `~/.zshrc` | Interactive: omz, plugins, aliases, fzf, zoxide | Overwritten |
|
||||||
| `~/.config/zsh/*.zsh` | Always-on tool fragments (e.g. `fnm.zsh`) | Left alone (via `patch.sh`) |
|
| `~/.config/zsh/*.zsh` | Always-on tool fragments (e.g. `fnm.zsh`) | Left alone (via `patch.sh`) |
|
||||||
| `~/.config/zsh/local.zsh` | Machine-local overrides (every zsh, including agents) | **Never overwritten** |
|
| `~/.config/zsh/local.zsh` | Machine-local overrides (every zsh, including agents) | **Never overwritten** |
|
||||||
| `~/.config/zshrc/*.zsh` | Personal/tool overlays before oh-my-zsh (interactive) | Left alone |
|
| `~/.config/zshrc/*.zsh` | Personal/tool overlays before oh-my-zsh (interactive) | Left alone |
|
||||||
| `~/.local/bin/` | User tools + shims (`grok` → Grok CLI; `agent` → Cursor when installed) | Left alone except those two shims |
|
| `~/.local/bin/` | User tools + shims (`grok` → Grok CLI; `agent` → Cursor when installed) | Left alone except those two shims |
|
||||||
|
|
||||||
Core deploy does not manage `~/.zprofile`. The pyenv add-on appends one login
|
macOS login shells run `path_helper` after `~/.zshenv`, which would put Homebrew
|
||||||
hook so macOS `path_helper` cannot outrank pyenv shims. Put other machine hooks
|
ahead of fnm, pyenv, and `~/.local/bin`. `~/.zprofile` re-sources `~/.zshenv`
|
||||||
in `local.zsh`.
|
(idempotent prepends) so login and `zsh -c` keep the same PATH. Put other
|
||||||
|
machine-local env in `local.zsh`; extra login-only lines can stay in
|
||||||
|
`~/.zprofile` below the easyzsh block.
|
||||||
|
|
||||||
Do **not** put `~/.grok/bin` on PATH. That tree ships an `agent` that shadows
|
Do **not** put `~/.grok/bin` on PATH. That tree ships an `agent` that shadows
|
||||||
Cursor. Grok is the `grok` command (`~/.local/bin/grok`). Cursor is `agent`
|
Cursor. Grok is the `grok` command (`~/.local/bin/grok`). Cursor is `agent`
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Install easyzsh shell stubs into a home directory.
|
# Install easyzsh shell stubs into a home directory.
|
||||||
# Overwrites: ~/.zshenv ~/.zshrc
|
# Overwrites: ~/.zshenv ~/.zshrc
|
||||||
|
# Installs: ~/.zprofile (re-applies ~/.zshenv after macOS path_helper)
|
||||||
# Never overwrites: ~/.config/zsh/local.zsh ~/.config/zshrc/** ~/.local/bin/**
|
# Never overwrites: ~/.config/zsh/local.zsh ~/.config/zshrc/** ~/.local/bin/**
|
||||||
# Does not manage ~/.zprofile (machine/login hooks belong in local.zsh).
|
# Extra ~/.zprofile lines stay as login-only hooks unless --migrate-zprofile
|
||||||
|
# folds them into local.zsh.
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# ./deploy.sh
|
# ./deploy.sh
|
||||||
# ./deploy.sh --home /path/to/home
|
# ./deploy.sh --home /path/to/home
|
||||||
# ./deploy.sh --migrate-zprofile # fold real ~/.zprofile into local.zsh, then remove stub
|
# ./deploy.sh --migrate-zprofile # fold extra ~/.zprofile lines into local.zsh
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -58,6 +60,9 @@ file_has_content() {
|
|||||||
[[ -f "$1" ]] && grep -q '[^[:space:]]' "$1"
|
[[ -f "$1" ]] && grep -q '[^[:space:]]' "$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ZPROFILE_MARKER='# easyzsh: reapply always-on PATH after macOS path_helper'
|
||||||
|
PYENV_LOGIN_HOOK='[[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/zsh/pyenv.zsh" ]] && . "${XDG_CONFIG_HOME:-$HOME/.config}/zsh/pyenv.zsh"'
|
||||||
|
|
||||||
is_easyzsh_zprofile_stub() {
|
is_easyzsh_zprofile_stub() {
|
||||||
local f="$1"
|
local f="$1"
|
||||||
[[ -f "$f" ]] || return 1
|
[[ -f "$f" ]] || return 1
|
||||||
@@ -68,9 +73,25 @@ is_easyzsh_zprofile_stub() {
|
|||||||
grep -Eq 'easyzsh|PATH lives in|Leave this file empty|prefer.*local\.zsh' "$f"
|
grep -Eq 'easyzsh|PATH lives in|Leave this file empty|prefer.*local\.zsh' "$f"
|
||||||
}
|
}
|
||||||
|
|
||||||
has_pyenv_login_hook() {
|
is_pyenv_only_zprofile() {
|
||||||
local hook='[[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/zsh/pyenv.zsh" ]] && . "${XDG_CONFIG_HOME:-$HOME/.config}/zsh/pyenv.zsh"'
|
local f="$1"
|
||||||
[[ -f "$1" ]] && grep -Fqx "$hook" "$1"
|
local body
|
||||||
|
[[ -f "$f" ]] || return 1
|
||||||
|
body=$(grep -Ev '^[[:space:]]*(#|$)' "$f" || true)
|
||||||
|
[[ "$body" == "$PYENV_LOGIN_HOOK" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Lines that are not the managed path_helper block or the old pyenv login hook.
|
||||||
|
zprofile_extras() {
|
||||||
|
local f="$1"
|
||||||
|
[[ -f "$f" ]] || return 0
|
||||||
|
awk -v marker="$ZPROFILE_MARKER" -v hook="$PYENV_LOGIN_HOOK" '
|
||||||
|
$0 == marker { in_block=1; next }
|
||||||
|
in_block && $0 == "fi" { in_block=0; next }
|
||||||
|
in_block { next }
|
||||||
|
$0 == hook { next }
|
||||||
|
{ print }
|
||||||
|
' "$f"
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "Deploying easyzsh shell stubs into $TARGET_HOME"
|
echo "Deploying easyzsh shell stubs into $TARGET_HOME"
|
||||||
@@ -104,45 +125,49 @@ if [[ ! -f "$LOCAL_ZSH" ]]; then
|
|||||||
rm -f "$tmp"
|
rm -f "$tmp"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Optional: fold a real (non-stub) ~/.zprofile into local.zsh.
|
# ~/.zprofile re-applies ~/.zshenv after macOS path_helper.
|
||||||
if [[ "$MIGRATE_ZPROFILE" -eq 1 && -f "$ZPROFILE" ]]; then
|
# Replace comment-only stubs and the old pyenv-only hook. Keep other login
|
||||||
if has_pyenv_login_hook "$ZPROFILE"; then
|
# lines, or fold them into local.zsh when --migrate-zprofile is set.
|
||||||
# ponytail: keep the whole profile; split migration only if per-line ownership is needed.
|
zprofile_extras_file=$(mktemp)
|
||||||
echo "Keeping ~/.zprofile: contains the pyenv login hook"
|
: >"$zprofile_extras_file"
|
||||||
elif is_easyzsh_zprofile_stub "$ZPROFILE"; then
|
if [[ -f "$ZPROFILE" ]] && ! is_easyzsh_zprofile_stub "$ZPROFILE" && ! is_pyenv_only_zprofile "$ZPROFILE"; then
|
||||||
echo "Removing easyzsh ~/.zprofile stub (hooks live in local.zsh / .zshenv)"
|
zprofile_extras "$ZPROFILE" | awk '
|
||||||
rm -f "$ZPROFILE"
|
|
||||||
elif [[ ! -f "$LOCAL_ZSH" ]]; then
|
|
||||||
zprofile_extract=$(mktemp)
|
|
||||||
awk '
|
|
||||||
/Created by `pipx`/ { skip_pipx=1; next }
|
/Created by `pipx`/ { skip_pipx=1; next }
|
||||||
skip_pipx && /local\/bin/ { skip_pipx=0; next }
|
skip_pipx && /local\/bin/ { skip_pipx=0; next }
|
||||||
skip_pipx { next }
|
skip_pipx { next }
|
||||||
{ print }
|
{ print }
|
||||||
' "$ZPROFILE" >"$zprofile_extract"
|
' >"$zprofile_extras_file"
|
||||||
if file_has_content "$zprofile_extract"; then
|
|
||||||
cp "$zprofile_extract" "$LOCAL_ZSH"
|
|
||||||
echo "Migrated ~/.zprofile body -> ~/.config/zsh/local.zsh"
|
|
||||||
rm -f "$ZPROFILE"
|
|
||||||
echo "Removed ~/.zprofile after migration"
|
|
||||||
fi
|
|
||||||
rm -f "$zprofile_extract"
|
|
||||||
elif is_easyzsh_zprofile_stub "$ZPROFILE"; then
|
|
||||||
rm -f "$ZPROFILE"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Always drop the comment-only easyzsh stub if present (even without --migrate).
|
if [[ "$MIGRATE_ZPROFILE" -eq 1 ]] && file_has_content "$zprofile_extras_file"; then
|
||||||
if is_easyzsh_zprofile_stub "$ZPROFILE"; then
|
if [[ -f "$LOCAL_ZSH" ]]; then
|
||||||
rm -f "$ZPROFILE"
|
printf '\n' >>"$LOCAL_ZSH"
|
||||||
echo "Removed empty easyzsh ~/.zprofile stub"
|
cat "$zprofile_extras_file" >>"$LOCAL_ZSH"
|
||||||
|
else
|
||||||
|
cp "$zprofile_extras_file" "$LOCAL_ZSH"
|
||||||
|
fi
|
||||||
|
echo "Migrated extra ~/.zprofile lines -> ~/.config/zsh/local.zsh"
|
||||||
|
: >"$zprofile_extras_file"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
backup_file "${TARGET_HOME}/.zshenv"
|
backup_file "${TARGET_HOME}/.zshenv"
|
||||||
backup_file "${TARGET_HOME}/.zshrc"
|
backup_file "${TARGET_HOME}/.zshrc"
|
||||||
|
backup_file "$ZPROFILE"
|
||||||
|
|
||||||
install -m 644 "${ROOT}/.zshenv" "${TARGET_HOME}/.zshenv"
|
install -m 644 "${ROOT}/.zshenv" "${TARGET_HOME}/.zshenv"
|
||||||
install -m 644 "${ROOT}/.zshrc" "${TARGET_HOME}/.zshrc"
|
install -m 644 "${ROOT}/.zshrc" "${TARGET_HOME}/.zshrc"
|
||||||
|
if file_has_content "$zprofile_extras_file"; then
|
||||||
|
{
|
||||||
|
cat "${ROOT}/.zprofile"
|
||||||
|
printf '\n'
|
||||||
|
cat "$zprofile_extras_file"
|
||||||
|
} >"$ZPROFILE"
|
||||||
|
echo "Installed ~/.zprofile (kept extra login lines)"
|
||||||
|
else
|
||||||
|
install -m 644 "${ROOT}/.zprofile" "$ZPROFILE"
|
||||||
|
echo "Installed ~/.zprofile"
|
||||||
|
fi
|
||||||
|
rm -f "$zprofile_extras_file"
|
||||||
|
|
||||||
# Remove obsolete managed-tree layout and examples from earlier deploys.
|
# Remove obsolete managed-tree layout and examples from earlier deploys.
|
||||||
/bin/rm -rf \
|
/bin/rm -rf \
|
||||||
|
|||||||
+2
-1
@@ -357,7 +357,8 @@ echo -e "Downloading easyzsh shell stubs\n"
|
|||||||
for rel in \
|
for rel in \
|
||||||
deploy.sh \
|
deploy.sh \
|
||||||
.zshenv \
|
.zshenv \
|
||||||
.zshrc
|
.zshrc \
|
||||||
|
.zprofile
|
||||||
do
|
do
|
||||||
download_easyzsh_file "$rel"
|
download_easyzsh_file "$rel"
|
||||||
done
|
done
|
||||||
|
|||||||
+2
-7
@@ -21,13 +21,8 @@ fi
|
|||||||
# Uncomment the following line if you would like to automatically install it
|
# Uncomment the following line if you would like to automatically install it
|
||||||
# pyenv install 3.12.0 && pyenv global 3.12.0
|
# pyenv install 3.12.0 && pyenv global 3.12.0
|
||||||
|
|
||||||
# Always-on fragment: ~/.config/zsh/pyenv.zsh (sourced from ~/.zshenv)
|
# Always-on fragment: ~/.config/zsh/pyenv.zsh (sourced from ~/.zshenv).
|
||||||
|
# Login shells re-apply it via ~/.zprofile after macOS path_helper.
|
||||||
curl -fsSL https://git.miomio.moe/mio/easyzsh/raw/branch/master/patch.sh | bash -s -- zsh/pyenv
|
curl -fsSL https://git.miomio.moe/mio/easyzsh/raw/branch/master/patch.sh | bash -s -- zsh/pyenv
|
||||||
# macOS path_helper runs after ~/.zshenv in login shells, so reapply pyenv afterwards.
|
|
||||||
PYENV_LOGIN_HOOK='[[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/zsh/pyenv.zsh" ]] && . "${XDG_CONFIG_HOME:-$HOME/.config}/zsh/pyenv.zsh"'
|
|
||||||
if ! grep -Fqx "$PYENV_LOGIN_HOOK" "$HOME/.zprofile" 2>/dev/null; then
|
|
||||||
[[ ! -s "$HOME/.zprofile" ]] || printf '\n' >> "$HOME/.zprofile"
|
|
||||||
printf '%s\n' "$PYENV_LOGIN_HOOK" >> "$HOME/.zprofile"
|
|
||||||
fi
|
|
||||||
# Drop legacy interactive-only copy if present
|
# Drop legacy interactive-only copy if present
|
||||||
rm -f "$HOME/.config/zshrc/pyenv.zsh"
|
rm -f "$HOME/.config/zshrc/pyenv.zsh"
|
||||||
+83
-12
@@ -81,11 +81,13 @@ for script in "$ROOT"/*.sh; do
|
|||||||
bash -n "$script"
|
bash -n "$script"
|
||||||
done
|
done
|
||||||
|
|
||||||
for config in "$ROOT/.zshenv" "$ROOT/.zshrc" "$ROOT"/zshrc/*.zsh "$ROOT"/zsh/*.zsh; do
|
for config in "$ROOT/.zshenv" "$ROOT/.zshrc" "$ROOT/.zprofile" "$ROOT"/zshrc/*.zsh "$ROOT"/zsh/*.zsh; do
|
||||||
[[ -f "$config" ]] || continue
|
[[ -f "$config" ]] || continue
|
||||||
zsh -n "$config"
|
zsh -n "$config"
|
||||||
done
|
done
|
||||||
[[ ! -e "$ROOT/.zprofile" ]] || fail "easyzsh should not ship a managed .zprofile"
|
[[ -f "$ROOT/.zprofile" ]] || fail "easyzsh should ship a managed .zprofile"
|
||||||
|
grep -Fqx '# easyzsh: reapply always-on PATH after macOS path_helper' "$ROOT/.zprofile" ||
|
||||||
|
fail ".zprofile is missing the path_helper reapply marker"
|
||||||
[[ -f "$ROOT/zsh/fnm.zsh" ]] || fail "always-on fnm fragment is missing"
|
[[ -f "$ROOT/zsh/fnm.zsh" ]] || fail "always-on fnm fragment is missing"
|
||||||
[[ ! -e "$ROOT/zshrc/fnm.zsh" ]] || fail "legacy interactive fnm fragment still exists"
|
[[ ! -e "$ROOT/zshrc/fnm.zsh" ]] || fail "legacy interactive fnm fragment still exists"
|
||||||
[[ -f "$ROOT/zsh/pyenv.zsh" ]] || fail "always-on pyenv fragment is missing"
|
[[ -f "$ROOT/zsh/pyenv.zsh" ]] || fail "always-on pyenv fragment is missing"
|
||||||
@@ -96,6 +98,7 @@ grep -q 'apt-get install -y unzip' "$ROOT/install_fnm.sh" || fail "Ubuntu unzip
|
|||||||
grep -q 'tail -1 || true' "$ROOT/install_merlin_worker.sh" || fail "a missing PYTHONPATH remains fatal"
|
grep -q 'tail -1 || true' "$ROOT/install_merlin_worker.sh" || fail "a missing PYTHONPATH remains fatal"
|
||||||
grep -Fq 'mktemp "$HOME/.zshrc.download.' "$ROOT/install.sh" || fail ".zshrc is not downloaded on its target filesystem"
|
grep -Fq 'mktemp "$HOME/.zshrc.download.' "$ROOT/install.sh" || fail ".zshrc is not downloaded on its target filesystem"
|
||||||
grep -Fq 'mktemp "$HOME/.zshenv.download.' "$ROOT/install.sh" || fail ".zshenv is not downloaded on its target filesystem"
|
grep -Fq 'mktemp "$HOME/.zshenv.download.' "$ROOT/install.sh" || fail ".zshenv is not downloaded on its target filesystem"
|
||||||
|
grep -Fq '.zprofile' "$ROOT/install.sh" || fail "install.sh does not download .zprofile"
|
||||||
grep -Fq 'mktemp "$(dirname "$destination")/.easyzsh-' "$ROOT/patch.sh" || fail "patch downloads can be sourced while incomplete"
|
grep -Fq 'mktemp "$(dirname "$destination")/.easyzsh-' "$ROOT/patch.sh" || fail "patch downloads can be sourced while incomplete"
|
||||||
grep -Fq '"$ZSH_CONFIGS_DIR"/*(DN)' "$ROOT/.zshrc" || fail "existing extensionless Zsh configs are ignored"
|
grep -Fq '"$ZSH_CONFIGS_DIR"/*(DN)' "$ROOT/.zshrc" || fail "existing extensionless Zsh configs are ignored"
|
||||||
grep -Fq '_resolve_trash_cmd' "$ROOT/.zshrc" || fail "trash-backed rm helper is missing"
|
grep -Fq '_resolve_trash_cmd' "$ROOT/.zshrc" || fail "trash-backed rm helper is missing"
|
||||||
@@ -143,6 +146,8 @@ chmod +x "$deploy_home/.grok/bin/grok"
|
|||||||
HOME="$deploy_home" bash "$ROOT/deploy.sh" --home "$deploy_home"
|
HOME="$deploy_home" bash "$ROOT/deploy.sh" --home "$deploy_home"
|
||||||
[[ -f "$deploy_home/.zshenv" ]] || fail "deploy.sh did not install .zshenv"
|
[[ -f "$deploy_home/.zshenv" ]] || fail "deploy.sh did not install .zshenv"
|
||||||
[[ -f "$deploy_home/.zshrc" ]] || fail "deploy.sh did not install .zshrc"
|
[[ -f "$deploy_home/.zshrc" ]] || fail "deploy.sh did not install .zshrc"
|
||||||
|
grep -Fqx '# easyzsh: reapply always-on PATH after macOS path_helper' "$deploy_home/.zprofile" ||
|
||||||
|
fail "deploy.sh did not install .zprofile"
|
||||||
grep -Fxq '# machine-only' "$deploy_home/.config/zsh/local.zsh" ||
|
grep -Fxq '# machine-only' "$deploy_home/.config/zsh/local.zsh" ||
|
||||||
fail "deploy.sh overwrote local.zsh"
|
fail "deploy.sh overwrote local.zsh"
|
||||||
[[ ! -e "$deploy_home/.config/zsh/env" ]] || fail "deploy.sh left obsolete env/ tree"
|
[[ ! -e "$deploy_home/.config/zsh/env" ]] || fail "deploy.sh left obsolete env/ tree"
|
||||||
@@ -205,10 +210,7 @@ HOME="$pyenv_env_home" XDG_CONFIG_HOME="$pyenv_env_xdg" \
|
|||||||
zsh -c '[[ "$(command -v python3)" == "$HOME/.pyenv/shims/python3" ]]' ||
|
zsh -c '[[ "$(command -v python3)" == "$HOME/.pyenv/shims/python3" ]]' ||
|
||||||
fail "pyenv Python is not available to non-interactive zsh via .zshenv"
|
fail "pyenv Python is not available to non-interactive zsh via .zshenv"
|
||||||
|
|
||||||
# Login zsh must reapply pyenv after the system profile changes PATH.
|
# Login zsh must reapply always-on PATH after the system profile (path_helper).
|
||||||
pyenv_login_hook=$(sed -n "s/^PYENV_LOGIN_HOOK='\(.*\)'$/\1/p" "$ROOT/install_pyenv.sh")
|
|
||||||
[[ -n "$pyenv_login_hook" ]] || fail "install_pyenv.sh is missing its login hook"
|
|
||||||
printf '%s\n' "$pyenv_login_hook" > "$pyenv_env_home/.zprofile"
|
|
||||||
HOME="$pyenv_env_home" XDG_CONFIG_HOME="$pyenv_env_xdg" \
|
HOME="$pyenv_env_home" XDG_CONFIG_HOME="$pyenv_env_xdg" \
|
||||||
PYENV_ROOT="$pyenv_env_home/.pyenv" PATH=/usr/bin:/bin \
|
PYENV_ROOT="$pyenv_env_home/.pyenv" PATH=/usr/bin:/bin \
|
||||||
zsh -lc '[[ "$(command -v python3)" == "$HOME/.pyenv/shims/python3" ]]' ||
|
zsh -lc '[[ "$(command -v python3)" == "$HOME/.pyenv/shims/python3" ]]' ||
|
||||||
@@ -234,25 +236,94 @@ HOME="$pyenv_env_home" PYENV_ROOT="$pyenv_env_home/.pyenv" PATH=/usr/bin:/bin \
|
|||||||
printf '%s\n' 'init - --no-rehash zsh' | cmp -s - "$pyenv_env_home/.pyenv/init-calls" ||
|
printf '%s\n' 'init - --no-rehash zsh' | cmp -s - "$pyenv_env_home/.pyenv/init-calls" ||
|
||||||
fail "pyenv initialization must run once without a startup rehash"
|
fail "pyenv initialization must run once without a startup rehash"
|
||||||
|
|
||||||
# A later easyzsh migration must not move the login hook before the system profile.
|
# A later easyzsh migration still restores pyenv; the old pyenv-only hook is replaced.
|
||||||
|
pyenv_login_hook='[[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/zsh/pyenv.zsh" ]] && . "${XDG_CONFIG_HOME:-$HOME/.config}/zsh/pyenv.zsh"'
|
||||||
|
printf '%s\n' "$pyenv_login_hook" > "$pyenv_env_home/.zprofile"
|
||||||
HOME="$pyenv_env_home" bash "$ROOT/deploy.sh" --home "$pyenv_env_home" --migrate-zprofile >/dev/null
|
HOME="$pyenv_env_home" bash "$ROOT/deploy.sh" --home "$pyenv_env_home" --migrate-zprofile >/dev/null
|
||||||
grep -Fqx "$pyenv_login_hook" "$pyenv_env_home/.zprofile" ||
|
grep -Fqx '# easyzsh: reapply always-on PATH after macOS path_helper' "$pyenv_env_home/.zprofile" ||
|
||||||
fail "deploy.sh migrated the pyenv login hook out of .zprofile"
|
fail "deploy.sh did not replace the pyenv-only login hook with the path_helper reapply"
|
||||||
|
if grep -Fqx "$pyenv_login_hook" "$pyenv_env_home/.zprofile"; then
|
||||||
|
fail "deploy.sh left the obsolete pyenv login hook in .zprofile"
|
||||||
|
fi
|
||||||
HOME="$pyenv_env_home" XDG_CONFIG_HOME="$pyenv_env_xdg" \
|
HOME="$pyenv_env_home" XDG_CONFIG_HOME="$pyenv_env_xdg" \
|
||||||
PYENV_ROOT="$pyenv_env_home/.pyenv" PATH=/usr/bin:/bin \
|
PYENV_ROOT="$pyenv_env_home/.pyenv" PATH=/usr/bin:/bin \
|
||||||
zsh -lc '[[ "$(command -v python3)" == "$HOME/.pyenv/shims/python3" ]]' ||
|
zsh -lc '[[ "$(command -v python3)" == "$HOME/.pyenv/shims/python3" ]]' ||
|
||||||
fail "pyenv Python was lost after a later easyzsh migration"
|
fail "pyenv Python was lost after a later easyzsh migration"
|
||||||
|
|
||||||
# A comment mentioning the fragment is not an active pyenv login hook.
|
# Extra login lines are folded into local.zsh on --migrate-zprofile; .zprofile stays managed.
|
||||||
profile_comment_home="$TEMP_DIR/profile-comment-home"
|
profile_comment_home="$TEMP_DIR/profile-comment-home"
|
||||||
mkdir -p "$profile_comment_home"
|
mkdir -p "$profile_comment_home"
|
||||||
printf '%s\n' '# pyenv config: ~/.config/zsh/pyenv.zsh' 'ordinary-login-hook' > "$profile_comment_home/.zprofile"
|
printf '%s\n' '# pyenv config: ~/.config/zsh/pyenv.zsh' 'ordinary-login-hook' > "$profile_comment_home/.zprofile"
|
||||||
HOME="$profile_comment_home" bash "$ROOT/deploy.sh" --home "$profile_comment_home" --migrate-zprofile >/dev/null
|
HOME="$profile_comment_home" bash "$ROOT/deploy.sh" --home "$profile_comment_home" --migrate-zprofile >/dev/null
|
||||||
[[ ! -e "$profile_comment_home/.zprofile" ]] ||
|
grep -Fqx '# easyzsh: reapply always-on PATH after macOS path_helper' "$profile_comment_home/.zprofile" ||
|
||||||
fail "deploy.sh treated a pyenv path comment as an active login hook"
|
fail "deploy.sh did not install the managed .zprofile after migrating extra lines"
|
||||||
|
if grep -Fxq 'ordinary-login-hook' "$profile_comment_home/.zprofile"; then
|
||||||
|
fail "deploy.sh left migrated login lines in .zprofile"
|
||||||
|
fi
|
||||||
grep -Fxq 'ordinary-login-hook' "$profile_comment_home/.config/zsh/local.zsh" ||
|
grep -Fxq 'ordinary-login-hook' "$profile_comment_home/.config/zsh/local.zsh" ||
|
||||||
fail "deploy.sh did not migrate an ordinary profile mentioning pyenv"
|
fail "deploy.sh did not migrate an ordinary profile mentioning pyenv"
|
||||||
|
|
||||||
|
# Without --migrate-zprofile, extra login lines stay in .zprofile below the reapply block.
|
||||||
|
profile_keep_home="$TEMP_DIR/profile-keep-home"
|
||||||
|
mkdir -p "$profile_keep_home"
|
||||||
|
printf '%s\n' 'ordinary-login-hook' > "$profile_keep_home/.zprofile"
|
||||||
|
HOME="$profile_keep_home" bash "$ROOT/deploy.sh" --home "$profile_keep_home" >/dev/null
|
||||||
|
grep -Fqx '# easyzsh: reapply always-on PATH after macOS path_helper' "$profile_keep_home/.zprofile" ||
|
||||||
|
fail "deploy.sh did not install the managed .zprofile in front of extra login lines"
|
||||||
|
grep -Fxq 'ordinary-login-hook' "$profile_keep_home/.zprofile" ||
|
||||||
|
fail "deploy.sh dropped extra login lines without --migrate-zprofile"
|
||||||
|
|
||||||
|
# ~/.local/bin must beat path_helper-promoted system binaries in login zsh.
|
||||||
|
tee_login_home="$TEMP_DIR/tee-login-home"
|
||||||
|
mkdir -p "$tee_login_home/.local/bin"
|
||||||
|
printf '%s\n' '#!/bin/sh' 'echo local-tee' >"$tee_login_home/.local/bin/tee"
|
||||||
|
chmod +x "$tee_login_home/.local/bin/tee"
|
||||||
|
HOME="$tee_login_home" bash "$ROOT/deploy.sh" --home "$tee_login_home" >/dev/null
|
||||||
|
HOME="$tee_login_home" PATH=/usr/bin:/bin \
|
||||||
|
zsh -c '[[ "$(command -v tee)" == "$HOME/.local/bin/tee" ]]' ||
|
||||||
|
fail "~/.local/bin/tee is not preferred in non-login zsh"
|
||||||
|
HOME="$tee_login_home" PATH=/usr/bin:/bin \
|
||||||
|
zsh -lc '[[ "$(command -v tee)" == "$HOME/.local/bin/tee" ]]' ||
|
||||||
|
fail "~/.local/bin/tee is not restored in login zsh after the system profile"
|
||||||
|
|
||||||
|
# Login zsh must prefer fnm-managed npm over Homebrew/system npm.
|
||||||
|
fnm_login_home="$TEMP_DIR/fnm-login-home"
|
||||||
|
mkdir -p "$fnm_login_home/.local/share/fnm/shim/bin" "$fnm_login_home/.config/zsh"
|
||||||
|
cat >"$fnm_login_home/.local/share/fnm/fnm" <<'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
if [[ "$1" == "env" ]]; then
|
||||||
|
shim="$HOME/.local/share/fnm/shim"
|
||||||
|
printf '%s\n' "export PATH=\"${shim}/bin:\$PATH\""
|
||||||
|
printf '%s\n' "export FNM_MULTISHELL_PATH=\"${shim}\""
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
EOF
|
||||||
|
chmod +x "$fnm_login_home/.local/share/fnm/fnm"
|
||||||
|
printf '%s\n' '#!/bin/sh' 'echo fnm-npm' >"$fnm_login_home/.local/share/fnm/shim/bin/npm"
|
||||||
|
chmod +x "$fnm_login_home/.local/share/fnm/shim/bin/npm"
|
||||||
|
cp "$ROOT/zsh/fnm.zsh" "$fnm_login_home/.config/zsh/fnm.zsh"
|
||||||
|
HOME="$fnm_login_home" bash "$ROOT/deploy.sh" --home "$fnm_login_home" >/dev/null
|
||||||
|
HOME="$fnm_login_home" PATH=/usr/bin:/bin \
|
||||||
|
zsh -c '[[ "$(command -v npm)" == "$HOME/.local/share/fnm/shim/bin/npm" ]]' ||
|
||||||
|
fail "fnm npm is not preferred in non-login zsh"
|
||||||
|
HOME="$fnm_login_home" PATH=/usr/bin:/bin \
|
||||||
|
zsh -lc '[[ "$(command -v npm)" == "$HOME/.local/share/fnm/shim/bin/npm" ]]' ||
|
||||||
|
fail "fnm npm is not restored in login zsh after the system profile"
|
||||||
|
|
||||||
|
# Re-sourcing fnm.zsh must reuse the existing multishell instead of stacking PATH.
|
||||||
|
HOME="$fnm_login_home" PATH=/usr/bin:/bin zsh -c '
|
||||||
|
source "$HOME/.config/zsh/fnm.zsh"
|
||||||
|
first=$FNM_MULTISHELL_PATH
|
||||||
|
source "$HOME/.config/zsh/fnm.zsh"
|
||||||
|
[[ $FNM_MULTISHELL_PATH == $first ]] || exit 1
|
||||||
|
n=0
|
||||||
|
for p in $path; do
|
||||||
|
[[ $p == "$first/bin" ]] && n=$((n + 1))
|
||||||
|
done
|
||||||
|
(( n == 1 ))
|
||||||
|
' || fail "fnm.zsh stacked a second multishell on PATH when re-sourced"
|
||||||
|
|
||||||
# patch.sh path form installs into ~/.config/zsh/
|
# patch.sh path form installs into ~/.config/zsh/
|
||||||
path_patch_home="$TEMP_DIR/path-patch-home"
|
path_patch_home="$TEMP_DIR/path-patch-home"
|
||||||
path_bin="$TEMP_DIR/path-bin"
|
path_bin="$TEMP_DIR/path-bin"
|
||||||
|
|||||||
+22
-2
@@ -1,10 +1,30 @@
|
|||||||
# fnm (Fast Node Manager) — always-on (sourced from ~/.zshenv)
|
# fnm (Fast Node Manager) — always-on via ~/.zshenv
|
||||||
FNM_PATH="${XDG_DATA_HOME:-$HOME/.local/share}/fnm"
|
FNM_PATH="${XDG_DATA_HOME:-$HOME/.local/share}/fnm"
|
||||||
[[ -d "$FNM_PATH" ]] && export PATH="$FNM_PATH:$PATH"
|
[[ -d "$FNM_PATH" ]] && path=("$FNM_PATH" ${path:#$FNM_PATH})
|
||||||
|
|
||||||
if command -v fnm &> /dev/null; then
|
if command -v fnm &> /dev/null; then
|
||||||
|
_easyzsh_fnm_state="${XDG_STATE_HOME:-$HOME/.local/state}/fnm_multishells"
|
||||||
|
_easyzsh_fnm_ready=0
|
||||||
|
if [[ -n "$FNM_MULTISHELL_PATH" && -d "$FNM_MULTISHELL_PATH/bin" ]] \
|
||||||
|
&& [[ "$FNM_MULTISHELL_PATH" == "$_easyzsh_fnm_state/"* || "$FNM_MULTISHELL_PATH" == "$FNM_PATH/"* ]]; then
|
||||||
|
if [[ ! -o interactive ]] || (( $+functions[_fnm_autoload_hook] )); then
|
||||||
|
_easyzsh_fnm_ready=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if (( _easyzsh_fnm_ready )); then
|
||||||
|
path=("$FNM_MULTISHELL_PATH/bin" ${path:#$FNM_MULTISHELL_PATH/bin})
|
||||||
|
else
|
||||||
|
_easyzsh_fnm_prev="$FNM_MULTISHELL_PATH"
|
||||||
if [[ -o interactive ]]; then
|
if [[ -o interactive ]]; then
|
||||||
eval "$(fnm env --use-on-cd --shell zsh)"
|
eval "$(fnm env --use-on-cd --shell zsh)"
|
||||||
else
|
else
|
||||||
eval "$(fnm env --shell zsh)"
|
eval "$(fnm env --shell zsh)"
|
||||||
fi
|
fi
|
||||||
|
if [[ -n "$_easyzsh_fnm_prev" ]]; then
|
||||||
|
path=(${path:#$_easyzsh_fnm_prev/bin})
|
||||||
fi
|
fi
|
||||||
|
unset _easyzsh_fnm_prev
|
||||||
|
fi
|
||||||
|
unset _easyzsh_fnm_ready _easyzsh_fnm_state
|
||||||
|
fi
|
||||||
|
export PATH
|
||||||
Reference in new issue
Block a user