mirror of
https://github.com/pyenv/pyenv.git
synced 2026-10-02 23:41:06 +09:00
Merge pull request #3516 from macayu17/fix/2334-package-feedback
pyenv-binary-package: check patchelf early and add --verbose
This commit is contained in:
commit
d92b6e1bbe
@ -16,7 +16,7 @@ and dependency metadata exist to catch that.
|
|||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
### `pyenv binary package <version>[:<entry>] --archive-base-url <url>`
|
### `pyenv binary package [-v|--verbose] <version>[:<entry>] --archive-base-url <url>`
|
||||||
|
|
||||||
Installs `<version>` from source under a separate name, packages that install
|
Installs `<version>` from source under a separate name, packages that install
|
||||||
with `save`, then emits a python-build definition for it with
|
with `save`, then emits a python-build definition for it with
|
||||||
@ -24,6 +24,8 @@ with `save`, then emits a python-build definition for it with
|
|||||||
current platform, platform version and architecture. An explicit entry keeps
|
current platform, platform version and architecture. An explicit entry keeps
|
||||||
the existing custom-build workflow.
|
the existing custom-build workflow.
|
||||||
|
|
||||||
|
Pass `-v` to show build progress from `pyenv install`.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pyenv binary package 3.12.7 \
|
pyenv binary package 3.12.7 \
|
||||||
--archive-base-url https://example.com/binaries
|
--archive-base-url https://example.com/binaries
|
||||||
|
|||||||
@ -185,6 +185,11 @@ elif [ -n "$DEPS" ]; then
|
|||||||
echo "pyenv-binary: cannot check required system libraries (ldconfig cache unavailable)" >&2
|
echo "pyenv-binary: cannot check required system libraries (ldconfig cache unavailable)" >&2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if ! command -v patchelf >/dev/null 2>&1; then
|
||||||
|
echo "pyenv-binary: need patchelf to relocate the binary" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
build_package_relocate() {
|
build_package_relocate() {
|
||||||
pyenv binary relocate "$PREFIX_PATH"
|
pyenv binary relocate "$PREFIX_PATH"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
#
|
#
|
||||||
# Summary: Create an installable binary package from a Python version
|
# Summary: Create an installable binary package from a Python version
|
||||||
#
|
#
|
||||||
# Usage: pyenv binary package <version>[:<entry>] --archive-base-url <url>
|
# Usage: pyenv binary package [-v|--verbose] <version>[:<entry>] --archive-base-url <url>
|
||||||
#
|
#
|
||||||
# Installs <version> from source under a separate entry name, saves it as a
|
# Installs <version> from source under a separate entry name, saves it as a
|
||||||
# binary package, then emits a python-build definition for that package.
|
# binary package, then emits a python-build definition for that package.
|
||||||
@ -13,6 +13,7 @@
|
|||||||
# <entry> The optional name to build under and install the
|
# <entry> The optional name to build under and install the
|
||||||
# binary as. If omitted, a name is generated from the
|
# binary as. If omitted, a name is generated from the
|
||||||
# current platform, platform version and architecture.
|
# current platform, platform version and architecture.
|
||||||
|
# -v,--verbose Show build progress from `pyenv install'.
|
||||||
# --archive-base-url <url>
|
# --archive-base-url <url>
|
||||||
# Where the archive will be hosted; the definition
|
# Where the archive will be hosted; the definition
|
||||||
# downloads it from <url>/<entry>.tar.gz.
|
# downloads it from <url>/<entry>.tar.gz.
|
||||||
@ -23,23 +24,29 @@ set -e
|
|||||||
# Provide pyenv completions
|
# Provide pyenv completions
|
||||||
if [ "$1" = "--complete" ]; then
|
if [ "$1" = "--complete" ]; then
|
||||||
echo --archive-base-url
|
echo --archive-base-url
|
||||||
|
echo --verbose
|
||||||
exec pyenv-install --list --bare
|
exec pyenv-install --list --bare
|
||||||
fi
|
fi
|
||||||
|
|
||||||
spec=""
|
spec=""
|
||||||
archive_base_url=""
|
archive_base_url=""
|
||||||
|
verbose=""
|
||||||
|
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--archive-base-url )
|
--archive-base-url )
|
||||||
[ $# -ge 2 ] || { echo "pyenv-binary: --archive-base-url needs a value" >&2; exit 1; }
|
[ $# -lt 2 ] && { echo "pyenv-binary: --archive-base-url needs a value" >&2; exit 1; }
|
||||||
archive_base_url="$2"; shift 2 ;;
|
archive_base_url="$2"; shift ;;
|
||||||
|
-v|--verbose)
|
||||||
|
verbose=1 ;;
|
||||||
-* )
|
-* )
|
||||||
echo "pyenv-binary: unknown option \`$1'" >&2; exit 1 ;;
|
echo "pyenv-binary: unknown option \`$1'" >&2; exit 1 ;;
|
||||||
* )
|
* )
|
||||||
[ -z "$spec" ] || { echo "pyenv-binary: unexpected argument \`$1'" >&2; exit 1; }
|
[ -z "$spec" ] || { echo "pyenv-binary: unexpected argument \`$1'" >&2; exit 1; }
|
||||||
spec="$1"; shift ;;
|
spec="$1"
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ -z "$spec" ] || [ -z "$archive_base_url" ]; then
|
if [ -z "$spec" ] || [ -z "$archive_base_url" ]; then
|
||||||
@ -78,7 +85,7 @@ if [ "$os" = "Darwin" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# `pyenv install' puts a `<version>:<alias>' build under versions/<alias>.
|
# `pyenv install' puts a `<version>:<alias>' build under versions/<alias>.
|
||||||
pyenv-install "$spec"
|
pyenv-install ${verbose:+--verbose} "$spec"
|
||||||
pyenv-binary-save "$entry" "$PWD" --name "$entry"
|
pyenv-binary-save "$entry" "$PWD" --name "$entry"
|
||||||
|
|
||||||
pyenv-binary-generate-installer "${entry}.meta" \
|
pyenv-binary-generate-installer "${entry}.meta" \
|
||||||
|
|||||||
@ -106,6 +106,17 @@ create_meta() {
|
|||||||
assert_failure "pyenv-binary: missing required system libraries: libmissing.so.1"
|
assert_failure "pyenv-binary: missing required system libraries: libmissing.so.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "checks for patchelf before installing the archive" {
|
||||||
|
local out="${BATS_TEST_TMPDIR}/definition"
|
||||||
|
pyenv-binary-generate-installer "$(create_meta)" \
|
||||||
|
--archive-url http://example.com/a.tar.gz -o "$out"
|
||||||
|
create_stub uname 'case "$1" in -s) echo Linux;; -m) echo x86_64;; esac'
|
||||||
|
create_stub getconf 'echo "glibc 2.31"'
|
||||||
|
|
||||||
|
PATH="$(path_without patchelf)" run bash "$out"
|
||||||
|
assert_failure "pyenv-binary: need patchelf to relocate the binary"
|
||||||
|
}
|
||||||
|
|
||||||
@test "fails when the archive is not beside the metadata" {
|
@test "fails when the archive is not beside the metadata" {
|
||||||
local meta="$(create_meta)"
|
local meta="$(create_meta)"
|
||||||
rm "${BATS_TEST_TMPDIR}/3.12.7.tar.gz"
|
rm "${BATS_TEST_TMPDIR}/3.12.7.tar.gz"
|
||||||
@ -125,6 +136,7 @@ create_meta() {
|
|||||||
mkdir -p "$cache"
|
mkdir -p "$cache"
|
||||||
cp "$archive" "${cache}/Python-3.12.7-binary.tar.gz"
|
cp "$archive" "${cache}/Python-3.12.7-binary.tar.gz"
|
||||||
create_stub pyenv 'echo "pyenv $*"'
|
create_stub pyenv 'echo "pyenv $*"'
|
||||||
|
create_path_executable patchelf "exit 0"
|
||||||
create_stub uname 'case "$1" in -s) echo Linux;; -m) echo x86_64;; esac'
|
create_stub uname 'case "$1" in -s) echo Linux;; -m) echo x86_64;; esac'
|
||||||
|
|
||||||
PYTHON_BUILD_CACHE_PATH="$cache" run \
|
PYTHON_BUILD_CACHE_PATH="$cache" run \
|
||||||
|
|||||||
@ -6,22 +6,33 @@ load test_helper
|
|||||||
# the platform tools report a fixed Linux target so the real `save' and
|
# the platform tools report a fixed Linux target so the real `save' and
|
||||||
# `generate-installer' behave the same on any test host.
|
# `generate-installer' behave the same on any test host.
|
||||||
stub_build_environment() {
|
stub_build_environment() {
|
||||||
create_stub pyenv-install 'mkdir -p "${PYENV_ROOT}/versions/${1##*:}/bin"'
|
create_stub pyenv-install 'echo "${0##*/} $*"; mkdir -p "${PYENV_ROOT}/versions/${1##*:}/bin"'
|
||||||
create_stub pyenv-latest '[ "$1" = "-f" ] && [ "$2" = "-k" ] && shift 2 && echo "$*"'
|
create_stub pyenv-latest 'while (($#)); do case "$1" in -f|-k);; *)break;; esac; shift; done; echo "$*"'
|
||||||
create_stub uname 'case "$1" in -s) echo Linux;; -m) echo x86_64;; esac'
|
create_stub uname 'case "$1" in -s) echo Linux;; -m) echo x86_64;; esac'
|
||||||
create_stub getconf 'echo "glibc 2.17"'
|
create_stub getconf 'echo "glibc 2.17"'
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "completion lists the option and definitions provided by another plugin" {
|
@test "-v|--verbose runs pyenv install verbosely" {
|
||||||
mkdir -p "${PYENV_ROOT}/plugins/example/share/python-build"
|
stub_build_environment
|
||||||
touch "${PYENV_ROOT}/plugins/example/share/python-build/3.12.7-example"
|
create_stub pyenv-binary-save true
|
||||||
PATH="${BATS_TEST_DIRNAME}/../../python-build/bin:${PATH}"
|
create_stub pyenv-binary-generate-installer true
|
||||||
|
|
||||||
|
for opt in "" -v --verbose; do
|
||||||
|
run pyenv-binary-package $opt 3.12.7:3.12.7-test \
|
||||||
|
--archive-base-url http://example.com/binaries
|
||||||
|
assert_success "pyenv-install ${opt:+--verbose }3.12.7:3.12.7-test"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "completions" {
|
||||||
|
create_stub pyenv-install 'echo "${0##*/} $*"'
|
||||||
|
|
||||||
run pyenv-binary-package --complete
|
run pyenv-binary-package --complete
|
||||||
assert_success
|
assert_success <<!
|
||||||
assert_line "--archive-base-url"
|
--archive-base-url
|
||||||
assert_line "3.12.7-example"
|
--verbose
|
||||||
refute_line "Available versions:"
|
pyenv-install --list --bare
|
||||||
|
!
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "fails with no arguments" {
|
@test "fails with no arguments" {
|
||||||
@ -76,7 +87,7 @@ stub_build_environment() {
|
|||||||
assert_failure "pyenv-binary: macOS archives are not supported yet"
|
assert_failure "pyenv-binary: macOS archives are not supported yet"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "writes the archive, metadata and definition under the entry name" {
|
@test "writes the archive, metadata and definition under the entry name (integration)" {
|
||||||
stub_build_environment
|
stub_build_environment
|
||||||
cd "${BATS_TEST_TMPDIR}"
|
cd "${BATS_TEST_TMPDIR}"
|
||||||
|
|
||||||
@ -90,13 +101,24 @@ stub_build_environment() {
|
|||||||
assert_success "ARCHIVE_URL=http://example.com/binaries/3.12.7-test.tar.gz"
|
assert_success "ARCHIVE_URL=http://example.com/binaries/3.12.7-test.tar.gz"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "strips a trailing slash from the archive base url" {
|
@test "correctly joins archive base url with a trailing slash" {
|
||||||
stub_build_environment
|
stub_build_environment
|
||||||
cd "${BATS_TEST_TMPDIR}"
|
create_stub pyenv-binary-save true
|
||||||
|
create_stub pyenv-binary-generate-installer <<'!'
|
||||||
|
echo -n "${0##*/} "
|
||||||
|
while (($#)); do
|
||||||
|
case $1 in
|
||||||
|
--archive-url)
|
||||||
|
echo "$1 ${2:?}"
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
!
|
||||||
|
|
||||||
run pyenv-binary-package 3.12.7:3.12.7-test \
|
run pyenv-binary-package 3.12.7:3.12.7-test \
|
||||||
--archive-base-url http://example.com/binaries/
|
--archive-base-url http://example.com/binaries/
|
||||||
assert_success
|
assert_success
|
||||||
run grep '^ARCHIVE_URL=' "${BATS_TEST_TMPDIR}/3.12.7-test"
|
assert_line "pyenv-binary-generate-installer --archive-url http://example.com/binaries/3.12.7-test.tar.gz"
|
||||||
assert_success "ARCHIVE_URL=http://example.com/binaries/3.12.7-test.tar.gz"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,8 @@ load test_helper
|
|||||||
touch "${PYENV_ROOT}/shims/.pyenv-shim"
|
touch "${PYENV_ROOT}/shims/.pyenv-shim"
|
||||||
#avoid failure due to a localized error message
|
#avoid failure due to a localized error message
|
||||||
LANG=C run pyenv-rehash
|
LANG=C run pyenv-rehash
|
||||||
assert_failure <<!
|
assert_failure
|
||||||
|
assert_output_glob <<!
|
||||||
pyenv: cannot rehash: couldn't acquire lock ${PYENV_ROOT}/shims/.pyenv-shim for 1 seconds. Last error message:
|
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
|
*/pyenv-rehash: line *: ${PYENV_ROOT}/shims/.pyenv-shim: cannot overwrite existing file
|
||||||
!
|
!
|
||||||
|
|||||||
@ -58,34 +58,64 @@ assert_success() {
|
|||||||
if [ "$status" -ne 0 ]; then
|
if [ "$status" -ne 0 ]; then
|
||||||
flunk "command failed with exit status $status" $'\n'\
|
flunk "command failed with exit status $status" $'\n'\
|
||||||
"output: $output"
|
"output: $output"
|
||||||
elif [ "$#" -gt 0 ]; then
|
|
||||||
assert_output "$1"
|
|
||||||
fi
|
fi
|
||||||
|
_assert_output_if_provided "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_failure() {
|
assert_failure() {
|
||||||
if [ "$status" -eq 0 ]; then
|
if [ "$status" -eq 0 ]; then
|
||||||
flunk "expected failed exit status" $'\n'\
|
flunk "expected failed exit status" $'\n'\
|
||||||
"output: $output"
|
"output: $output"
|
||||||
elif [ "$#" -gt 0 ]; then
|
|
||||||
assert_output "$1"
|
|
||||||
fi
|
fi
|
||||||
|
_assert_output_if_provided "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_equal() {
|
assert_equal() {
|
||||||
if [ "$1" != "$2" ]; then
|
_assert_equal_as text "$@"
|
||||||
{ echo "expected: \`$1'"
|
}
|
||||||
echo "actual: \`$2'"
|
|
||||||
|
_assert_equal_as() {
|
||||||
|
if case "$1" in
|
||||||
|
text)
|
||||||
|
[[ "$2" != "$3" ]];;
|
||||||
|
glob)
|
||||||
|
[[ "$3" != $2 ]];;
|
||||||
|
*)
|
||||||
|
echo "invalid comparison type: \`$1'" >&2; return 1;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
{ diff -u --label expected --label actual <(echo "$2") <(echo "$3") | cat -te
|
||||||
} | flunk
|
} | flunk
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_output() {
|
_assert_output_if_provided() {
|
||||||
local expected
|
if [ "$#" -gt 0 ]; then
|
||||||
if [ $# -eq 0 ]; then expected="$(cat -)"
|
assert_output "$1"
|
||||||
else expected="$1"
|
elif [ ! -t 0 ]; then
|
||||||
|
local expected=$(cat -)
|
||||||
|
if [[ -n $expected ]]; then
|
||||||
|
assert_output "$expected"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
assert_equal "$expected" "$output"
|
}
|
||||||
|
|
||||||
|
assert_output() {
|
||||||
|
_assert_output_as text "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_output_glob() {
|
||||||
|
_assert_output_as glob "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
_assert_output_as() {
|
||||||
|
local kind="${1:?}"; shift
|
||||||
|
local expected
|
||||||
|
if [ $# -eq 0 ]
|
||||||
|
then expected="$(cat -)"
|
||||||
|
else expected="$1"
|
||||||
|
fi
|
||||||
|
_assert_equal_as "$kind" "$expected" "$output"
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_line() {
|
assert_line() {
|
||||||
|
|||||||
@ -90,13 +90,13 @@ IN
|
|||||||
}
|
}
|
||||||
|
|
||||||
@test "skips glob path traversal" {
|
@test "skips glob path traversal" {
|
||||||
cat > my-version <<IN
|
cat > my-version <<'IN'
|
||||||
../*
|
../*
|
||||||
3.9.3
|
3.9.3
|
||||||
IN
|
IN
|
||||||
run pyenv-version-file-read my-version
|
run pyenv-version-file-read my-version
|
||||||
assert_success <<OUT
|
assert_success <<'OUT'
|
||||||
pyenv: invalid version \`../\*' ignored in \`my-version'
|
pyenv: invalid version `../*' ignored in `my-version'
|
||||||
3.9.3
|
3.9.3
|
||||||
OUT
|
OUT
|
||||||
}
|
}
|
||||||
|
|||||||
@ -83,8 +83,7 @@ OUT
|
|||||||
create_version "3.4.0/envs/bar"
|
create_version "3.4.0/envs/bar"
|
||||||
create_version "3.5.2"
|
create_version "3.5.2"
|
||||||
run pyenv-versions
|
run pyenv-versions
|
||||||
assert_success
|
assert_success <<OUT
|
||||||
assert_output <<OUT
|
|
||||||
* system (set by ${PYENV_ROOT}/version)
|
* system (set by ${PYENV_ROOT}/version)
|
||||||
2.7.6
|
2.7.6
|
||||||
3.4.0
|
3.4.0
|
||||||
@ -95,6 +94,7 @@ OUT
|
|||||||
}
|
}
|
||||||
|
|
||||||
@test "skips envs with --skip-envs" {
|
@test "skips envs with --skip-envs" {
|
||||||
|
stub_system_python
|
||||||
create_version "3.3.3"
|
create_version "3.3.3"
|
||||||
create_version "3.4.0"
|
create_version "3.4.0"
|
||||||
create_version "3.4.0/envs/foo"
|
create_version "3.4.0/envs/foo"
|
||||||
@ -102,7 +102,7 @@ OUT
|
|||||||
create_version "3.5.0"
|
create_version "3.5.0"
|
||||||
|
|
||||||
run pyenv-versions --skip-envs
|
run pyenv-versions --skip-envs
|
||||||
assert_success <<OUT
|
assert_success <<OUT
|
||||||
* system (set by ${PYENV_ROOT}/version)
|
* system (set by ${PYENV_ROOT}/version)
|
||||||
3.3.3
|
3.3.3
|
||||||
3.4.0
|
3.4.0
|
||||||
@ -188,9 +188,7 @@ OUT
|
|||||||
create_external_version "moo"
|
create_external_version "moo"
|
||||||
|
|
||||||
run pyenv-versions --bare --skip-aliases
|
run pyenv-versions --bare --skip-aliases
|
||||||
assert_success
|
assert_success <<OUT
|
||||||
|
|
||||||
assert_output <<OUT
|
|
||||||
1.8.7
|
1.8.7
|
||||||
moo
|
moo
|
||||||
OUT
|
OUT
|
||||||
|
|||||||
@ -64,7 +64,7 @@ load test_helper
|
|||||||
assert_failure <<OUT
|
assert_failure <<OUT
|
||||||
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
|
pyenv: py.test: command not found
|
||||||
|
|
||||||
The \`py.test' command exists in these Python versions:
|
The \`py.test' command exists in these Python versions:
|
||||||
3.4
|
3.4
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ 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
|
pyenv: py.test: command not found
|
||||||
|
|
||||||
The \`py.test' command exists in these Python versions:
|
The \`py.test' command exists in these Python versions:
|
||||||
3.4
|
3.4
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user