fix(pyenv): load managed Python in every zsh

The pyenv fragment lived in the interactive overlay, so agents and zsh -c fell back to system Python. Install it through the always-on fragment path and keep XDG destinations aligned with the loader.
This commit is contained in:
Frank Qing
2026-08-07 18:14:22 +08:00
parent bff5ceddf0
commit 9257eceb47
6 changed files with 31 additions and 15 deletions
+1 -4
View File
@@ -57,8 +57,5 @@ Tool fragments from this repo:
```bash
# always-on (sourced from ~/.zshenv)
curl -fsSL https://git.miomio.moe/mio/easyzsh/raw/branch/master/patch.sh | bash -s -- zsh/fnm
# interactive-only (sourced from ~/.zshrc)
curl -fsSL https://git.miomio.moe/mio/easyzsh/raw/branch/master/patch.sh | bash -s -- pyenv
curl -fsSL https://git.miomio.moe/mio/easyzsh/raw/branch/master/patch.sh | bash -s -- zsh/fnm zsh/pyenv
```
+4 -2
View File
@@ -21,5 +21,7 @@ fi
# Uncomment the following line if you would like to automatically install it
# pyenv install 3.12.0 && pyenv global 3.12.0
# Apply the pyenv zsh configuration patch (downloads zshrc/pyenv.zsh to ~/.config/zshrc/pyenv.zsh)
curl -fsSL https://git.miomio.moe/mio/easyzsh/raw/branch/master/patch.sh | bash -s -- pyenv
# 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
# Drop legacy interactive-only copy if present
rm -f "$HOME/.config/zshrc/pyenv.zsh"
+2 -2
View File
@@ -23,7 +23,7 @@ for arg in "$@"; do
exit 1
fi
rel="${arg}.zsh"
destination="$HOME/.config/${arg}.zsh"
destination="${XDG_CONFIG_HOME:-$HOME/.config}/${arg}.zsh"
else
if [[ -z "$arg" || "$arg" == *[![:alnum:]_-]* ]]; then
echo "Invalid config name: $arg" >&2
@@ -34,7 +34,7 @@ for arg in "$@"; do
fi
mkdir -p "$(dirname "$destination")"
temporary=$(mktemp "$HOME/.config/.easyzsh-XXXXXX")
temporary=$(mktemp "$(dirname "$destination")/.easyzsh-XXXXXX")
trap 'rm -f "$temporary"' EXIT
if ! curl -fsSL "${BASE_URL}/${rel}" -o "$temporary"; then
+17 -3
View File
@@ -88,13 +88,15 @@ done
[[ ! -e "$ROOT/.zprofile" ]] || fail "easyzsh should not ship a managed .zprofile"
[[ -f "$ROOT/zsh/fnm.zsh" ]] || fail "always-on fnm fragment is missing"
[[ ! -e "$ROOT/zshrc/fnm.zsh" ]] || fail "legacy interactive fnm fragment still exists"
[[ -f "$ROOT/zsh/pyenv.zsh" ]] || fail "always-on pyenv fragment is missing"
[[ ! -e "$ROOT/zshrc/pyenv.zsh" ]] || fail "legacy interactive pyenv fragment still exists"
grep -q 'NVM_VERSION="v0.40.4"' "$ROOT/install_nvm.sh" || fail "nvm version is stale"
grep -q 'apt-get install -y unzip' "$ROOT/install_fnm.sh" || fail "Ubuntu unzip installation is missing"
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/.zshenv.download.' "$ROOT/install.sh" || fail ".zshenv is not downloaded on its target filesystem"
grep -Fq 'mktemp "$HOME/.config/.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 '_resolve_trash_cmd' "$ROOT/.zshrc" || fail "trash-backed rm helper is missing"
grep -Fq 'libglib2.0-bin' "$ROOT/install.sh" || fail "Ubuntu Trash support is not installed"
@@ -114,6 +116,7 @@ grep -Fq '$HOME/.local/bin' "$ROOT/.zshenv" || fail "~/.local/bin is not added i
grep -Fq 'local.zsh' "$ROOT/.zshenv" || fail "local.zsh is not sourced from .zshenv"
grep -Fq 'ZSH_ALWAYS_ON_DIR' "$ROOT/.zshenv" || fail "always-on ~/.config/zsh/*.zsh glob is missing from .zshenv"
grep -Fq 'zsh/fnm' "$ROOT/install_fnm.sh" || fail "install_fnm.sh does not patch always-on zsh/fnm"
grep -Fq 'zsh/pyenv' "$ROOT/install_pyenv.sh" || fail "install_pyenv.sh does not patch always-on zsh/pyenv"
if grep -Fq 'brew shellenv' "$ROOT/.zshrc"; then
fail "Homebrew still initializes from interactive-only .zshrc"
fi
@@ -160,6 +163,16 @@ HOME="$fnm_env_home" PATH=/usr/bin:/bin \
zsh -c 'command -v fnm >/dev/null' ||
fail "always-on fnm is not available to non-interactive zsh via .zshenv"
# 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"
ln -s /usr/bin/true "$pyenv_env_home/.pyenv/shims/python3"
cp "$ROOT/zsh/pyenv.zsh" "$pyenv_env_home/.config/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 \
zsh -c '[[ "$(command -v python3)" == "$HOME/.pyenv/shims/python3" ]]' ||
fail "pyenv Python is not available to non-interactive zsh via .zshenv"
# patch.sh path form installs into ~/.config/zsh/
path_patch_home="$TEMP_DIR/path-patch-home"
path_bin="$TEMP_DIR/path-bin"
@@ -180,8 +193,9 @@ printf '%s\n' '# patched-fnm' >"$out"
CURL
chmod +x "$path_bin/curl"
# Prefer real coreutils for mktemp/mkdir used by patch.sh
HOME="$path_patch_home" PATH="$path_bin:/usr/bin:/bin" bash "$ROOT/patch.sh" zsh/fnm >/dev/null
grep -Fxq '# patched-fnm' "$path_patch_home/.config/zsh/fnm.zsh" ||
HOME="$path_patch_home" XDG_CONFIG_HOME="$path_patch_home/xdg" PATH="$path_bin:/usr/bin:/bin" \
bash "$ROOT/patch.sh" zsh/fnm >/dev/null
grep -Fxq '# patched-fnm' "$path_patch_home/xdg/zsh/fnm.zsh" ||
fail "patch.sh zsh/fnm did not install ~/.config/zsh/fnm.zsh"
echo "installer checks passed"
+7
View File
@@ -0,0 +1,7 @@
# 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"
if [[ -o interactive ]] && command -v pyenv &> /dev/null; then
eval "$(pyenv init - zsh)"
fi
-4
View File
@@ -1,4 +0,0 @@
# Initialize pyenv (Python Version Manager)
export PYENV_ROOT="$HOME/.pyenv"
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH" # Add pyenv to PATH
command -v pyenv &> /dev/null && eval "$(pyenv init - zsh)"