From aa6c9b9694b2c2ce69d06ab68c46da52d32d9d34 Mon Sep 17 00:00:00 2001 From: native-api Date: Sun, 21 Dec 2025 07:21:30 +0300 Subject: [PATCH] init: don't silence automatic rehash; rehash: report final error but not provisional ones (#3377) --- libexec/pyenv-init | 4 ++-- libexec/pyenv-rehash | 28 +++++++++++++++++----------- test/init.bats | 4 ++-- test/rehash.bats | 8 ++++++-- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/libexec/pyenv-init b/libexec/pyenv-init index 757a443f..293f9881 100755 --- a/libexec/pyenv-init +++ b/libexec/pyenv-init @@ -287,10 +287,10 @@ function print_rehash() { if [ -z "$no_rehash" ]; then case "$shell" in pwsh ) - echo '& pyenv rehash 2>/dev/null' + echo '& pyenv rehash' ;; * ) - echo 'command pyenv rehash 2>/dev/null' + echo 'command pyenv rehash' ;; esac fi diff --git a/libexec/pyenv-rehash b/libexec/pyenv-rehash index 3dc7c291..7ef7bf20 100755 --- a/libexec/pyenv-rehash +++ b/libexec/pyenv-rehash @@ -10,6 +10,8 @@ PROTOTYPE_SHIM_PATH="${SHIM_PATH}/.pyenv-shim" # Create the shims directory if it doesn't already exist. mkdir -p "$SHIM_PATH" +declare last_acquire_error + acquire_lock() { # Ensure only one instance of pyenv-rehash is running at a time by # 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. local ret 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 [ -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() { rm -f "$PROTOTYPE_SHIM_PATH" } @@ -39,11 +37,17 @@ if [ ! -w "$SHIM_PATH" ]; then exit 1 fi -unset acquired -start=$SECONDS -while (( SECONDS <= start + ${PYENV_REHASH_TIMEOUT:-60} )); do - if acquire_lock 2>/dev/null; then +declare acquired tested_for_other_write_errors +declare start=$SECONDS +PYENV_REHASH_TIMEOUT=${PYENV_REHASH_TIMEOUT:-60} +while (( SECONDS <= start + PYENV_REHASH_TIMEOUT )); do + if acquire_lock; then 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 else #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. if [[ -z $tested_for_other_write_errors ]]; then ( 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 # POSIX sleep(1) doesn't provide subsecond precision, but many others do sleep 0.1 2>/dev/null || sleep 1 @@ -62,7 +66,9 @@ done if [ -z "${acquired}" ]; 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 exit 1 fi diff --git a/test/init.bats b/test/init.bats index 85ef01ec..746b176f 100755 --- a/test/init.bats +++ b/test/init.bats @@ -14,13 +14,13 @@ load test_helper @test "auto rehash" { run pyenv-init - assert_success - assert_line "command pyenv rehash 2>/dev/null" + assert_line "command pyenv rehash" } @test "auto rehash for --path" { run pyenv-init --path assert_success - assert_line "command pyenv rehash 2>/dev/null" + assert_line "command pyenv rehash" } @test "setup shell completions" { diff --git a/test/rehash.bats b/test/rehash.bats index c878a3da..e8edf675 100755 --- a/test/rehash.bats +++ b/test/rehash.bats @@ -21,8 +21,12 @@ load test_helper export PYENV_REHASH_TIMEOUT=1 mkdir -p "${PYENV_ROOT}/shims" touch "${PYENV_ROOT}/shims/.pyenv-shim" - run pyenv-rehash - assert_failure "pyenv: cannot rehash: ${PYENV_ROOT}/shims/.pyenv-shim exists" + #avoid failure due to a localized error message + LANG=C run pyenv-rehash + assert_failure <