mirror of
https://github.com/pyenv/pyenv-virtualenv.git
synced 2026-09-14 17:26:28 -04:00
This is useful for listing the “frinedly” virtualenv names instead of the short path which includes the Python version.
192 lines
4.3 KiB
Bash
Executable file
192 lines
4.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# Summary: List all Python virtualenvs found in `$PYENV_ROOT/versions/*'.
|
|
# Usage: pyenv virtualenvs [--bare] [--skip-aliases] [--only-aliases]
|
|
#
|
|
# List all virtualenvs found in `$PYENV_ROOT/versions/*' and its `$PYENV_ROOT/versions/envs/*'.
|
|
|
|
set -e
|
|
[ -n "$PYENV_DEBUG" ] && set -x
|
|
if [ -L "${BASH_SOURCE[0]}" ]; then
|
|
READLINK=$(type -p greadlink readlink | head -1)
|
|
if [ -z "$READLINK" ]; then
|
|
echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2
|
|
exit 1
|
|
fi
|
|
resolve_link() {
|
|
$READLINK -f "$1"
|
|
}
|
|
script_path=$(resolve_link "${BASH_SOURCE[0]}")
|
|
else
|
|
script_path="${BASH_SOURCE[0]}"
|
|
fi
|
|
|
|
. "${script_path%/*}"/../libexec/pyenv-virtualenv-realpath
|
|
|
|
if [ -z "$PYENV_ROOT" ]; then
|
|
PYENV_ROOT="${HOME}/.pyenv"
|
|
fi
|
|
|
|
unset bare
|
|
unset skip_aliases
|
|
# Provide pyenv completions
|
|
for arg; do
|
|
case "$arg" in
|
|
--complete )
|
|
echo --bare
|
|
echo --only-aliases
|
|
exit ;;
|
|
--bare ) bare=1 ;;
|
|
--skip-aliases ) skip_aliases=1 ;;
|
|
--only-aliases ) only_aliases=1 ;;
|
|
* )
|
|
pyenv-help --usage virtualenvs >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
versions_dir="${PYENV_ROOT}/versions"
|
|
|
|
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 ((BASH_VERSINFO[0] > 3)); then
|
|
declare -A current_versions
|
|
else
|
|
current_versions=()
|
|
fi
|
|
if [ -n "$bare" ]; then
|
|
include_system=""
|
|
else
|
|
hit_prefix="* "
|
|
miss_prefix=" "
|
|
OLDIFS="$IFS"
|
|
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"
|
|
include_system="1"
|
|
fi
|
|
|
|
num_versions=0
|
|
|
|
exists() {
|
|
local car="$1"
|
|
local cdar
|
|
shift
|
|
for cdar in "$@"; do
|
|
if [ "${car}" == "${cdar}" ]; then
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
print_version() {
|
|
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
|
|
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
|
|
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
|
|
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
|
|
done
|
|
fi
|
|
|
|
shopt -u dotglob
|
|
shopt -u nullglob
|
|
|
|
if [ "$num_versions" -eq 0 ] && [ -n "$include_system" ]; then
|
|
echo "Warning: no Python virtualenv detected on the system" >&2
|
|
exit 1
|
|
fi
|
|
|