mirror of
https://github.com/pyenv/pyenv-virtualenv.git
synced 2026-09-10 07:16:18 -04:00
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:
parent
99d35f201c
commit
563bcff28e
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue