Support missing versions being present and set in a local .python-version (#3134)
Requested in https://github.com/pyenv/pyenv/issues/2680 for deployments with a stock `.pyenv-version` that can use any of a number of Python versions and for compatibility with `uv`. * Support `pyenv local --force` * Support `pyenv-version-file-write --force` * Support `pyenv version-name --force` * Ignore missing versions when searching for executables * Display "commmand not found" even when there are nonexistent versions * exec.bats: replace `python` and `rspec` with something that doesn't exist globally, either in Ubuntu Github CI, `python` exists globally
This commit is contained in:
parent
aef6a2a6d0
commit
dc873cf568
@ -91,6 +91,10 @@ or, if you prefer 3.3.3 over 2.7.6,
|
|||||||
Python 3.3.3
|
Python 3.3.3
|
||||||
|
|
||||||
|
|
||||||
|
You can use the `-f/--force` flag to force setting versions even if some aren't installed.
|
||||||
|
This is mainly useful in special cases like provisioning scripts.
|
||||||
|
|
||||||
|
|
||||||
## `pyenv global`
|
## `pyenv global`
|
||||||
|
|
||||||
Sets the global version of Python to be used in all shells by writing
|
Sets the global version of Python to be used in all shells by writing
|
||||||
|
@ -21,7 +21,7 @@ if [ "$1" = "--complete" ]; then
|
|||||||
exec pyenv-shims --short
|
exec pyenv-shims --short
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PYENV_VERSION="$(pyenv-version-name)"
|
PYENV_VERSION="$(pyenv-version-name -f)"
|
||||||
PYENV_COMMAND="$1"
|
PYENV_COMMAND="$1"
|
||||||
|
|
||||||
if [ -z "$PYENV_COMMAND" ]; then
|
if [ -z "$PYENV_COMMAND" ]; then
|
||||||
@ -29,9 +29,9 @@ if [ -z "$PYENV_COMMAND" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export PYENV_VERSION
|
|
||||||
PYENV_COMMAND_PATH="$(pyenv-which "$PYENV_COMMAND")"
|
PYENV_COMMAND_PATH="$(pyenv-which "$PYENV_COMMAND")"
|
||||||
PYENV_BIN_PATH="${PYENV_COMMAND_PATH%/*}"
|
PYENV_BIN_PATH="${PYENV_COMMAND_PATH%/*}"
|
||||||
|
export PYENV_VERSION
|
||||||
|
|
||||||
OLDIFS="$IFS"
|
OLDIFS="$IFS"
|
||||||
IFS=$'\n' scripts=(`pyenv-hooks exec`)
|
IFS=$'\n' scripts=(`pyenv-hooks exec`)
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
#
|
#
|
||||||
# Summary: Set or show the local application-specific Python version(s)
|
# Summary: Set or show the local application-specific Python version(s)
|
||||||
#
|
#
|
||||||
# Usage: pyenv local <version> <version2> <..>
|
# Usage: pyenv local [-f|--force] [<version> [...]]
|
||||||
# pyenv local --unset
|
# pyenv local --unset
|
||||||
#
|
#
|
||||||
|
# -f/--force Do not verify that the versions being set exist
|
||||||
|
#
|
||||||
# Sets the local application-specific Python version(s) by writing the
|
# Sets the local application-specific Python version(s) by writing the
|
||||||
# version name to a file named `.python-version'.
|
# version name to a file named `.python-version'.
|
||||||
#
|
#
|
||||||
@ -36,12 +38,25 @@ if [ "$1" = "--complete" ]; then
|
|||||||
exec pyenv-versions --bare
|
exec pyenv-versions --bare
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]
|
||||||
|
do
|
||||||
|
case "$1" in
|
||||||
|
-f|--force)
|
||||||
|
FORCE=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
versions=("$@")
|
versions=("$@")
|
||||||
|
|
||||||
if [ "$versions" = "--unset" ]; then
|
if [ "$versions" = "--unset" ]; then
|
||||||
rm -f .python-version
|
rm -f .python-version
|
||||||
elif [ -n "$versions" ]; then
|
elif [ -n "$versions" ]; then
|
||||||
pyenv-version-file-write .python-version "${versions[@]}"
|
pyenv-version-file-write ${FORCE:+-f }.python-version "${versions[@]}"
|
||||||
else
|
else
|
||||||
if version_file="$(pyenv-version-file "$PWD")"; then
|
if version_file="$(pyenv-version-file "$PWD")"; then
|
||||||
IFS=: versions=($(pyenv-version-file-read "$version_file"))
|
IFS=: versions=($(pyenv-version-file-read "$version_file"))
|
||||||
|
@ -1,9 +1,25 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Usage: pyenv version-file-write <file> <version>
|
# Usage: pyenv version-file-write [-f|--force] <file> <version> [...]
|
||||||
|
#
|
||||||
|
# -f/--force Don't verify that the versions exist
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
[ -n "$PYENV_DEBUG" ] && set -x
|
[ -n "$PYENV_DEBUG" ] && set -x
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]
|
||||||
|
do
|
||||||
|
case "$1" in
|
||||||
|
-f|--force)
|
||||||
|
FORCE=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
PYENV_VERSION_FILE="$1"
|
PYENV_VERSION_FILE="$1"
|
||||||
shift || true
|
shift || true
|
||||||
versions=("$@")
|
versions=("$@")
|
||||||
@ -14,7 +30,7 @@ if [ -z "$versions" ] || [ -z "$PYENV_VERSION_FILE" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Make sure the specified version is installed.
|
# Make sure the specified version is installed.
|
||||||
pyenv-prefix "${versions[@]}" >/dev/null
|
[[ -z $FORCE ]] && pyenv-prefix "${versions[@]}" >/dev/null
|
||||||
|
|
||||||
# Write the version out to disk.
|
# Write the version out to disk.
|
||||||
# Create an empty file. Using "rm" might cause a permission error.
|
# Create an empty file. Using "rm" might cause a permission error.
|
||||||
|
@ -1,8 +1,25 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Summary: Show the current Python version
|
# Summary: Show the current Python version
|
||||||
|
#
|
||||||
|
# -f/--force (Internal) If a version doesn't exist, print it as is rather than produce an error
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
[ -n "$PYENV_DEBUG" ] && set -x
|
[ -n "$PYENV_DEBUG" ] && set -x
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]
|
||||||
|
do
|
||||||
|
case "$1" in
|
||||||
|
-f|--force)
|
||||||
|
FORCE=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
if [ -z "$PYENV_VERSION" ]; then
|
if [ -z "$PYENV_VERSION" ]; then
|
||||||
PYENV_VERSION_FILE="$(pyenv-version-file)"
|
PYENV_VERSION_FILE="$(pyenv-version-file)"
|
||||||
PYENV_VERSION="$(pyenv-version-file-read "$PYENV_VERSION_FILE" || true)"
|
PYENV_VERSION="$(pyenv-version-file-read "$PYENV_VERSION_FILE" || true)"
|
||||||
@ -33,16 +50,20 @@ OLDIFS="$IFS"
|
|||||||
# Remove the explicit 'python-' prefix from versions like 'python-3.12'.
|
# Remove the explicit 'python-' prefix from versions like 'python-3.12'.
|
||||||
normalised_version="${version#python-}"
|
normalised_version="${version#python-}"
|
||||||
if version_exists "${version}" || [ "$version" = "system" ]; then
|
if version_exists "${version}" || [ "$version" = "system" ]; then
|
||||||
versions=("${versions[@]}" "${version}")
|
versions+=("${version}")
|
||||||
elif version_exists "${normalised_version}"; then
|
elif version_exists "${normalised_version}"; then
|
||||||
versions=("${versions[@]}" "${normalised_version}")
|
versions+=("${normalised_version}")
|
||||||
elif resolved_version="$(pyenv-latest -b "${version}")"; then
|
elif resolved_version="$(pyenv-latest -b "${version}")"; then
|
||||||
versions=("${versions[@]}" "${resolved_version}")
|
versions+=("${resolved_version}")
|
||||||
elif resolved_version="$(pyenv-latest -b "${normalised_version}")"; then
|
elif resolved_version="$(pyenv-latest -b "${normalised_version}")"; then
|
||||||
versions=("${versions[@]}" "${resolved_version}")
|
versions+=("${resolved_version}")
|
||||||
else
|
else
|
||||||
echo "pyenv: version \`$version' is not installed (set by $(pyenv-version-origin))" >&2
|
if [[ -n $FORCE ]]; then
|
||||||
any_not_installed=1
|
versions+=("${normalised_version}")
|
||||||
|
else
|
||||||
|
echo "pyenv: version \`$version' is not installed (set by $(pyenv-version-origin))" >&2
|
||||||
|
any_not_installed=1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,6 @@ else
|
|||||||
for version in "${nonexistent_versions[@]}"; do
|
for version in "${nonexistent_versions[@]}"; do
|
||||||
echo "pyenv: version \`$version' is not installed (set by $(pyenv-version-origin))" >&2
|
echo "pyenv: version \`$version' is not installed (set by $(pyenv-version-origin))" >&2
|
||||||
done
|
done
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "pyenv: $PYENV_COMMAND: command not found" >&2
|
echo "pyenv: $PYENV_COMMAND: command not found" >&2
|
||||||
|
@ -16,16 +16,22 @@ create_executable() {
|
|||||||
|
|
||||||
@test "fails with invalid version" {
|
@test "fails with invalid version" {
|
||||||
export PYENV_VERSION="3.4"
|
export PYENV_VERSION="3.4"
|
||||||
run pyenv-exec python -V
|
run pyenv-exec nonexistent
|
||||||
assert_failure "pyenv: version \`3.4' is not installed (set by PYENV_VERSION environment variable)"
|
assert_failure <<EOF
|
||||||
|
pyenv: version \`3.4' is not installed (set by PYENV_VERSION environment variable)
|
||||||
|
pyenv: nonexistent: command not found
|
||||||
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "fails with invalid version set from file" {
|
@test "fails with invalid version set from file" {
|
||||||
mkdir -p "$PYENV_TEST_DIR"
|
mkdir -p "$PYENV_TEST_DIR"
|
||||||
cd "$PYENV_TEST_DIR"
|
cd "$PYENV_TEST_DIR"
|
||||||
echo 2.7 > .python-version
|
echo 2.7 > .python-version
|
||||||
run pyenv-exec rspec
|
run pyenv-exec nonexistent
|
||||||
assert_failure "pyenv: version \`2.7' is not installed (set by $PWD/.python-version)"
|
assert_failure <<EOF
|
||||||
|
pyenv: version \`2.7' is not installed (set by $PWD/.python-version)
|
||||||
|
pyenv: nonexistent: command not found
|
||||||
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "completes with names of executables" {
|
@test "completes with names of executables" {
|
||||||
|
@ -41,6 +41,18 @@ setup() {
|
|||||||
assert [ "$(cat .python-version)" = "1.2.3" ]
|
assert [ "$(cat .python-version)" = "1.2.3" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "fails to set a nonexistent local version" {
|
||||||
|
run pyenv-local 1.2.3
|
||||||
|
assert_failure "pyenv: version \`1.2.3' not installed"
|
||||||
|
assert [ ! -e .python-version ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "sets a nonexistent local version with --force" {
|
||||||
|
run pyenv-local -f 1.2.3
|
||||||
|
assert_success ""
|
||||||
|
assert [ "$(cat .python-version)" = "1.2.3" ]
|
||||||
|
}
|
||||||
|
|
||||||
@test "changes local version" {
|
@test "changes local version" {
|
||||||
echo "1.0-pre" > .python-version
|
echo "1.0-pre" > .python-version
|
||||||
mkdir -p "${PYENV_ROOT}/versions/1.2.3"
|
mkdir -p "${PYENV_ROOT}/versions/1.2.3"
|
||||||
|
@ -9,7 +9,7 @@ setup() {
|
|||||||
|
|
||||||
@test "invocation without 2 arguments prints usage" {
|
@test "invocation without 2 arguments prints usage" {
|
||||||
run pyenv-version-file-write
|
run pyenv-version-file-write
|
||||||
assert_failure "Usage: pyenv version-file-write <file> <version>"
|
assert_failure "Usage: pyenv version-file-write [-f|--force] <file> <version> [...]"
|
||||||
run pyenv-version-file-write "one" ""
|
run pyenv-version-file-write "one" ""
|
||||||
assert_failure
|
assert_failure
|
||||||
}
|
}
|
||||||
@ -21,6 +21,13 @@ setup() {
|
|||||||
assert [ ! -e ".python-version" ]
|
assert [ ! -e ".python-version" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "setting nonexistent version succeeds with force" {
|
||||||
|
assert [ ! -e ".python-version" ]
|
||||||
|
run pyenv-version-file-write --force ".python-version" "2.7.6"
|
||||||
|
assert_success
|
||||||
|
assert [ -e ".python-version" ]
|
||||||
|
}
|
||||||
|
|
||||||
@test "writes value to arbitrary file" {
|
@test "writes value to arbitrary file" {
|
||||||
mkdir -p "${PYENV_ROOT}/versions/2.7.6"
|
mkdir -p "${PYENV_ROOT}/versions/2.7.6"
|
||||||
assert [ ! -e "my-version" ]
|
assert [ ! -e "my-version" ]
|
||||||
|
@ -73,6 +73,11 @@ SH
|
|||||||
assert_failure "pyenv: version \`1.2' is not installed (set by PYENV_VERSION environment variable)"
|
assert_failure "pyenv: version \`1.2' is not installed (set by PYENV_VERSION environment variable)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "missing version with --force" {
|
||||||
|
PYENV_VERSION=1.2 run pyenv-version-name -f
|
||||||
|
assert_success "1.2"
|
||||||
|
}
|
||||||
|
|
||||||
@test "one missing version (second missing)" {
|
@test "one missing version (second missing)" {
|
||||||
create_version "3.5.1"
|
create_version "3.5.1"
|
||||||
PYENV_VERSION="3.5.1:1.2" run pyenv-version-name
|
PYENV_VERSION="3.5.1:1.2" run pyenv-version-name
|
||||||
|
@ -71,7 +71,16 @@ create_executable() {
|
|||||||
@test "version not installed" {
|
@test "version not installed" {
|
||||||
create_executable "3.4" "py.test"
|
create_executable "3.4" "py.test"
|
||||||
PYENV_VERSION=3.3 run pyenv-which py.test
|
PYENV_VERSION=3.3 run pyenv-which py.test
|
||||||
assert_failure "pyenv: version \`3.3' is not installed (set by PYENV_VERSION environment variable)"
|
assert_failure <<OUT
|
||||||
|
pyenv: version \`3.3' is not installed (set by PYENV_VERSION environment variable)
|
||||||
|
pyenv: py.test: command not found
|
||||||
|
|
||||||
|
The \`py.test' command exists in these Python versions:
|
||||||
|
3.4
|
||||||
|
|
||||||
|
Note: See 'pyenv help global' for tips on allowing both
|
||||||
|
python2 and python3 to be found.
|
||||||
|
OUT
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "versions not installed" {
|
@test "versions not installed" {
|
||||||
@ -80,6 +89,13 @@ create_executable() {
|
|||||||
assert_failure <<OUT
|
assert_failure <<OUT
|
||||||
pyenv: version \`2.7' is not installed (set by PYENV_VERSION environment variable)
|
pyenv: version \`2.7' is not installed (set by PYENV_VERSION environment variable)
|
||||||
pyenv: version \`3.3' is not installed (set by PYENV_VERSION environment variable)
|
pyenv: version \`3.3' is not installed (set by PYENV_VERSION environment variable)
|
||||||
|
pyenv: py.test: command not found
|
||||||
|
|
||||||
|
The \`py.test' command exists in these Python versions:
|
||||||
|
3.4
|
||||||
|
|
||||||
|
Note: See 'pyenv help global' for tips on allowing both
|
||||||
|
python2 and python3 to be found.
|
||||||
OUT
|
OUT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user