Improve performance of pyenv-virtualenvs

Use the code from pyenv-versions for efficiency and consistent output.

The main performance problem was in the call to pyenv-virtualenv-prefix,
which called pyenv-prefix, which then enumerated every virtual environment.
This was done inside a loop, compounding the problem.

Simply the virtual environment listing so that it does not have to call
pyenv-virtualenv-prefix anymore.
This commit is contained in:
Sam Doran 2025-02-13 11:50:18 -05:00
parent 99d35f201c
commit 563bcff28e
No known key found for this signature in database
GPG key ID: 01602635F94328AA

View file

@ -47,24 +47,60 @@ done
versions_dir="${PYENV_ROOT}/versions"
if [ -d "$versions_dir" ]; then
versions_dir="$(realpath "$versions_dir")"
if ! enable -f "${BASH_SOURCE%/*}"/pyenv-realpath.dylib realpath 2>/dev/null; then
if [ -n "$PYENV_NATIVE_EXT" ]; then
echo "pyenv: failed to load \`realpath' builtin" >&2
exit 1
fi
READLINK=$(type -P readlink)
if [ -z "$READLINK" ]; then
echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2
exit 1
fi
resolve_link() {
$READLINK "$1"
}
realpath() {
local path="$1"
local name
# Use a subshell to avoid changing the current path
(
while [ -n "$path" ]; do
name="${path##*/}"
[ "$name" = "$path" ] || cd "${path%/*}"
path="$(resolve_link "$name" || true)"
done
echo "${PWD}/$name"
)
}
fi
if [ -n "$bare" ]; then
hit_prefix=""
miss_prefix=""
if ((BASH_VERSINFO[0] > 3)); then
declare -A current_versions
else
current_versions=()
unset print_origin
fi
if [ -n "$bare" ]; then
include_system=""
else
hit_prefix="* "
miss_prefix=" "
OLDIFS="$IFS"
IFS=: current_versions=($(pyenv-version-name || true))
IFS=:
if ((BASH_VERSINFO[0] > 3)); then
for i in $(pyenv-version-name || true); do
current_versions["$i"]="1"
done
else
read -r -a current_versions <<< "$(pyenv-version-name || true)"
fi
IFS="$OLDIFS"
print_origin="1"
include_system=""
include_system="1"
fi
num_versions=0
@ -82,35 +118,68 @@ exists() {
}
print_version() {
if exists "$1" "${current_versions[@]}"; then
echo "${hit_prefix}${1}${print_origin+$2}"
local version="${1:?}"
if [[ -n $bare ]]; then
echo "$version"
return
fi
local path="${2:?}"
if [[ -L "$path" ]]; then
# Only resolve the link itself for printing, do not resolve further.
# Doing otherwise would misinform the user of what the link contains.
version_repr="$version --> $(readlink "$path")"
else
echo "${miss_prefix}${1}${print_origin+$2}"
version_repr="$version"
fi
if [[ ${BASH_VERSINFO[0]} -ge 4 && ${current_versions["$1"]} ]]; then
echo "${hit_prefix}${version_repr} (set by $(pyenv-version-origin))"
elif (( BASH_VERSINFO[0] <= 3 )) && exists "$1" "${current_versions[@]}"; then
echo "${hit_prefix}${version_repr} (set by $(pyenv-version-origin))"
else
echo "${miss_prefix}${version_repr}"
fi
num_versions=$((num_versions + 1))
}
shopt -s dotglob
shopt -s nullglob
for path in "$versions_dir"/*; do
if [ -d "$path" ]; then
if [ -n "$skip_aliases" ] && [ -L "$path" ]; then
target="$(realpath "$path")"
[ "${target%/*/envs/*}" != "$versions_dir" ] || continue
version_dir_entries=("$versions_dir"/*)
venv_dir_entries=("$versions_dir"/*/envs/*)
if sort --version-sort </dev/null >/dev/null 2>&1; then
# system sort supports version sorting
OLDIFS="$IFS"
IFS='||'
read -r -a version_dir_entries <<< "$(
printf "%s||" "${version_dir_entries[@]}" |
sort --version-sort
)"
read -r -a venv_dir_entries <<< "$(
printf "%s||" "${venv_dir_entries[@]}" |
sort --version-sort
)"
IFS="$OLDIFS"
fi
if [ -z "$only_aliases" ]; then
for env_path in "${venv_dir_entries[@]}"; do
if [ -d "${env_path}" ]; then
print_version "${env_path#"${PYENV_ROOT}"/versions/}" "${env_path}"
fi
virtualenv_prefix="$(pyenv-virtualenv-prefix "${path##*/}" 2>/dev/null || true)"
if [ -d "${virtualenv_prefix}" ]; then
print_version "${path##*/}" " (created from ${virtualenv_prefix})"
done
fi
if [ -z "$skip_aliases" ]; then
for env_path in "${version_dir_entries[@]}"; do
if [ -d "${env_path}" ] && [ -L "${env_path}" ]; then
print_version "${env_path#"${PYENV_ROOT}"/versions/}" "${env_path}"
fi
for venv_path in "${path}/envs/"*; do
venv="${path##*/}/envs/${venv_path##*/}"
virtualenv_prefix="$(pyenv-virtualenv-prefix "${venv}" 2>/dev/null || true)"
if [ -d "${virtualenv_prefix}" ]; then
print_version "${venv}" " (created from ${virtualenv_prefix})"
fi
done
fi
done
done
fi
shopt -u dotglob
shopt -u nullglob