Handle case where pyenv-commands --sh returns nothing

When running `eval "$(pyenv init -)"` to initialize `pyenv`, the command
generates a shell script to be executed. When not using the `fish`
shell, this script contains a `case` statement where the first case
matches against the output of `pyenv-commands --sh` and the second case
handles everything else. However, if no commands are returned, then the
matching expression will be only `)`, which is invalid Bash.

I have solved this (on the advice of @ native-api) by using the string
`/` if there are no commands to include. `/` is the only character in
Linux/POSIX besides `\0` that a filename cannot contain, so it is safe
to use as a pattern that will never match. To catch any regressions, I
have added a test to catch unexpected changes in the generated `case`
statement. I copied the `create_executable` function from `latest.bats`
because I needed to shim `pyenv-commands`.

I do not know if `pyenv-commands --sh` can ever return nothing under
normal conditions, but it happened to me due to completely unrelated
problems in underlying Unix utilities called by `pyenv`. Although this
bug will rarely occur, I feel that this increased robustness will be
useful.
This commit is contained in:
Alex Hedges 2024-02-25 15:02:41 -05:00
parent f9a2bb81b6
commit 54c51d8f87
2 changed files with 31 additions and 1 deletions

View File

@ -297,7 +297,7 @@ EOS
fi fi
case "\$command" in case "\$command" in
${commands[*]}) ${commands[*]:-/})
eval "\$(pyenv "sh-\$command" "\$@")" eval "\$(pyenv "sh-\$command" "\$@")"
;; ;;
*) *)

View File

@ -2,6 +2,18 @@
load test_helper load test_helper
setup() {
export PATH="${PYENV_TEST_DIR}/bin:$PATH"
}
create_executable() {
local name="$1"
local bin="${PYENV_TEST_DIR}/bin"
mkdir -p "$bin"
sed -Ee '1s/^ +//' > "${bin}/$name"
chmod +x "${bin}/$name"
}
@test "creates shims and versions directories" { @test "creates shims and versions directories" {
assert [ ! -d "${PYENV_ROOT}/shims" ] assert [ ! -d "${PYENV_ROOT}/shims" ]
assert [ ! -d "${PYENV_ROOT}/versions" ] assert [ ! -d "${PYENV_ROOT}/versions" ]
@ -167,6 +179,24 @@ echo "\$PATH"
assert_line ' case "$command" in' assert_line ' case "$command" in'
} }
@test "outputs sh-compatible case syntax" {
create_executable pyenv-commands <<!
#!$BASH
echo -e 'activate\ndeactivate\nrehash\nshell'
!
run pyenv-init - bash
assert_success
assert_line ' activate|deactivate|rehash|shell)'
create_executable pyenv-commands <<!
#!$BASH
echo
!
run pyenv-init - bash
assert_success
assert_line ' /)'
}
@test "outputs fish-specific syntax (fish)" { @test "outputs fish-specific syntax (fish)" {
run pyenv-init - fish run pyenv-init - fish
assert_success assert_success