diff --git a/plugins/python-build/bin/pyenv-install b/plugins/python-build/bin/pyenv-install index 22b211a8a9..6453564986 100755 --- a/plugins/python-build/bin/pyenv-install +++ b/plugins/python-build/bin/pyenv-install @@ -120,8 +120,8 @@ unset VERSION_NAME # version is specified by pyenv. Show usage instructions if a local # version is not specified. DEFINITIONS=("${ARGUMENTS[@]}") -[ -n "${DEFINITIONS[*]}" ] || DEFINITIONS=($(pyenv-local 2>/dev/null || true)) -[ -n "${DEFINITIONS[*]}" ] || usage 1 >&2 +[[ "${#DEFINITIONS[*]}" -eq 0 ]] && DEFINITIONS=($(pyenv-local 2>/dev/null || true)) +[[ "${#DEFINITIONS[*]}" -eq 0 ]] && usage 1 >&2 # Define `before_install` and `after_install` functions that allow # plugin hooks to register a string of code for execution before or @@ -151,7 +151,10 @@ IFS=$'\n' scripts=(`pyenv-hooks install`) IFS="$OLDIFS" for script in "${scripts[@]}"; do source "$script"; done -for DEFINITION in "${DEFINITIONS[@]}";do +COMBINED_STATUS=0 +for DEFINITION in "${DEFINITIONS[@]}"; do + STATUS=0 + # Try to resolve a prefix if user indeed gave a prefix. # We install the version under the resolved name # and hooks also see the resolved name @@ -173,7 +176,7 @@ for DEFINITION in "${DEFINITIONS[@]}";do case "$REPLY" in y | Y | yes | YES ) ;; - * ) exit 1 ;; + * ) { STATUS=1; [[ $STATUS -gt $COMBINED_STATUS ]] && COMBINED_STATUS=$STATUS; }; continue ;; esac elif [ -n "$SKIP_EXISTING" ]; then # Since we know the python version is already installed, and are opting to @@ -247,8 +250,8 @@ for DEFINITION in "${DEFINITIONS[@]}";do for hook in "${before_hooks[@]}"; do eval "$hook"; done # Invoke `python-build` and record the exit status in $STATUS. - STATUS=0 - python-build $KEEP $VERBOSE $HAS_PATCH $DEBUG "$DEFINITION" "$PREFIX" || STATUS="$?" + python-build $KEEP $VERBOSE $HAS_PATCH $DEBUG "$DEFINITION" "$PREFIX" || \ + { STATUS=$?; [[ $STATUS -gt $COMBINED_STATUS ]] && COMBINED_STATUS=$STATUS; } # Display a more helpful message if the definition wasn't found. if [ "$STATUS" == "2" ]; then @@ -279,13 +282,14 @@ for DEFINITION in "${DEFINITIONS[@]}";do for hook in "${after_hooks[@]}"; do eval "$hook"; done # Run `pyenv-rehash` after a successful installation. - if [ "$STATUS" == "0" ]; then + if [[ $STATUS -eq 0 ]]; then pyenv-rehash else - break cleanup + break fi done -exit "${STATUS:-0}" + +exit "${COMBINED_STATUS}" diff --git a/plugins/python-build/test/pyenv.bats b/plugins/python-build/test/pyenv.bats index 5eae5b2c65..1ca8270636 100644 --- a/plugins/python-build/test/pyenv.bats +++ b/plugins/python-build/test/pyenv.bats @@ -5,31 +5,36 @@ export PYENV_ROOT="${TMP}/pyenv" setup() { stub pyenv-hooks 'install : true' - stub pyenv-rehash 'true' + stub pyenv-rehash true } -stub_python_build() { +stub_python_build_lib() { stub python-build "--lib : $BATS_TEST_DIRNAME/../bin/python-build --lib" "$@" - stub pyenv-latest ": false" } -@test "install proper" { - stub_python_build 'echo python-build "$@"' +stub_python_build_no_latest() { + stub python-build "${@:-echo python-build \"\$@\"}" +} + +stub_python_build() { + stub_python_build_no_latest "$@" + stub pyenv-latest false +} + +@test "install a single version" { + stub_python_build_lib + stub_python_build run pyenv-install 3.4.2 assert_success "python-build 3.4.2 ${PYENV_ROOT}/versions/3.4.2" unstub python-build - unstub pyenv-hooks - unstub pyenv-rehash } -@test "install proper multi versions" { - #stub python-build "--lib : $BATS_TEST_DIRNAME/../bin/python-build --lib" 'echo python-build "$@"' 'echo python-build "$@"' - #stub pyenv-latest ": false" ": false" - stub_python_build 'echo python-build "$@"' 'echo python-build "$@"' - stub pyenv-latest ": false" - stub pyenv-rehash 'true' +@test "install multiple versions" { + stub_python_build_lib + stub_python_build + stub_python_build run pyenv-install 3.4.1 3.4.2 assert_success @@ -40,61 +45,72 @@ OUT unstub python-build unstub pyenv-latest - unstub pyenv-hooks - unstub pyenv-rehash } -@test "install resolves a prefix" { - stub_python_build 'echo python-build "$@"' - stub pyenv-latest '-q -k 3.4 : echo 3.4.2' - pyenv-latest || true # pass through the stub entry added by stub_python_build +@test "install multiple versions, some fail" { + stub_python_build_lib + stub_python_build 'echo "fail: python-build" "$@"; false' - run pyenv-install 3.4 - assert_success "python-build 3.4.2 ${PYENV_ROOT}/versions/3.4.2" + run pyenv-install 3.4.1 3.4.2 + assert_failure + assert_output <&2 && exit 2' \ - "--definitions : echo 2.6.9 2.7.9-rc1 2.7.9-rc2 3.4.2 | tr ' ' $'\\n'" + stub_python_build_lib + stub_python_build 'echo ERROR >&2 && exit 2' + stub_python_build "--definitions : echo 2.6.9 2.7.9-rc1 2.7.9-rc2 3.4.2 | tr ' ' $'\\n'" run pyenv-install 2.7.9 assert_failure @@ -142,8 +159,9 @@ OUT unstub python-build } -@test "Homebrew upgrade instructions" { +@test "homebrew upgrade instructions given when pyenv is homebrew-installed" { stub brew "--prefix : echo '${BATS_TEST_DIRNAME%/*}'" + stub_python_build_lib stub_python_build 'echo ERROR >&2 && exit 2' \ "--definitions : true" @@ -165,15 +183,19 @@ OUT @test "no build definitions from plugins" { assert [ ! -e "${PYENV_ROOT}/plugins" ] + stub_python_build_lib stub_python_build 'echo $PYTHON_BUILD_DEFINITIONS' run pyenv-install 3.4.2 assert_success "" + + unstub python-build } @test "some build definitions from plugins" { mkdir -p "${PYENV_ROOT}/plugins/foo/share/python-build" mkdir -p "${PYENV_ROOT}/plugins/bar/share/python-build" + stub_python_build_lib stub_python_build "echo \$PYTHON_BUILD_DEFINITIONS | tr ':' $'\\n'" run pyenv-install 3.4.2 @@ -183,11 +205,14 @@ OUT ${PYENV_ROOT}/plugins/bar/share/python-build ${PYENV_ROOT}/plugins/foo/share/python-build OUT + + unstub python-build } @test "list build definitions from plugins" { mkdir -p "${PYENV_ROOT}/plugins/foo/share/python-build" mkdir -p "${PYENV_ROOT}/plugins/bar/share/python-build" + stub_python_build_lib stub_python_build "--definitions : echo \$PYTHON_BUILD_DEFINITIONS | tr ':' $'\\n'" run pyenv-install --list @@ -198,12 +223,14 @@ Available versions: ${PYENV_ROOT}/plugins/bar/share/python-build ${PYENV_ROOT}/plugins/foo/share/python-build OUT + + unstub python-build } @test "completion results include build definitions from plugins" { mkdir -p "${PYENV_ROOT}/plugins/foo/share/python-build" mkdir -p "${PYENV_ROOT}/plugins/bar/share/python-build" - stub python-build "--definitions : echo \$PYTHON_BUILD_DEFINITIONS | tr ':' $'\\n'" + stub_python_build "--definitions : echo \$PYTHON_BUILD_DEFINITIONS | tr ':' $'\\n'" run pyenv-install --complete assert_success @@ -220,10 +247,12 @@ OUT ${PYENV_ROOT}/plugins/bar/share/python-build ${PYENV_ROOT}/plugins/foo/share/python-build OUT + + unstub python-build } @test "not enough arguments for pyenv-install if no local version" { - stub_python_build + stub_python_build_lib stub pyenv-help 'install : true' run pyenv-install @@ -232,17 +261,7 @@ OUT assert_output "" } -@test "multi arguments for pyenv-install" { - stub_python_build - stub pyenv-help 'install : true' - - run pyenv-install 3.4.1 3.4.2 - assert_success - assert_output "" -} - @test "show help for pyenv-install" { - stub_python_build stub pyenv-help 'install : true' run pyenv-install -h @@ -263,7 +282,7 @@ OUT unstub pyenv-help } -@test "more than one argument for pyenv-uninstall" { +@test "multiple arguments for pyenv-uninstall" { mkdir -p "${PYENV_ROOT}/versions/3.4.1" mkdir -p "${PYENV_ROOT}/versions/3.4.2" run pyenv-uninstall -f 3.4.1 3.4.2 diff --git a/pyenv.d/install/latest.bash b/pyenv.d/install/latest.bash index 6f45a50dd5..790b2dd10f 100644 --- a/pyenv.d/install/latest.bash +++ b/pyenv.d/install/latest.bash @@ -1,13 +1,25 @@ -DEFINITION_PREFIX="${DEFINITION%%:*}" -DEFINITION_TYPE="${DEFINITION_PREFIX%%-*}" # TODO: support non-CPython versions -if [[ "${DEFINITION}" != "${DEFINITION_PREFIX}" ]]; then - DEFINITION_CANDIDATES=(\ - $(python-build --definitions | \ - grep -F "${DEFINITION_PREFIX}" | \ - grep "^${DEFINITION_TYPE}" | \ - sed -E -e '/-dev$/d' -e '/-src$/d' -e '/(b|rc)[0-9]+$/d' | \ - sort -t. -k1,1r -k 2,2nr -k 3,3nr \ - || true)) - DEFINITION="${DEFINITION_CANDIDATES}" - VERSION_NAME="${DEFINITION##*/}" -fi +pyenv_install_resolve_latest() { + local DEFINITION_PREFIX DEFINITION_TYPE + local -a DEFINITION_CANDIDATES + local DEFINITION="$1" + + DEFINITION_PREFIX="${DEFINITION%%:*}" + DEFINITION_TYPE="${DEFINITION_PREFIX%%-*}" # TODO: support non-CPython versions + if [[ "${DEFINITION}" != "${DEFINITION_PREFIX}" ]]; then + DEFINITION_CANDIDATES=(\ + $(python-build --definitions | \ + grep -F "${DEFINITION_PREFIX}" | \ + grep "^${DEFINITION_TYPE}" | \ + sed -E -e '/-dev$/d' -e '/-src$/d' -e '/(b|rc)[0-9]+$/d' | \ + sort -t. -k1,1r -k 2,2nr -k 3,3nr \ + || true)) + DEFINITION="${DEFINITION_CANDIDATES}" + fi + echo "$DEFINITION" +} + +for i in ${!DEFINITIONS[*]}; do + DEFINITIONS[$i]="$(pyenv_install_resolve_latest "${DEFINITIONS[$i]}")" +done + +unset pyenv_install_resolve_latest