Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bin/pyenv-activate
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ set -e
# Provide pyenv completions
if [ "$1" = "--complete" ]; then
echo --unset
exec pyenv-virtualenvs --bare
exec pyenv-virtualenvs --bare --only-aliases
Comment thread
samdoran marked this conversation as resolved.
fi

{ printf "\x1B[31;1m"
Expand Down
2 changes: 1 addition & 1 deletion bin/pyenv-virtualenv
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fi

# Provide pyenv completions
if [ "$1" = "--complete" ]; then
exec pyenv-versions --bare
exec pyenv-versions --bare --skip-envs --skip-aliases
fi

unset PIP_REQUIRE_VENV
Expand Down
118 changes: 69 additions & 49 deletions bin/pyenv-virtualenvs
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,9 @@
# 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}" ]; 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})
else
script_path=${BASH_SOURCE}
fi

. ${script_path%/*}/../libexec/pyenv-virtualenv-realpath
[[ -n $PYENV_DEBUG ]] && set -x

if [ -z "$PYENV_ROOT" ]; then
if [[ -z $PYENV_ROOT ]]; then
PYENV_ROOT="${HOME}/.pyenv"
fi

Expand All @@ -47,24 +32,27 @@ done

versions_dir="${PYENV_ROOT}/versions"

if [ -d "$versions_dir" ]; then
versions_dir="$(realpath "$versions_dir")"
fi

if [ -n "$bare" ]; then
hit_prefix=""
miss_prefix=""
if [[ ${BASH_VERSINFO[0]} -gt 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]} -gt 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
Expand All @@ -82,39 +70,71 @@ 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
version_repr="$version"
fi
if [[ ${BASH_VERSINFO[0]} -ge 4 && ${current_versions["$1"]} ]]; then
Comment thread
samdoran marked this conversation as resolved.
echo "${hit_prefix}${version_repr} (set by $(pyenv-version-origin))"
elif [[ ${BASH_VERSINFO[0]} -le 3 ]] && exists "$1" "${current_versions[@]}"; then
echo "${hit_prefix}${version_repr} (set by $(pyenv-version-origin))"
else
echo "${miss_prefix}${1}${print_origin+$2}"
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
fi
virtualenv_prefix="$(pyenv-virtualenv-prefix "${path##*/}" 2>/dev/null || true)"
if [ -d "${virtualenv_prefix}" ]; then
print_version "${path##*/}" " (created from ${virtualenv_prefix})"
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
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

for env_path in "${venv_dir_entries[@]}"; do
if [[ -d ${env_path} ]]; then
print_version "${env_path#"${PYENV_ROOT}"/versions/}" "${env_path}"
fi
done

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
if [[ $num_versions -eq 0 ]] && [[ -n $include_system ]]; then
echo "Warning: no Python virtualenv detected on the system" >&2
exit 1
fi

120 changes: 93 additions & 27 deletions test/virtualenvs.bats
Original file line number Diff line number Diff line change
Expand Up @@ -4,63 +4,129 @@ load test_helper

setup() {
export PYENV_ROOT="${TMP}/pyenv"
mkdir -p "${PYENV_ROOT}/versions/2.7.6"
mkdir -p "${PYENV_ROOT}/versions/3.3.3"
mkdir -p "${PYENV_ROOT}/versions/venv27"
mkdir -p "${PYENV_ROOT}/versions/venv33"
mkdir -p "${PYENV_ROOT}/versions/2.7.6/envs/venv27"
mkdir -p "${PYENV_ROOT}/versions/3.3.3/envs/venv33"
ln -s "${PYENV_ROOT}/versions/2.7.6/envs/venv27" "${PYENV_ROOT}/versions/venv27"
ln -s "${PYENV_ROOT}/versions/3.3.3/envs/venv33" "${PYENV_ROOT}/versions/venv33"
}

@test "list virtual environments only" {
@test "list virtual environments" {
stub pyenv-version-name ": echo system"
stub pyenv-virtualenv-prefix "2.7.6 : false"
stub pyenv-virtualenv-prefix "3.3.3 : false"
stub pyenv-virtualenv-prefix "venv27 : echo \"${PYENV_ROOT}/versions/2.7.6\""
stub pyenv-virtualenv-prefix "venv33 : echo \"${PYENV_ROOT}/versions/3.3.3\""

run pyenv-virtualenvs

assert_success
assert_output <<OUT
venv27 (created from ${PYENV_ROOT}/versions/2.7.6)
venv33 (created from ${PYENV_ROOT}/versions/3.3.3)
2.7.6/envs/venv27
3.3.3/envs/venv33
venv27 --> ${PYENV_ROOT}/versions/2.7.6/envs/venv27
venv33 --> ${PYENV_ROOT}/versions/3.3.3/envs/venv33
OUT

unstub pyenv-version-name
unstub pyenv-virtualenv-prefix
}

@test "list virtual environments with hit prefix" {
stub pyenv-version-name ": echo venv33"
stub pyenv-virtualenv-prefix "2.7.6 : false"
stub pyenv-virtualenv-prefix "3.3.3 : false"
stub pyenv-virtualenv-prefix "venv27 : echo \"/usr\""
stub pyenv-virtualenv-prefix "venv33 : echo \"/usr\""
stub pyenv-version-name ": echo 3.3.3/envs/venv33"
stub pyenv-version-origin ": echo PYENV_VERSION"

run pyenv-virtualenvs

assert_success
assert_output <<OUT
venv27 (created from /usr)
* venv33 (created from /usr)
2.7.6/envs/venv27
* 3.3.3/envs/venv33 (set by PYENV_VERSION)
venv27 --> ${PYENV_ROOT}/versions/2.7.6/envs/venv27
venv33 --> ${PYENV_ROOT}/versions/3.3.3/envs/venv33
OUT

unstub pyenv-version-name
unstub pyenv-virtualenv-prefix
unstub pyenv-version-origin
}

@test "list virtual environments with --bare" {
stub pyenv-virtualenv-prefix "2.7.6 : false"
stub pyenv-virtualenv-prefix "3.3.3 : false"
stub pyenv-virtualenv-prefix "venv27 : echo \"/usr\""
stub pyenv-virtualenv-prefix "venv33 : echo \"/usr\""

@test "list bare virtual environments" {
run pyenv-virtualenvs --bare

assert_success
assert_output <<OUT
2.7.6/envs/venv27
3.3.3/envs/venv33
venv27
venv33
OUT
}

@test "list bare virtual environments without aliases" {
run pyenv-virtualenvs --bare --skip-aliases

assert_success
assert_output <<OUT
2.7.6/envs/venv27
3.3.3/envs/venv33
OUT
}

@test "list virtual environments without aliases" {
stub pyenv-version-name ": echo system"

run pyenv-virtualenvs --skip-aliases

assert_success
assert_output <<OUT
2.7.6/envs/venv27
3.3.3/envs/venv33
OUT

unstub pyenv-version-name
}

@test "hit prefix matches alias version name" {
stub pyenv-version-name ": echo venv27"
stub pyenv-version-origin ": echo PYENV_VERSION"

run pyenv-virtualenvs

assert_success
assert_output <<OUT
2.7.6/envs/venv27
3.3.3/envs/venv33
* venv27 --> ${PYENV_ROOT}/versions/2.7.6/envs/venv27 (set by PYENV_VERSION)
venv33 --> ${PYENV_ROOT}/versions/3.3.3/envs/venv33
OUT

unstub pyenv-version-name
unstub pyenv-version-origin
}

@test "no virtualenvs warning" {
rm -rf "${PYENV_ROOT}/versions"
mkdir -p "${PYENV_ROOT}/versions"
stub pyenv-version-name ": echo system"

run pyenv-virtualenvs

unstub pyenv-virtualenv-prefix
assert_failure
assert_output "Warning: no Python virtualenv detected on the system"

unstub pyenv-version-name
}

@test "no warning with --bare and no virtualenvs" {
rm -rf "${PYENV_ROOT}/versions"
mkdir -p "${PYENV_ROOT}/versions"

run pyenv-virtualenvs --bare

assert_success
assert_output ""
}

@test "completions output" {
run pyenv-virtualenvs --complete

assert_success
assert_output <<OUT
--bare
--skip-aliases
OUT
}