mirror of
https://github.com/pyenv/pyenv.git
synced 2026-04-06 21:55:11 +09:00
rehash: streamline executables discovery; fix regression (#3418)
Separate the corner-cutting code for `rehash' into a dedicated branch. Saves some more time (about 100ms for the large fixture)
This commit is contained in:
parent
d5fa1e225e
commit
8037f22665
@ -110,17 +110,6 @@ remove_outdated_shims() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# List basenames of executables for every Python version
|
|
||||||
list_executable_names() {
|
|
||||||
local version file
|
|
||||||
pyenv-versions --bare --skip-aliases | \
|
|
||||||
while read -r version; do
|
|
||||||
for file in "${PYENV_ROOT}/versions/${version}/bin/"*; do
|
|
||||||
echo "${file##*/}"
|
|
||||||
done
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# The basename of each argument passed to `make_shims` will be
|
# The basename of each argument passed to `make_shims` will be
|
||||||
# registered for installation as a shim. In this way, plugins may call
|
# registered for installation as a shim. In this way, plugins may call
|
||||||
# `make_shims` with a glob to register many shims at once.
|
# `make_shims` with a glob to register many shims at once.
|
||||||
@ -196,7 +185,7 @@ shopt -s nullglob
|
|||||||
create_prototype_shim
|
create_prototype_shim
|
||||||
remove_outdated_shims
|
remove_outdated_shims
|
||||||
# shellcheck disable=SC2046
|
# shellcheck disable=SC2046
|
||||||
make_shims $(list_executable_names)
|
make_shims $(pyenv-versions --executables)
|
||||||
|
|
||||||
|
|
||||||
# Allow plugins to register shims.
|
# Allow plugins to register shims.
|
||||||
|
|||||||
@ -1,13 +1,21 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Summary: List all Python versions available to pyenv
|
# Summary: List all Python versions available to pyenv
|
||||||
# Usage: pyenv versions [--bare] [--skip-aliases] [--skip-envs]
|
# Usage: pyenv versions [--bare] [--skip-aliases] [--skip-envs] [--executables]
|
||||||
#
|
#
|
||||||
# Lists all Python versions found in `$PYENV_ROOT/versions/*'.
|
# Lists all Python versions found in `$PYENV_ROOT/versions/*'.
|
||||||
|
#
|
||||||
|
# --bare List just the names, omit `system'
|
||||||
|
# --skip-aliases Skip symlinks to other versions and to virtual environments
|
||||||
|
# --skip-envs Skip virtual environments (under <version>/envs)
|
||||||
|
# --executables Internal. Overrides other options.
|
||||||
|
# Optimally get a deduplicated list of all executable names in Pyenv-managed
|
||||||
|
# versions and environments for `pyenv rehash'
|
||||||
|
#
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
[ -n "$PYENV_DEBUG" ] && set -x
|
[ -n "$PYENV_DEBUG" ] && set -x
|
||||||
|
|
||||||
unset bare skip_aliases skip_envs
|
unset bare skip_aliases skip_envs executables
|
||||||
# Provide pyenv completions
|
# Provide pyenv completions
|
||||||
for arg; do
|
for arg; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
@ -16,6 +24,7 @@ for arg; do
|
|||||||
echo --skip-aliases
|
echo --skip-aliases
|
||||||
echo --skip-envs
|
echo --skip-envs
|
||||||
exit ;;
|
exit ;;
|
||||||
|
--executables ) executables=1; break ;;
|
||||||
--bare ) bare=1 ;;
|
--bare ) bare=1 ;;
|
||||||
--skip-aliases ) skip_aliases=1 ;;
|
--skip-aliases ) skip_aliases=1 ;;
|
||||||
--skip-envs ) skip_envs=1 ;;
|
--skip-envs ) skip_envs=1 ;;
|
||||||
@ -26,31 +35,21 @@ for arg; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# Fast path for --bare --skip-aliases: skip sort and full realpath resolution
|
|
||||||
if [[ -n "$bare" && -n "$skip_aliases" ]]; then
|
versions_dir="${PYENV_ROOT}/versions"
|
||||||
versions_dir="${PYENV_ROOT}/versions"
|
|
||||||
|
# Fast path for rehash: skip filtering and link resolution
|
||||||
|
if [[ -n "$executables" ]]; then
|
||||||
if [ -d "$versions_dir" ]; then
|
if [ -d "$versions_dir" ]; then
|
||||||
shopt -s dotglob nullglob
|
shopt -s dotglob nullglob
|
||||||
for path in "$versions_dir"/*/; do
|
# MacOS 12+ and FreeBSD 15 support `xargs -r -0' and `basename -a'
|
||||||
path="${path%/}"
|
# `sort -u` is simpler and a bit faster than `awk '!seen[$0]++'`, with the same result for rehash purposes
|
||||||
if [ -L "$path" ]; then
|
printf '%s\0' "$versions_dir"/*/bin/* "$versions_dir"/*/envs/*/bin/* | xargs -0 -r basename -a | sort -u
|
||||||
# Relative link = internal alias → skip; absolute = external → keep
|
|
||||||
[[ "$(readlink "$path")" == /* ]] || continue
|
|
||||||
fi
|
|
||||||
echo "${path##*/}"
|
|
||||||
if [[ -z "$skip_envs" ]]; then
|
|
||||||
for env_path in "${path}/envs/"*; do
|
|
||||||
[ -d "$env_path" ] && echo "${env_path#${versions_dir}/}"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
shopt -u dotglob nullglob
|
shopt -u dotglob nullglob
|
||||||
fi
|
fi
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
versions_dir="${PYENV_ROOT}/versions"
|
|
||||||
|
|
||||||
if ! enable -f "${BASH_SOURCE%/*}"/pyenv-realpath.dylib realpath 2>/dev/null; then
|
if ! enable -f "${BASH_SOURCE%/*}"/pyenv-realpath.dylib realpath 2>/dev/null; then
|
||||||
if [ -n "$PYENV_NATIVE_EXT" ]; then
|
if [ -n "$PYENV_NATIVE_EXT" ]; then
|
||||||
echo "pyenv: failed to load \`realpath' builtin" >&2
|
echo "pyenv: failed to load \`realpath' builtin" >&2
|
||||||
|
|||||||
@ -135,7 +135,7 @@ path_without() {
|
|||||||
if [ "$found" != "${PYENV_ROOT}/shims" ]; then
|
if [ "$found" != "${PYENV_ROOT}/shims" ]; then
|
||||||
alt="${PYENV_TEST_DIR}/$(echo "${found#/}" | tr '/' '-')"
|
alt="${PYENV_TEST_DIR}/$(echo "${found#/}" | tr '/' '-')"
|
||||||
mkdir -p "$alt"
|
mkdir -p "$alt"
|
||||||
for util in bash head cut readlink greadlink tr sed; do
|
for util in bash head cut readlink greadlink tr sed xargs basename sort; do
|
||||||
if [ -x "${found}/$util" ]; then
|
if [ -x "${found}/$util" ]; then
|
||||||
ln -s "${found}/$util" "${alt}/$util"
|
ln -s "${found}/$util" "${alt}/$util"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -11,6 +11,11 @@ create_alias() {
|
|||||||
ln -s "$2" "${PYENV_ROOT}/versions/$1"
|
ln -s "$2" "${PYENV_ROOT}/versions/$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create_external_version() {
|
||||||
|
mkdir -p "$PYENV_TEST_DIR/${1:?}"
|
||||||
|
create_alias "${1:?}" "$PYENV_TEST_DIR/${1:?}"
|
||||||
|
}
|
||||||
|
|
||||||
_setup() {
|
_setup() {
|
||||||
mkdir -p "$PYENV_TEST_DIR"
|
mkdir -p "$PYENV_TEST_DIR"
|
||||||
cd "$PYENV_TEST_DIR"
|
cd "$PYENV_TEST_DIR"
|
||||||
@ -168,15 +173,39 @@ OUT
|
|||||||
@test "doesn't list symlink aliases when --skip-aliases" {
|
@test "doesn't list symlink aliases when --skip-aliases" {
|
||||||
create_version "1.8.7"
|
create_version "1.8.7"
|
||||||
create_alias "1.8" "1.8.7"
|
create_alias "1.8" "1.8.7"
|
||||||
mkdir moo
|
create_external_version "moo"
|
||||||
create_alias "1.9" "${PWD}/moo"
|
|
||||||
|
|
||||||
run pyenv-versions --bare --skip-aliases
|
run pyenv-versions --bare --skip-aliases
|
||||||
assert_success
|
assert_success
|
||||||
|
|
||||||
assert_output <<OUT
|
assert_output <<OUT
|
||||||
1.8.7
|
1.8.7
|
||||||
1.9
|
moo
|
||||||
|
OUT
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "--executables lists executables everywhere and overrides other switches" {
|
||||||
|
create_alt_executable_in_version "3.5.0" "python"
|
||||||
|
create_alt_executable_in_version "3.5.0" "python1"
|
||||||
|
create_alt_executable_in_version "3.6.0" "python"
|
||||||
|
create_alt_executable_in_version "3.5.0/envs/foo" "python_foo"
|
||||||
|
create_alt_executable_in_version "3.6.0/envs/bar" "python_bar"
|
||||||
|
create_alias "bar" "3.6.0/envs/bar"
|
||||||
|
create_external_version "moo"
|
||||||
|
create_alt_executable_in_version "moo" "moopython"
|
||||||
|
|
||||||
|
run pyenv-versions --skip-aliases --skip-envs --executables
|
||||||
|
assert_success
|
||||||
|
#The sort order does not matter for this functionality. However,
|
||||||
|
#MacOS 15 `sort` sorts differently that Linux's due to a different LC_COLLATE definition for en-US:
|
||||||
|
#https://unix.stackexchange.com/questions/362728/why-does-gnu-sort-sort-differently-on-my-osx-machine-and-linux-machine
|
||||||
|
#So to get a match, we have to check against the same order that the local `sort` produces
|
||||||
|
sort <<OUT | assert_output
|
||||||
|
moopython
|
||||||
|
python
|
||||||
|
python1
|
||||||
|
python_bar
|
||||||
|
python_foo
|
||||||
OUT
|
OUT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user