init: don't silence automatic rehash; rehash: report final error but not provisional ones (#3377)

This commit is contained in:
native-api 2025-12-21 07:21:30 +03:00 committed by GitHub
parent a944da76c0
commit aa6c9b9694
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 27 additions and 17 deletions

View File

@ -287,10 +287,10 @@ function print_rehash() {
if [ -z "$no_rehash" ]; then if [ -z "$no_rehash" ]; then
case "$shell" in case "$shell" in
pwsh ) pwsh )
echo '& pyenv rehash 2>/dev/null' echo '& pyenv rehash'
;; ;;
* ) * )
echo 'command pyenv rehash 2>/dev/null' echo 'command pyenv rehash'
;; ;;
esac esac
fi fi

View File

@ -10,6 +10,8 @@ PROTOTYPE_SHIM_PATH="${SHIM_PATH}/.pyenv-shim"
# Create the shims directory if it doesn't already exist. # Create the shims directory if it doesn't already exist.
mkdir -p "$SHIM_PATH" mkdir -p "$SHIM_PATH"
declare last_acquire_error
acquire_lock() { acquire_lock() {
# Ensure only one instance of pyenv-rehash is running at a time by # Ensure only one instance of pyenv-rehash is running at a time by
# setting the shell's `noclobber` option and attempting to write to # setting the shell's `noclobber` option and attempting to write to
@ -17,15 +19,11 @@ acquire_lock() {
# to stderr and exit with a non-zero status. # to stderr and exit with a non-zero status.
local ret local ret
set -o noclobber set -o noclobber
echo > "$PROTOTYPE_SHIM_PATH" 2>| /dev/null || ret=1 last_acquire_error="$( { ( echo -n > "$PROTOTYPE_SHIM_PATH"; ) 2>&1 1>&3 3>&1-; } 3>&1)" || ret=1
set +o noclobber set +o noclobber
[ -z "${ret}" ] [ -z "${ret}" ]
} }
# If we were able to obtain a lock, register a trap to clean up the
# prototype shim when the process exits.
trap release_lock EXIT
remove_prototype_shim() { remove_prototype_shim() {
rm -f "$PROTOTYPE_SHIM_PATH" rm -f "$PROTOTYPE_SHIM_PATH"
} }
@ -39,11 +37,17 @@ if [ ! -w "$SHIM_PATH" ]; then
exit 1 exit 1
fi fi
unset acquired declare acquired tested_for_other_write_errors
start=$SECONDS declare start=$SECONDS
while (( SECONDS <= start + ${PYENV_REHASH_TIMEOUT:-60} )); do PYENV_REHASH_TIMEOUT=${PYENV_REHASH_TIMEOUT:-60}
if acquire_lock 2>/dev/null; then while (( SECONDS <= start + PYENV_REHASH_TIMEOUT )); do
if acquire_lock; then
acquired=1 acquired=1
# If we were able to obtain a lock, register a trap to clean up the
# prototype shim when the process exits.
trap release_lock EXIT
break break
else else
#Landlock sandbox subsystem in the Linux kernel returns false information in access() as of 6.14.0, #Landlock sandbox subsystem in the Linux kernel returns false information in access() as of 6.14.0,
@ -53,7 +57,7 @@ while (( SECONDS <= start + ${PYENV_REHASH_TIMEOUT:-60} )); do
# in a way that taxes the usual use case as little as possible. # in a way that taxes the usual use case as little as possible.
if [[ -z $tested_for_other_write_errors ]]; then if [[ -z $tested_for_other_write_errors ]]; then
( t="$(TMPDIR="$SHIM_PATH" mktemp)" && rm "$t" ) && tested_for_other_write_errors=1 || ( t="$(TMPDIR="$SHIM_PATH" mktemp)" && rm "$t" ) && tested_for_other_write_errors=1 ||
{ echo "pyenv: cannot rehash: $SHIM_PATH isnt writable" >&2; break; } { echo "pyenv: cannot rehash: $SHIM_PATH isn't writable" >&2; break; }
fi fi
# POSIX sleep(1) doesn't provide subsecond precision, but many others do # POSIX sleep(1) doesn't provide subsecond precision, but many others do
sleep 0.1 2>/dev/null || sleep 1 sleep 0.1 2>/dev/null || sleep 1
@ -62,7 +66,9 @@ done
if [ -z "${acquired}" ]; then if [ -z "${acquired}" ]; then
if [[ -n $tested_for_other_write_errors ]]; then if [[ -n $tested_for_other_write_errors ]]; then
echo "pyenv: cannot rehash: $PROTOTYPE_SHIM_PATH exists" >&2 echo "pyenv: cannot rehash: couldn't acquire lock"\
"$PROTOTYPE_SHIM_PATH for $PYENV_REHASH_TIMEOUT seconds. Last error message:" >&2
echo "$last_acquire_error" >&2
fi fi
exit 1 exit 1
fi fi

View File

@ -14,13 +14,13 @@ load test_helper
@test "auto rehash" { @test "auto rehash" {
run pyenv-init - run pyenv-init -
assert_success assert_success
assert_line "command pyenv rehash 2>/dev/null" assert_line "command pyenv rehash"
} }
@test "auto rehash for --path" { @test "auto rehash for --path" {
run pyenv-init --path run pyenv-init --path
assert_success assert_success
assert_line "command pyenv rehash 2>/dev/null" assert_line "command pyenv rehash"
} }
@test "setup shell completions" { @test "setup shell completions" {

View File

@ -21,8 +21,12 @@ load test_helper
export PYENV_REHASH_TIMEOUT=1 export PYENV_REHASH_TIMEOUT=1
mkdir -p "${PYENV_ROOT}/shims" mkdir -p "${PYENV_ROOT}/shims"
touch "${PYENV_ROOT}/shims/.pyenv-shim" touch "${PYENV_ROOT}/shims/.pyenv-shim"
run pyenv-rehash #avoid failure due to a localized error message
assert_failure "pyenv: cannot rehash: ${PYENV_ROOT}/shims/.pyenv-shim exists" LANG=C run pyenv-rehash
assert_failure <<!
pyenv: cannot rehash: couldn't acquire lock ${PYENV_ROOT}/shims/.pyenv-shim for 1 seconds. Last error message:
*/pyenv-rehash: line *: ${PYENV_ROOT}/shims/.pyenv-shim: cannot overwrite existing file
!
} }
@test "wait until lock acquisition" { @test "wait until lock acquisition" {