mirror of
https://github.com/pyenv/pyenv-virtualenv.git
synced 2026-09-10 07:16:18 -04:00
Drastically speed up precommand hook by caching active version to skip redundant activate calls (#523)
This commit is contained in:
parent
38f3333f3a
commit
72cb35b2b4
|
|
@ -9,6 +9,23 @@
|
||||||
set -e
|
set -e
|
||||||
[ -n "$PYENV_DEBUG" ] && set -x
|
[ -n "$PYENV_DEBUG" ] && set -x
|
||||||
|
|
||||||
|
# Detect stat format for mtime: GNU uses -c %Y, BSD uses -f %m
|
||||||
|
# -L follows symlinks: a symlinked .python-version reflects target changes
|
||||||
|
if stat -L -c %Y / >/dev/null 2>&1; then
|
||||||
|
_stat_fmt="-L -c %Y"
|
||||||
|
else
|
||||||
|
_stat_fmt="-L -f %m"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for version-name hooks at init time. Hooks can alter version
|
||||||
|
# resolution in ways the mtime cache cannot track. If present, the hook
|
||||||
|
# falls back to upstream behavior (no caching). Restart shell after
|
||||||
|
# installing or removing pyenv plugins.
|
||||||
|
_has_version_hooks=""
|
||||||
|
if [ -n "$(pyenv hooks version-name 2>/dev/null)" ]; then
|
||||||
|
_has_version_hooks=1
|
||||||
|
fi
|
||||||
|
|
||||||
resolve_link() {
|
resolve_link() {
|
||||||
$(type -p greadlink readlink | head -1) "$1"
|
$(type -p greadlink readlink | head -1) "$1"
|
||||||
}
|
}
|
||||||
|
|
@ -103,7 +120,8 @@ esac
|
||||||
|
|
||||||
case "$shell" in
|
case "$shell" in
|
||||||
fish )
|
fish )
|
||||||
cat <<EOS
|
if [ -n "$_has_version_hooks" ]; then
|
||||||
|
cat <<EOS
|
||||||
function _pyenv_virtualenv_hook --on-event fish_prompt;
|
function _pyenv_virtualenv_hook --on-event fish_prompt;
|
||||||
set -l ret \$status
|
set -l ret \$status
|
||||||
if [ -n "\$VIRTUAL_ENV" ]
|
if [ -n "\$VIRTUAL_ENV" ]
|
||||||
|
|
@ -114,6 +132,53 @@ function _pyenv_virtualenv_hook --on-event fish_prompt;
|
||||||
return \$ret
|
return \$ret
|
||||||
end
|
end
|
||||||
EOS
|
EOS
|
||||||
|
else
|
||||||
|
cat <<EOS
|
||||||
|
function _pyenv_virtualenv_hook --on-event fish_prompt;
|
||||||
|
set -l ret \$status
|
||||||
|
if test "\$PYENV_VERSION" = "\$_PYENV_VH_VERSION" \\
|
||||||
|
-a "\$VIRTUAL_ENV" = "\$_PYENV_VH_VENV"
|
||||||
|
if test -n "\$PYENV_VERSION"
|
||||||
|
return \$ret
|
||||||
|
end
|
||||||
|
if test "\$PWD" = "\$_PYENV_VH_PWD" \\
|
||||||
|
-a "(stat ${_stat_fmt} \$_PYENV_VH_PATHS 2>/dev/null)" = "\$_PYENV_VH_MTIMES"
|
||||||
|
return \$ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if [ -n "\$VIRTUAL_ENV" ]
|
||||||
|
pyenv activate --quiet; or pyenv deactivate --quiet; or true
|
||||||
|
else
|
||||||
|
pyenv activate --quiet; or true
|
||||||
|
end
|
||||||
|
set -g _PYENV_VH_PWD "\$PWD"
|
||||||
|
set -g _PYENV_VH_VERSION "\$PYENV_VERSION"
|
||||||
|
set -g _PYENV_VH_VENV "\$VIRTUAL_ENV"
|
||||||
|
set -l d "\$PWD"
|
||||||
|
set -l _pvh_found_local 0
|
||||||
|
set -g _PYENV_VH_PATHS
|
||||||
|
while true
|
||||||
|
if test -f "\$d/.python-version"; or test -L "\$d/.python-version"
|
||||||
|
set -g _PYENV_VH_PATHS \$_PYENV_VH_PATHS "\$d/.python-version"
|
||||||
|
if test -f "\$d/.python-version"
|
||||||
|
set _pvh_found_local 1
|
||||||
|
break
|
||||||
|
end
|
||||||
|
else
|
||||||
|
set -g _PYENV_VH_PATHS \$_PYENV_VH_PATHS "\$d"
|
||||||
|
end
|
||||||
|
test "\$d" = "/"; and break
|
||||||
|
set d (string replace -r '/[^/]*\$' '' -- "\$d")
|
||||||
|
test -z "\$d"; and set d "/"
|
||||||
|
end
|
||||||
|
if test "\$_pvh_found_local" = "0"
|
||||||
|
set -g _PYENV_VH_PATHS \$_PYENV_VH_PATHS "\$PYENV_ROOT/version"
|
||||||
|
end
|
||||||
|
set -g _PYENV_VH_MTIMES (stat ${_stat_fmt} \$_PYENV_VH_PATHS 2>/dev/null)
|
||||||
|
return \$ret
|
||||||
|
end
|
||||||
|
EOS
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
ksh )
|
ksh )
|
||||||
cat <<EOS
|
cat <<EOS
|
||||||
|
|
@ -128,7 +193,8 @@ EOS
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [[ "$shell" != "fish" ]]; then
|
if [[ "$shell" != "fish" ]]; then
|
||||||
cat <<EOS
|
if [ -n "$_has_version_hooks" ]; then
|
||||||
|
cat <<EOS
|
||||||
local ret=\$?
|
local ret=\$?
|
||||||
if [ -n "\${VIRTUAL_ENV-}" ]; then
|
if [ -n "\${VIRTUAL_ENV-}" ]; then
|
||||||
eval "\$(pyenv sh-activate --quiet || pyenv sh-deactivate --quiet || true)" || true
|
eval "\$(pyenv sh-activate --quiet || pyenv sh-deactivate --quiet || true)" || true
|
||||||
|
|
@ -138,6 +204,52 @@ if [[ "$shell" != "fish" ]]; then
|
||||||
return \$ret
|
return \$ret
|
||||||
};
|
};
|
||||||
EOS
|
EOS
|
||||||
|
else
|
||||||
|
cat <<EOS
|
||||||
|
local ret=\$?
|
||||||
|
# Cache: env vars checked once, path list and stat rebuilt on miss only
|
||||||
|
if [ "\${PYENV_VERSION-}" = "\${_PYENV_VH_VERSION-}" ] \\
|
||||||
|
&& [ "\${VIRTUAL_ENV-}" = "\${_PYENV_VH_VENV-}" ]; then
|
||||||
|
if [ -n "\${PYENV_VERSION-}" ]; then
|
||||||
|
return \$ret
|
||||||
|
fi
|
||||||
|
if [ "\${PWD}" = "\${_PYENV_VH_PWD-}" ] \\
|
||||||
|
&& [ "\$(stat ${_stat_fmt} "\${_PYENV_VH_PATHS[@]}" 2>/dev/null)" = "\${_PYENV_VH_MTIMES-}" ]; then
|
||||||
|
return \$ret
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ -n "\${VIRTUAL_ENV-}" ]; then
|
||||||
|
eval "\$(pyenv sh-activate --quiet || pyenv sh-deactivate --quiet || true)" || true
|
||||||
|
else
|
||||||
|
eval "\$(pyenv sh-activate --quiet || true)" || true
|
||||||
|
fi
|
||||||
|
_PYENV_VH_PWD="\${PWD}"
|
||||||
|
_PYENV_VH_VERSION="\${PYENV_VERSION-}"
|
||||||
|
_PYENV_VH_VENV="\${VIRTUAL_ENV-}"
|
||||||
|
local _pvh_d="\${PWD}" _pvh_found_local=0
|
||||||
|
_PYENV_VH_PATHS=()
|
||||||
|
while :; do
|
||||||
|
if [ -f "\${_pvh_d}/.python-version" ] || [ -L "\${_pvh_d}/.python-version" ]; then
|
||||||
|
_PYENV_VH_PATHS+=("\${_pvh_d}/.python-version")
|
||||||
|
if [ -f "\${_pvh_d}/.python-version" ]; then
|
||||||
|
_pvh_found_local=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_PYENV_VH_PATHS+=("\${_pvh_d}")
|
||||||
|
fi
|
||||||
|
[ "\${_pvh_d}" = "/" ] && break
|
||||||
|
_pvh_d="\${_pvh_d%/*}"
|
||||||
|
[ -z "\${_pvh_d}" ] && _pvh_d="/"
|
||||||
|
done
|
||||||
|
if [ "\${_pvh_found_local}" = "0" ]; then
|
||||||
|
_PYENV_VH_PATHS+=("\${PYENV_ROOT}/version")
|
||||||
|
fi
|
||||||
|
_PYENV_VH_MTIMES="\$(stat ${_stat_fmt} "\${_PYENV_VH_PATHS[@]}" 2>/dev/null)"
|
||||||
|
return \$ret
|
||||||
|
};
|
||||||
|
EOS
|
||||||
|
fi
|
||||||
|
|
||||||
case "$shell" in
|
case "$shell" in
|
||||||
bash )
|
bash )
|
||||||
|
|
|
||||||
102
test/init.bats
102
test/init.bats
|
|
@ -54,11 +54,45 @@ export PATH="${TMP}/pyenv/plugins/pyenv-virtualenv/shims:\${PATH}";
|
||||||
export PYENV_VIRTUALENV_INIT=1;
|
export PYENV_VIRTUALENV_INIT=1;
|
||||||
_pyenv_virtualenv_hook() {
|
_pyenv_virtualenv_hook() {
|
||||||
local ret=\$?
|
local ret=\$?
|
||||||
|
# Cache: env vars checked once, path list and stat rebuilt on miss only
|
||||||
|
if [ "\${PYENV_VERSION-}" = "\${_PYENV_VH_VERSION-}" ] \\
|
||||||
|
&& [ "\${VIRTUAL_ENV-}" = "\${_PYENV_VH_VENV-}" ]; then
|
||||||
|
if [ -n "\${PYENV_VERSION-}" ]; then
|
||||||
|
return \$ret
|
||||||
|
fi
|
||||||
|
if [ "\${PWD}" = "\${_PYENV_VH_PWD-}" ] \\
|
||||||
|
&& [ "\$(stat ${_stat_fmt} "\${_PYENV_VH_PATHS[@]}" 2>/dev/null)" = "\${_PYENV_VH_MTIMES-}" ]; then
|
||||||
|
return \$ret
|
||||||
|
fi
|
||||||
|
fi
|
||||||
if [ -n "\${VIRTUAL_ENV-}" ]; then
|
if [ -n "\${VIRTUAL_ENV-}" ]; then
|
||||||
eval "\$(pyenv sh-activate --quiet || pyenv sh-deactivate --quiet || true)" || true
|
eval "\$(pyenv sh-activate --quiet || pyenv sh-deactivate --quiet || true)" || true
|
||||||
else
|
else
|
||||||
eval "\$(pyenv sh-activate --quiet || true)" || true
|
eval "\$(pyenv sh-activate --quiet || true)" || true
|
||||||
fi
|
fi
|
||||||
|
_PYENV_VH_PWD="\${PWD}"
|
||||||
|
_PYENV_VH_VERSION="\${PYENV_VERSION-}"
|
||||||
|
_PYENV_VH_VENV="\${VIRTUAL_ENV-}"
|
||||||
|
local _pvh_d="\${PWD}" _pvh_found_local=0
|
||||||
|
_PYENV_VH_PATHS=()
|
||||||
|
while :; do
|
||||||
|
if [ -f "\${_pvh_d}/.python-version" ] || [ -L "\${_pvh_d}/.python-version" ]; then
|
||||||
|
_PYENV_VH_PATHS+=("\${_pvh_d}/.python-version")
|
||||||
|
if [ -f "\${_pvh_d}/.python-version" ]; then
|
||||||
|
_pvh_found_local=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_PYENV_VH_PATHS+=("\${_pvh_d}")
|
||||||
|
fi
|
||||||
|
[ "\${_pvh_d}" = "/" ] && break
|
||||||
|
_pvh_d="\${_pvh_d%/*}"
|
||||||
|
[ -z "\${_pvh_d}" ] && _pvh_d="/"
|
||||||
|
done
|
||||||
|
if [ "\${_pvh_found_local}" = "0" ]; then
|
||||||
|
_PYENV_VH_PATHS+=("\${PYENV_ROOT}/version")
|
||||||
|
fi
|
||||||
|
_PYENV_VH_MTIMES="\$(stat ${_stat_fmt} "\${_PYENV_VH_PATHS[@]}" 2>/dev/null)"
|
||||||
return \$ret
|
return \$ret
|
||||||
};
|
};
|
||||||
if ! [[ "\${PROMPT_COMMAND-}" =~ _pyenv_virtualenv_hook ]]; then
|
if ! [[ "\${PROMPT_COMMAND-}" =~ _pyenv_virtualenv_hook ]]; then
|
||||||
|
|
@ -78,11 +112,45 @@ set -gx PATH '${TMP}/pyenv/plugins/pyenv-virtualenv/shims' \$PATH;
|
||||||
set -gx PYENV_VIRTUALENV_INIT 1;
|
set -gx PYENV_VIRTUALENV_INIT 1;
|
||||||
function _pyenv_virtualenv_hook --on-event fish_prompt;
|
function _pyenv_virtualenv_hook --on-event fish_prompt;
|
||||||
set -l ret \$status
|
set -l ret \$status
|
||||||
|
if test "\$PYENV_VERSION" = "\$_PYENV_VH_VERSION" \\
|
||||||
|
-a "\$VIRTUAL_ENV" = "\$_PYENV_VH_VENV"
|
||||||
|
if test -n "\$PYENV_VERSION"
|
||||||
|
return \$ret
|
||||||
|
end
|
||||||
|
if test "\$PWD" = "\$_PYENV_VH_PWD" \\
|
||||||
|
-a "(stat ${_stat_fmt} \$_PYENV_VH_PATHS 2>/dev/null)" = "\$_PYENV_VH_MTIMES"
|
||||||
|
return \$ret
|
||||||
|
end
|
||||||
|
end
|
||||||
if [ -n "\$VIRTUAL_ENV" ]
|
if [ -n "\$VIRTUAL_ENV" ]
|
||||||
pyenv activate --quiet; or pyenv deactivate --quiet; or true
|
pyenv activate --quiet; or pyenv deactivate --quiet; or true
|
||||||
else
|
else
|
||||||
pyenv activate --quiet; or true
|
pyenv activate --quiet; or true
|
||||||
end
|
end
|
||||||
|
set -g _PYENV_VH_PWD "\$PWD"
|
||||||
|
set -g _PYENV_VH_VERSION "\$PYENV_VERSION"
|
||||||
|
set -g _PYENV_VH_VENV "\$VIRTUAL_ENV"
|
||||||
|
set -l d "\$PWD"
|
||||||
|
set -l _pvh_found_local 0
|
||||||
|
set -g _PYENV_VH_PATHS
|
||||||
|
while true
|
||||||
|
if test -f "\$d/.python-version"; or test -L "\$d/.python-version"
|
||||||
|
set -g _PYENV_VH_PATHS \$_PYENV_VH_PATHS "\$d/.python-version"
|
||||||
|
if test -f "\$d/.python-version"
|
||||||
|
set _pvh_found_local 1
|
||||||
|
break
|
||||||
|
end
|
||||||
|
else
|
||||||
|
set -g _PYENV_VH_PATHS \$_PYENV_VH_PATHS "\$d"
|
||||||
|
end
|
||||||
|
test "\$d" = "/"; and break
|
||||||
|
set d (string replace -r '/[^/]*\$' '' -- "\$d")
|
||||||
|
test -z "\$d"; and set d "/"
|
||||||
|
end
|
||||||
|
if test "\$_pvh_found_local" = "0"
|
||||||
|
set -g _PYENV_VH_PATHS \$_PYENV_VH_PATHS "\$PYENV_ROOT/version"
|
||||||
|
end
|
||||||
|
set -g _PYENV_VH_MTIMES (stat ${_stat_fmt} \$_PYENV_VH_PATHS 2>/dev/null)
|
||||||
return \$ret
|
return \$ret
|
||||||
end
|
end
|
||||||
EOS
|
EOS
|
||||||
|
|
@ -97,11 +165,45 @@ export PATH="${TMP}/pyenv/plugins/pyenv-virtualenv/shims:\${PATH}";
|
||||||
export PYENV_VIRTUALENV_INIT=1;
|
export PYENV_VIRTUALENV_INIT=1;
|
||||||
_pyenv_virtualenv_hook() {
|
_pyenv_virtualenv_hook() {
|
||||||
local ret=\$?
|
local ret=\$?
|
||||||
|
# Cache: env vars checked once, path list and stat rebuilt on miss only
|
||||||
|
if [ "\${PYENV_VERSION-}" = "\${_PYENV_VH_VERSION-}" ] \\
|
||||||
|
&& [ "\${VIRTUAL_ENV-}" = "\${_PYENV_VH_VENV-}" ]; then
|
||||||
|
if [ -n "\${PYENV_VERSION-}" ]; then
|
||||||
|
return \$ret
|
||||||
|
fi
|
||||||
|
if [ "\${PWD}" = "\${_PYENV_VH_PWD-}" ] \\
|
||||||
|
&& [ "\$(stat ${_stat_fmt} "\${_PYENV_VH_PATHS[@]}" 2>/dev/null)" = "\${_PYENV_VH_MTIMES-}" ]; then
|
||||||
|
return \$ret
|
||||||
|
fi
|
||||||
|
fi
|
||||||
if [ -n "\${VIRTUAL_ENV-}" ]; then
|
if [ -n "\${VIRTUAL_ENV-}" ]; then
|
||||||
eval "\$(pyenv sh-activate --quiet || pyenv sh-deactivate --quiet || true)" || true
|
eval "\$(pyenv sh-activate --quiet || pyenv sh-deactivate --quiet || true)" || true
|
||||||
else
|
else
|
||||||
eval "\$(pyenv sh-activate --quiet || true)" || true
|
eval "\$(pyenv sh-activate --quiet || true)" || true
|
||||||
fi
|
fi
|
||||||
|
_PYENV_VH_PWD="\${PWD}"
|
||||||
|
_PYENV_VH_VERSION="\${PYENV_VERSION-}"
|
||||||
|
_PYENV_VH_VENV="\${VIRTUAL_ENV-}"
|
||||||
|
local _pvh_d="\${PWD}" _pvh_found_local=0
|
||||||
|
_PYENV_VH_PATHS=()
|
||||||
|
while :; do
|
||||||
|
if [ -f "\${_pvh_d}/.python-version" ] || [ -L "\${_pvh_d}/.python-version" ]; then
|
||||||
|
_PYENV_VH_PATHS+=("\${_pvh_d}/.python-version")
|
||||||
|
if [ -f "\${_pvh_d}/.python-version" ]; then
|
||||||
|
_pvh_found_local=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_PYENV_VH_PATHS+=("\${_pvh_d}")
|
||||||
|
fi
|
||||||
|
[ "\${_pvh_d}" = "/" ] && break
|
||||||
|
_pvh_d="\${_pvh_d%/*}"
|
||||||
|
[ -z "\${_pvh_d}" ] && _pvh_d="/"
|
||||||
|
done
|
||||||
|
if [ "\${_pvh_found_local}" = "0" ]; then
|
||||||
|
_PYENV_VH_PATHS+=("\${PYENV_ROOT}/version")
|
||||||
|
fi
|
||||||
|
_PYENV_VH_MTIMES="\$(stat ${_stat_fmt} "\${_PYENV_VH_PATHS[@]}" 2>/dev/null)"
|
||||||
return \$ret
|
return \$ret
|
||||||
};
|
};
|
||||||
typeset -g -a precmd_functions
|
typeset -g -a precmd_functions
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,12 @@
|
||||||
export TMP="$BATS_TEST_DIRNAME/tmp"
|
export TMP="$BATS_TEST_DIRNAME/tmp"
|
||||||
|
|
||||||
|
# Detect stat format for mtime: GNU uses -c %Y, BSD uses -f %m
|
||||||
|
# Must match the detection in bin/pyenv-virtualenv-init
|
||||||
|
if stat -L -c %Y / >/dev/null 2>&1; then
|
||||||
|
_stat_fmt="-L -c %Y"
|
||||||
|
else
|
||||||
|
_stat_fmt="-L -f %m"
|
||||||
|
fi
|
||||||
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
||||||
|
|
||||||
PATH=/usr/bin:/usr/sbin:/bin:/sbin
|
PATH=/usr/bin:/usr/sbin:/bin:/sbin
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue