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:
Frank Qing
2026-08-07 18:34:50 +08:00
parent 9257eceb47
commit e41d2b6e93
5 changed files with 54 additions and 7 deletions
+33 -3
View File
@@ -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"