fix(pyenv): preserve shims in login shells
macOS path_helper runs after .zshenv and can move system Python ahead of pyenv. Add an idempotent login hook and preserve it across later easyzsh migrations.
This commit is contained in:
@@ -41,7 +41,9 @@ From a git checkout (shell stubs only):
|
||||
| `~/.config/zshrc/*.zsh` | Personal/tool overlays before oh-my-zsh (interactive) | Left alone |
|
||||
| `~/.local/bin/` | User tools + shims (e.g. `grok` → `~/.grok/bin/grok`) | Left alone |
|
||||
|
||||
easyzsh does **not** manage `~/.zprofile`. Put machine/login hooks in `local.zsh`.
|
||||
Core deploy does not manage `~/.zprofile`. The pyenv add-on appends one login
|
||||
hook so macOS `path_helper` cannot outrank pyenv shims. Put other machine hooks
|
||||
in `local.zsh`.
|
||||
|
||||
Do **not** put `~/.grok/bin` on PATH wholesale.
|
||||
|
||||
|
||||
@@ -68,6 +68,11 @@ is_easyzsh_zprofile_stub() {
|
||||
grep -Eq 'easyzsh|PATH lives in|Leave this file empty|prefer.*local\.zsh' "$f"
|
||||
}
|
||||
|
||||
has_pyenv_login_hook() {
|
||||
local hook='[[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/zsh/pyenv.zsh" ]] && . "${XDG_CONFIG_HOME:-$HOME/.config}/zsh/pyenv.zsh"'
|
||||
[[ -f "$1" ]] && grep -Fqx "$hook" "$1"
|
||||
}
|
||||
|
||||
echo "Deploying easyzsh shell stubs into $TARGET_HOME"
|
||||
|
||||
mkdir -p \
|
||||
@@ -101,7 +106,10 @@ fi
|
||||
|
||||
# Optional: fold a real (non-stub) ~/.zprofile into local.zsh.
|
||||
if [[ "$MIGRATE_ZPROFILE" -eq 1 && -f "$ZPROFILE" ]]; then
|
||||
if is_easyzsh_zprofile_stub "$ZPROFILE"; then
|
||||
if has_pyenv_login_hook "$ZPROFILE"; then
|
||||
# ponytail: keep the whole profile; split migration only if per-line ownership is needed.
|
||||
echo "Keeping ~/.zprofile: contains the pyenv login hook"
|
||||
elif is_easyzsh_zprofile_stub "$ZPROFILE"; then
|
||||
echo "Removing easyzsh ~/.zprofile stub (hooks live in local.zsh / .zshenv)"
|
||||
rm -f "$ZPROFILE"
|
||||
elif [[ ! -f "$LOCAL_ZSH" ]]; then
|
||||
|
||||
@@ -23,5 +23,11 @@ fi
|
||||
|
||||
# Always-on fragment: ~/.config/zsh/pyenv.zsh (sourced from ~/.zshenv)
|
||||
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
|
||||
rm -f "$HOME/.config/zshrc/pyenv.zsh"
|
||||
|
||||
+33
-3
@@ -165,14 +165,44 @@ HOME="$fnm_env_home" PATH=/usr/bin:/bin \
|
||||
|
||||
# Non-interactive zsh must resolve pyenv's global Python via .zshenv.
|
||||
pyenv_env_home="$TEMP_DIR/pyenv-env-home"
|
||||
mkdir -p "$pyenv_env_home/.pyenv/shims" "$pyenv_env_home/.config/zsh"
|
||||
pyenv_env_xdg="$pyenv_env_home/xdg"
|
||||
mkdir -p "$pyenv_env_home/.pyenv/shims" "$pyenv_env_xdg/zsh"
|
||||
ln -s /usr/bin/true "$pyenv_env_home/.pyenv/shims/python3"
|
||||
cp "$ROOT/zsh/pyenv.zsh" "$pyenv_env_home/.config/zsh/pyenv.zsh"
|
||||
cp "$ROOT/zsh/pyenv.zsh" "$pyenv_env_xdg/zsh/pyenv.zsh"
|
||||
HOME="$pyenv_env_home" bash "$ROOT/deploy.sh" --home "$pyenv_env_home" >/dev/null
|
||||
HOME="$pyenv_env_home" PYENV_ROOT="$pyenv_env_home/.pyenv" PATH=/usr/bin:/bin \
|
||||
HOME="$pyenv_env_home" XDG_CONFIG_HOME="$pyenv_env_xdg" \
|
||||
PYENV_ROOT="$pyenv_env_home/.pyenv" PATH=/usr/bin:/bin \
|
||||
zsh -c '[[ "$(command -v python3)" == "$HOME/.pyenv/shims/python3" ]]' ||
|
||||
fail "pyenv Python is not available to non-interactive zsh via .zshenv"
|
||||
|
||||
# Login zsh must reapply pyenv after the system profile changes PATH.
|
||||
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" \
|
||||
PYENV_ROOT="$pyenv_env_home/.pyenv" PATH=/usr/bin:/bin \
|
||||
zsh -lc '[[ "$(command -v python3)" == "$HOME/.pyenv/shims/python3" ]]' ||
|
||||
fail "pyenv Python is not restored in login zsh after the system profile"
|
||||
|
||||
# A later easyzsh migration must not move the login hook before the system profile.
|
||||
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" ||
|
||||
fail "deploy.sh migrated the pyenv login hook out of .zprofile"
|
||||
HOME="$pyenv_env_home" XDG_CONFIG_HOME="$pyenv_env_xdg" \
|
||||
PYENV_ROOT="$pyenv_env_home/.pyenv" PATH=/usr/bin:/bin \
|
||||
zsh -lc '[[ "$(command -v python3)" == "$HOME/.pyenv/shims/python3" ]]' ||
|
||||
fail "pyenv Python was lost after a later easyzsh migration"
|
||||
|
||||
# A comment mentioning the fragment is not an active pyenv login hook.
|
||||
profile_comment_home="$TEMP_DIR/profile-comment-home"
|
||||
mkdir -p "$profile_comment_home"
|
||||
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
|
||||
[[ ! -e "$profile_comment_home/.zprofile" ]] ||
|
||||
fail "deploy.sh treated a pyenv path comment as an active login hook"
|
||||
grep -Fxq 'ordinary-login-hook' "$profile_comment_home/.config/zsh/local.zsh" ||
|
||||
fail "deploy.sh did not migrate an ordinary profile mentioning pyenv"
|
||||
|
||||
# patch.sh path form installs into ~/.config/zsh/
|
||||
path_patch_home="$TEMP_DIR/path-patch-home"
|
||||
path_bin="$TEMP_DIR/path-bin"
|
||||
|
||||
+3
-2
@@ -1,7 +1,8 @@
|
||||
# pyenv (Python Version Manager), always-on via ~/.zshenv
|
||||
export PYENV_ROOT="${PYENV_ROOT:-$HOME/.pyenv}"
|
||||
[[ -d "$PYENV_ROOT/bin" ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||
[[ -d "$PYENV_ROOT/shims" ]] && export PATH="$PYENV_ROOT/shims:$PATH"
|
||||
[[ -d "$PYENV_ROOT/bin" ]] && path=("$PYENV_ROOT/bin" ${path:#$PYENV_ROOT/bin})
|
||||
[[ -d "$PYENV_ROOT/shims" ]] && path=("$PYENV_ROOT/shims" ${path:#$PYENV_ROOT/shims})
|
||||
export PATH
|
||||
if [[ -o interactive ]] && command -v pyenv &> /dev/null; then
|
||||
eval "$(pyenv init - zsh)"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user