mirror of
https://github.com/pyenv/pyenv.git
synced 2026-09-10 15:46:17 -04:00
pyenv-binary: rename build to package
Delegate completion to `pyenv install --list`, use the explicit entry for the archive and metadata names, and distinguish the base URL from `generate-installer`'s full archive URL.
This commit is contained in:
parent
bcdc61bdf8
commit
94fcf1e269
|
|
@ -16,10 +16,10 @@ and dependency metadata exist to catch that.
|
|||
|
||||
## Commands
|
||||
|
||||
### `pyenv binary build <version>:<entry> --archive-url <url>`
|
||||
### `pyenv binary package <version>:<entry> --archive-base-url <url>`
|
||||
|
||||
Builds `<version>` from source under the separate name `<entry>`, packages it
|
||||
with `save`, then emits a python-build definition for it with
|
||||
Installs `<version>` from source under the separate name `<entry>`, packages
|
||||
that install with `save`, then emits a python-build definition for it with
|
||||
`generate-installer`. The archive, metadata and definition land in the current
|
||||
directory, named after the entry; host the archive under `<url>` and drop the
|
||||
definition into python-build's definition directory. Keeping the entry name
|
||||
|
|
@ -27,16 +27,18 @@ distinct from the version lets the binary sit alongside a normal source
|
|||
install of the same version.
|
||||
|
||||
```sh
|
||||
pyenv binary build 3.12.7:3.12.7-debian-12 --archive-url https://example.com/binaries
|
||||
# writes 3.12.7-debian-12-linux-x86_64.tar.gz, its .meta file and
|
||||
pyenv binary package 3.12.7:3.12.7-debian-12 \
|
||||
--archive-base-url https://example.com/binaries
|
||||
# writes 3.12.7-debian-12.tar.gz, its .meta file and
|
||||
# a `3.12.7-debian-12' definition
|
||||
```
|
||||
|
||||
### `pyenv binary save <version> [<output-dir>]`
|
||||
### `pyenv binary save <version> [<output-dir>] [--name <name>]`
|
||||
|
||||
Packs an installed version into `<version>-<platform>.tar.gz` (relative paths)
|
||||
and writes `<version>-<platform>.meta` describing the build platform (OS, arch,
|
||||
distro and libc version) and the system libraries the build links against.
|
||||
distro and libc version) and the system libraries the build links against. Use
|
||||
`--name` to set a different base name for both files.
|
||||
|
||||
```sh
|
||||
pyenv binary save 3.12.7 ./dist
|
||||
|
|
|
|||
|
|
@ -1,48 +1,41 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Summary: Build a Python version and package it as an installable binary
|
||||
# Summary: Create an installable binary package from a Python version
|
||||
#
|
||||
# Usage: pyenv binary build <version>:<entry> --archive-url <url>
|
||||
# Usage: pyenv binary package <version>:<entry> --archive-base-url <url>
|
||||
#
|
||||
# Builds <version> from source under the separate name <entry>, packages the
|
||||
# result with `pyenv binary save', then emits a python-build definition for
|
||||
# it with `pyenv binary generate-installer'. The archive, metadata and
|
||||
# definition are written to the current directory, named after <entry>.
|
||||
# Installs <version> from source under the separate name <entry>, saves it as
|
||||
# a binary package, then emits a python-build definition for that package.
|
||||
# The archive, metadata and definition are written to the current directory
|
||||
# as <entry>.tar.gz, <entry>.meta and <entry>.
|
||||
#
|
||||
# <version> A version `pyenv install' knows how to build.
|
||||
# <entry> The name to build under and to install the binary
|
||||
# as, e.g. `3.13.14-debian-12'. Keeping it distinct
|
||||
# from <version> lets the binary sit alongside a
|
||||
# normal source install of the same version.
|
||||
# --archive-url <url> Where the archive will be hosted; the definition
|
||||
# downloads it from <url>/<archive-name>.
|
||||
# --archive-base-url <url>
|
||||
# Where the archive will be hosted; the definition
|
||||
# downloads it from <url>/<entry>.tar.gz.
|
||||
#
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
# Provide pyenv completions. Only the definitions are useful here: the options
|
||||
# `pyenv install' takes are not accepted. Include definitions from other
|
||||
# plugins just as `pyenv install' does.
|
||||
# Provide pyenv completions
|
||||
if [ "$1" = "--complete" ]; then
|
||||
shopt -s nullglob
|
||||
for plugin_path in "$PYENV_ROOT"/plugins/*/share/python-build; do
|
||||
PYTHON_BUILD_DEFINITIONS="${PYTHON_BUILD_DEFINITIONS}:${plugin_path}"
|
||||
done
|
||||
export PYTHON_BUILD_DEFINITIONS
|
||||
shopt -u nullglob
|
||||
|
||||
echo --archive-url
|
||||
exec python-build --definitions
|
||||
echo --archive-base-url
|
||||
pyenv-install --list | sed '1d; s/^ //'
|
||||
exit
|
||||
fi
|
||||
|
||||
spec=""
|
||||
archive_url=""
|
||||
archive_base_url=""
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--archive-url )
|
||||
[ $# -ge 2 ] || { echo "pyenv-binary: --archive-url needs a value" >&2; exit 1; }
|
||||
archive_url="$2"; shift 2 ;;
|
||||
--archive-base-url )
|
||||
[ $# -ge 2 ] || { echo "pyenv-binary: --archive-base-url needs a value" >&2; exit 1; }
|
||||
archive_base_url="$2"; shift 2 ;;
|
||||
-* )
|
||||
echo "pyenv-binary: unknown option \`$1'" >&2; exit 1 ;;
|
||||
* )
|
||||
|
|
@ -51,8 +44,8 @@ while [ $# -gt 0 ]; do
|
|||
esac
|
||||
done
|
||||
|
||||
if [ -z "$spec" ] || [ -z "$archive_url" ]; then
|
||||
pyenv-help --usage binary-build >&2
|
||||
if [ -z "$spec" ] || [ -z "$archive_base_url" ]; then
|
||||
pyenv-help --usage binary-package >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -84,7 +77,7 @@ esac
|
|||
os="$(uname -s)"
|
||||
|
||||
# `generate-installer' refuses a macOS archive, so the last step here cannot
|
||||
# succeed on one. Give up before the build rather than after it.
|
||||
# succeed on one. Give up before compiling rather than after it.
|
||||
if [ "$os" = "Darwin" ]; then
|
||||
echo "pyenv-binary: macOS archives are not supported yet" >&2
|
||||
exit 1
|
||||
|
|
@ -92,9 +85,7 @@ fi
|
|||
|
||||
# `pyenv install' puts a `<version>:<alias>' build under versions/<alias>.
|
||||
pyenv-install "$spec"
|
||||
pyenv-binary-save "$entry"
|
||||
pyenv-binary-save "$entry" "$PWD" --name "$entry"
|
||||
|
||||
# Name the metadata and the archive the way `save' just named them.
|
||||
platform="$(printf '%s' "$os" | tr '[:upper:]' '[:lower:]')-$(uname -m)"
|
||||
pyenv-binary-generate-installer "${entry}-${platform}.meta" \
|
||||
--archive-url "${archive_url%/}/${entry}-${platform}.tar.gz" -o "$entry"
|
||||
pyenv-binary-generate-installer "${entry}.meta" \
|
||||
--archive-url "${archive_base_url%/}/${entry}.tar.gz" -o "$entry"
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# Summary: Save an installed Python version as a relocatable archive
|
||||
#
|
||||
# Usage: pyenv binary save <version> [<output-dir>]
|
||||
# Usage: pyenv binary save <version> [<output-dir>] [--name <name>]
|
||||
#
|
||||
# Packs an installed version into a relocatable .tar.gz (relative paths) and
|
||||
# writes a metadata file listing the build platform and the system libraries
|
||||
|
|
@ -10,20 +10,46 @@
|
|||
#
|
||||
# <version> An installed version, as listed by `pyenv versions --bare'.
|
||||
# <output-dir> Where to write the archive and metadata (default: `.').
|
||||
# --name <name> Use <name> as the archive and metadata base name instead of
|
||||
# <version>-<platform>.
|
||||
#
|
||||
set -e
|
||||
[ -n "$PYENV_DEBUG" ] && set -x
|
||||
|
||||
# Provide pyenv completions
|
||||
if [ "$1" = "--complete" ]; then
|
||||
echo --name
|
||||
exec pyenv-versions --bare
|
||||
fi
|
||||
|
||||
version="$1"
|
||||
output_dir="${2:-$PWD}"
|
||||
version=""
|
||||
output_dir=""
|
||||
package_name=""
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--name )
|
||||
[ $# -ge 2 ] && [ -n "$2" ] || { echo "pyenv-binary: --name needs a value" >&2; exit 1; }
|
||||
package_name="$2"; shift 2 ;;
|
||||
-* )
|
||||
echo "pyenv-binary: unknown option \`$1'" >&2; exit 1 ;;
|
||||
* )
|
||||
if [ -z "$version" ]; then
|
||||
version="$1"
|
||||
elif [ -z "$output_dir" ]; then
|
||||
output_dir="$1"
|
||||
else
|
||||
echo "pyenv-binary: unexpected argument \`$1'" >&2
|
||||
exit 1
|
||||
fi
|
||||
shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
output_dir="${output_dir:-$PWD}"
|
||||
|
||||
if [ -z "$version" ]; then
|
||||
echo "Usage: pyenv binary save <version> [<output-dir>]" >&2
|
||||
echo "Usage: pyenv binary save <version> [<output-dir>] [--name <name>]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -36,6 +62,13 @@ case "$version" in
|
|||
;;
|
||||
esac
|
||||
|
||||
case "$package_name" in
|
||||
*/* | .. | . )
|
||||
echo "pyenv-binary: invalid package name \`${package_name}'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
prefix="${PYENV_ROOT}/versions/${version}"
|
||||
if [ ! -d "${prefix}/bin" ]; then
|
||||
echo "pyenv-binary: version \`${version}' is not installed" >&2
|
||||
|
|
@ -85,8 +118,9 @@ system_deps() {
|
|||
}
|
||||
|
||||
mkdir -p "$output_dir"
|
||||
archive="${version}-${platform}.tar.gz"
|
||||
metadata="${version}-${platform}.meta"
|
||||
package_name="${package_name:-${version}-${platform}}"
|
||||
archive="${package_name}.tar.gz"
|
||||
metadata="${package_name}.meta"
|
||||
|
||||
tar -C "$(dirname "$prefix")" -czf "${output_dir}/${archive}" "$(basename "$prefix")"
|
||||
|
||||
|
|
|
|||
|
|
@ -11,79 +11,82 @@ stub_build_environment() {
|
|||
create_stub getconf 'echo "glibc 2.17"'
|
||||
}
|
||||
|
||||
@test "completion lists definitions provided by another plugin" {
|
||||
@test "completion lists the option and definitions provided by another plugin" {
|
||||
mkdir -p "${PYENV_ROOT}/plugins/example/share/python-build"
|
||||
touch "${PYENV_ROOT}/plugins/example/share/python-build/3.12.7-example"
|
||||
PATH="${BATS_TEST_DIRNAME}/../../python-build/bin:${PATH}"
|
||||
|
||||
run pyenv-binary-build --complete
|
||||
run pyenv-binary-package --complete
|
||||
assert_success
|
||||
assert_line "--archive-url"
|
||||
assert_line "--archive-base-url"
|
||||
assert_line "3.12.7-example"
|
||||
refute_line "Available versions:"
|
||||
}
|
||||
|
||||
@test "fails with no arguments" {
|
||||
create_stub pyenv-help "echo usage"
|
||||
run pyenv-binary-build
|
||||
run pyenv-binary-package
|
||||
assert_failure "usage"
|
||||
}
|
||||
|
||||
@test "fails without an archive url" {
|
||||
@test "fails without an archive base url" {
|
||||
create_stub pyenv-help "echo usage"
|
||||
run pyenv-binary-build 3.12.7:3.12.7-test
|
||||
run pyenv-binary-package 3.12.7:3.12.7-test
|
||||
assert_failure "usage"
|
||||
}
|
||||
|
||||
@test "fails when --archive-url has no value" {
|
||||
run pyenv-binary-build 3.12.7:3.12.7-test --archive-url
|
||||
assert_failure "pyenv-binary: --archive-url needs a value"
|
||||
@test "fails when --archive-base-url has no value" {
|
||||
run pyenv-binary-package 3.12.7:3.12.7-test --archive-base-url
|
||||
assert_failure "pyenv-binary: --archive-base-url needs a value"
|
||||
}
|
||||
|
||||
@test "rejects a second positional argument" {
|
||||
run pyenv-binary-build 3.12.7:3.12.7-test extra --archive-url http://x/b
|
||||
run pyenv-binary-package 3.12.7:3.12.7-test extra --archive-base-url http://x/b
|
||||
assert_failure "pyenv-binary: unexpected argument \`extra'"
|
||||
}
|
||||
|
||||
@test "rejects a bare version without an entry name" {
|
||||
run pyenv-binary-build 3.12.7 --archive-url http://x/b
|
||||
run pyenv-binary-package 3.12.7 --archive-base-url http://x/b
|
||||
assert_failure "pyenv-binary: expected <version>:<entry>, e.g. \`3.13.14:3.13.14-debian-12'"
|
||||
}
|
||||
|
||||
@test "rejects an entry name containing a slash" {
|
||||
run pyenv-binary-build "3.12.7:foo/bar" --archive-url http://x/b
|
||||
run pyenv-binary-package "3.12.7:foo/bar" --archive-base-url http://x/b
|
||||
assert_failure "pyenv-binary: invalid entry name \`foo/bar'"
|
||||
}
|
||||
|
||||
@test "rejects \`latest' as an entry name" {
|
||||
run pyenv-binary-build 3.12:latest --archive-url http://x/b
|
||||
run pyenv-binary-package 3.12:latest --archive-base-url http://x/b
|
||||
assert_failure "pyenv-binary: \`latest' cannot be used as an entry name"
|
||||
}
|
||||
|
||||
@test "refuses to build on macOS before compiling anything" {
|
||||
@test "refuses to package on macOS before compiling anything" {
|
||||
create_stub uname 'case "$1" in -s) echo Darwin;; -m) echo arm64;; esac'
|
||||
run pyenv-binary-build 3.12.7:3.12.7-test --archive-url http://x/b
|
||||
run pyenv-binary-package 3.12.7:3.12.7-test --archive-base-url http://x/b
|
||||
assert_failure "pyenv-binary: macOS archives are not supported yet"
|
||||
}
|
||||
|
||||
@test "builds under the entry name and writes the archive and definition" {
|
||||
@test "writes the archive, metadata and definition under the entry name" {
|
||||
stub_build_environment
|
||||
cd "${BATS_TEST_TMPDIR}"
|
||||
|
||||
run pyenv-binary-build 3.12.7:3.12.7-test --archive-url http://example.com/binaries
|
||||
run pyenv-binary-package 3.12.7:3.12.7-test \
|
||||
--archive-base-url http://example.com/binaries
|
||||
assert_success
|
||||
assert [ -d "${PYENV_ROOT}/versions/3.12.7-test" ]
|
||||
assert [ -f "${BATS_TEST_TMPDIR}/3.12.7-test-linux-x86_64.tar.gz" ]
|
||||
assert [ -f "${BATS_TEST_TMPDIR}/3.12.7-test-linux-x86_64.meta" ]
|
||||
assert [ -f "${BATS_TEST_TMPDIR}/3.12.7-test.tar.gz" ]
|
||||
assert [ -f "${BATS_TEST_TMPDIR}/3.12.7-test.meta" ]
|
||||
run grep '^ARCHIVE_URL=' "${BATS_TEST_TMPDIR}/3.12.7-test"
|
||||
assert_success "ARCHIVE_URL=http://example.com/binaries/3.12.7-test-linux-x86_64.tar.gz"
|
||||
assert_success "ARCHIVE_URL=http://example.com/binaries/3.12.7-test.tar.gz"
|
||||
}
|
||||
|
||||
@test "strips a trailing slash from the archive url" {
|
||||
@test "strips a trailing slash from the archive base url" {
|
||||
stub_build_environment
|
||||
cd "${BATS_TEST_TMPDIR}"
|
||||
|
||||
run pyenv-binary-build 3.12.7:3.12.7-test --archive-url http://example.com/binaries/
|
||||
run pyenv-binary-package 3.12.7:3.12.7-test \
|
||||
--archive-base-url http://example.com/binaries/
|
||||
assert_success
|
||||
run grep '^ARCHIVE_URL=' "${BATS_TEST_TMPDIR}/3.12.7-test"
|
||||
assert_success "ARCHIVE_URL=http://example.com/binaries/3.12.7-test-linux-x86_64.tar.gz"
|
||||
assert_success "ARCHIVE_URL=http://example.com/binaries/3.12.7-test.tar.gz"
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ platform() {
|
|||
|
||||
@test "fails with no version given" {
|
||||
run pyenv-binary-save
|
||||
assert_failure "Usage: pyenv binary save <version> [<output-dir>]"
|
||||
assert_failure "Usage: pyenv binary save <version> [<output-dir>] [--name <name>]"
|
||||
}
|
||||
|
||||
@test "fails for a version that is not installed" {
|
||||
|
|
@ -44,6 +44,29 @@ platform() {
|
|||
assert_line 0 "3.12.7/"
|
||||
}
|
||||
|
||||
@test "uses an explicit package name" {
|
||||
create_version "3.12.7"
|
||||
local out="${BATS_TEST_TMPDIR}/dist"
|
||||
|
||||
run pyenv-binary-save "3.12.7" "$out" --name "custom"
|
||||
assert_success "Saved custom.tar.gz and custom.meta to $out"
|
||||
assert [ -f "${out}/custom.tar.gz" ]
|
||||
run grep '^archive=' "${out}/custom.meta"
|
||||
assert_success "archive=custom.tar.gz"
|
||||
}
|
||||
|
||||
@test "fails when --name has no value" {
|
||||
run pyenv-binary-save "3.12.7" --name
|
||||
assert_failure "pyenv-binary: --name needs a value"
|
||||
}
|
||||
|
||||
@test "rejects an invalid package name" {
|
||||
create_version "3.12.7"
|
||||
|
||||
run pyenv-binary-save "3.12.7" --name "foo/bar"
|
||||
assert_failure "pyenv-binary: invalid package name \`foo/bar'"
|
||||
}
|
||||
|
||||
@test "records the platform in the metadata" {
|
||||
create_version "3.12.7"
|
||||
local out="${BATS_TEST_TMPDIR}/dist"
|
||||
|
|
|
|||
Loading…
Reference in a new issue