From 1184fe0290bbf2e6b7a7ae2a9911f37179cf1533 Mon Sep 17 00:00:00 2001 From: Chumper Date: Sun, 12 Jun 2022 23:07:48 +0200 Subject: [PATCH 1/4] feat: convert python to a v2 tool --- src/usr/local/buildpack/tools/python.sh | 117 ---------------- src/usr/local/buildpack/tools/v2/python.sh | 101 ++++++++++++++ test/bash/tools/python.bats | 155 +++++++++++++++++++++ 3 files changed, 256 insertions(+), 117 deletions(-) delete mode 100644 src/usr/local/buildpack/tools/python.sh create mode 100644 src/usr/local/buildpack/tools/v2/python.sh create mode 100644 test/bash/tools/python.bats diff --git a/src/usr/local/buildpack/tools/python.sh b/src/usr/local/buildpack/tools/python.sh deleted file mode 100644 index 01e47282c7..0000000000 --- a/src/usr/local/buildpack/tools/python.sh +++ /dev/null @@ -1,117 +0,0 @@ -#!/bin/bash - -set -e - -check_semver "${TOOL_VERSION}" - - -if [[ ! "${MAJOR}" || ! "${MINOR}" || ! "${PATCH}" ]]; then - echo Invalid version: "${TOOL_VERSION}" - exit 1 -fi - -tool_path=$(find_versioned_tool_path) - -if [[ -z "${tool_path}" ]]; then - INSTALL_DIR=$(get_install_dir) - base_path=${INSTALL_DIR}/${TOOL_NAME} - tool_path=${base_path}/${TOOL_VERSION} - - mkdir -p "${base_path}" - - file=/tmp/python.tar.xz - - ARCH=$(uname -p) - PYTHON_URL="https://github.com/containerbase/python-prebuild/releases/download" - - version_codename=$(get_distro) - - curl -sSfLo ${file} "${PYTHON_URL}/${TOOL_VERSION}/python-${TOOL_VERSION}-${version_codename}-${ARCH}.tar.xz" || echo 'Ignore download error' - - if [[ -f ${file} ]]; then - echo 'Using prebuild python' - tar -C "${base_path}" -xf ${file} - rm ${file} - else - echo 'No prebuild python found, building from source' - require_root - apt_install \ - build-essential \ - libbz2-dev \ - libffi-dev \ - liblzma-dev \ - libreadline-dev \ - libsqlite3-dev \ - libssl-dev \ - zlib1g-dev \ - ; - - if [[ ! -x "$(command -v python-build)" ]]; then - git clone https://github.com/pyenv/pyenv.git - pushd pyenv/plugins/python-build - ./install.sh - popd - rm -rf pyenv - fi - python-build "$TOOL_VERSION" "${base_path}"/"$TOOL_VERSION" - fi - - fix_python_shebangs() { - # https://github.com/koalaman/shellcheck/wiki/SC2044 - while IFS= read -r -d '' file - do - case "$(head -1 "${file}")" in - "#!"*"/bin/python" ) - sed -i "1 s:.*:#\!${tool_path}\/bin\/python:" "${file}" - ;; - "#!"*"/bin/python${MAJOR}" ) - sed -i "1 s:.*:#\!${tool_path}\/bin\/python${MAJOR}:" "${file}" - ;; - "#!"*"/bin/python${MAJOR}.${MINOR}" ) - sed -i "1 s:.*:#\!${tool_path}\/bin\/python${MAJOR}.${MINOR}:" "${file}" - ;; - esac - done < <(find "${tool_path}/bin" -type f -exec grep -Iq . {} \; -print0) - } - - fix_python_shebangs - - PYTHONHOME=${tool_path} "${tool_path}/bin/pip" install --upgrade pip - - # clean cache https://pip.pypa.io/en/stable/reference/pip_cache/#pip-cache - PYTHONHOME=${tool_path} "${tool_path}/bin/pip" cache purge -fi - -reset_tool_env -# TODO: fix me, currently required for global pip -export_tool_path "${tool_path}/bin" -export_tool_path "${USER_HOME}/.local/bin" - -function python_shell_wrapper () { - local install_dir - local tool_target - local tool_wrapper - - install_dir=$(get_install_dir) - tool_wrapper="${install_dir}/bin/${1}" - tool_target="${tool_path}/bin/$1" - check_command "${tool_target}" - cat > "$tool_wrapper" <<- EOM -#!/bin/bash - -export PYTHONHOME=${tool_path} PATH=${tool_path}/bin:\$PATH - -${tool_target} "\$@" -EOM - chmod 775 "$tool_wrapper" -} - -python_shell_wrapper "${TOOL_NAME}" -python_shell_wrapper "${TOOL_NAME}${MAJOR}" -python_shell_wrapper "${TOOL_NAME}${MAJOR}.${MINOR}" -python_shell_wrapper pip -python_shell_wrapper "pip${MAJOR}" -python_shell_wrapper "pip${MAJOR}.${MINOR}" - -python --version -pip --version diff --git a/src/usr/local/buildpack/tools/v2/python.sh b/src/usr/local/buildpack/tools/v2/python.sh new file mode 100644 index 0000000000..f956478b23 --- /dev/null +++ b/src/usr/local/buildpack/tools/v2/python.sh @@ -0,0 +1,101 @@ +#!/bin/bash + +# sets the correct shebang for python +fix_python_shebangs() { + # https://github.com/koalaman/shellcheck/wiki/SC2044 + while IFS= read -r -d '' file + do + case "$(head -1 "${file}")" in + "#!"*"/bin/python" ) + sed -i "1 s:.*:#\!${versioned_tool_path}\/bin\/python:" "${file}" + ;; + "#!"*"/bin/python${MAJOR}" ) + sed -i "1 s:.*:#\!${versioned_tool_path}\/bin\/python${MAJOR}:" "${file}" + ;; + "#!"*"/bin/python${MAJOR}.${MINOR}" ) + sed -i "1 s:.*:#\!${versioned_tool_path}\/bin\/python${MAJOR}.${MINOR}:" "${file}" + ;; + esac + done < <(find "${versioned_tool_path}/bin" -type f -exec grep -Iq . {} \; -print0) +} + +function prepare_tool() { + apt_install \ + build-essential \ + libbz2-dev \ + libffi-dev \ + liblzma-dev \ + libreadline-dev \ + libsqlite3-dev \ + libssl-dev \ + zlib1g-dev \ + ; + if [[ ! -x "$(command -v python-build)" ]]; then + git clone https://github.com/pyenv/pyenv.git + pushd pyenv/plugins/python-build || exit + ./install.sh + popd || exit + rm -rf pyenv + fi +} + +function install_tool () { + local versioned_tool_path + local file + local url + local arch + local version_codename + + # get semver -> major, minor, patch + check_semver "${TOOL_VERSION}" + + versioned_tool_path=$(create_versioned_tool_path) + arch=$(uname -p) + url="https://github.com/containerbase/python-prebuild/releases/download" + version_codename=$(get_distro) + + create_folder "${versioned_tool_path}/bin" + + file=$(get_from_url "${url}/${TOOL_VERSION}/python-${TOOL_VERSION}-${version_codename}-${arch}.tar.xz") + + if [[ -f ${file} ]]; then + echo 'Using prebuild python' + tar -C "${versioned_tool_path}" --strip 1 -xf "${file}" + else + python-build "$TOOL_VERSION" "${versioned_tool_path}/${TOOL_VERSION}" + fi + + fix_python_shebangs + + # install latest pip + PYTHONHOME=${versioned_tool_path} "${versioned_tool_path}/bin/pip" install --upgrade pip + + # clean cache https://pip.pypa.io/en/stable/reference/pip_cache/#pip-cache + PYTHONHOME=${versioned_tool_path} "${versioned_tool_path}/bin/pip" cache purge +} + +function link_tool () { + local versioned_tool_path + versioned_tool_path=$(find_versioned_tool_path) + + # get semver -> major, minor, patch + check_semver "${TOOL_VERSION}" + + reset_tool_env + + # export python vars + export_tool_env PYTHONHOME "${versioned_tool_path}" + export_tool_path "${versioned_tool_path}/bin" + export_tool_path "${USER_HOME}/.local/bin" + + # TODO: fix me, currently required for global pip + shell_wrapper "${TOOL_NAME}" "${versioned_tool_path}/bin" + shell_wrapper "${TOOL_NAME}${MAJOR}" "${versioned_tool_path}/bin" + shell_wrapper "${TOOL_NAME}${MAJOR}.${MINOR}" "${versioned_tool_path}/bin" + shell_wrapper pip "${versioned_tool_path}/bin" + shell_wrapper "pip${MAJOR}" "${versioned_tool_path}/bin" + shell_wrapper "pip${MAJOR}.${MINOR}" "${versioned_tool_path}/bin" + + python --version + pip --version +} diff --git a/test/bash/tools/python.bats b/test/bash/tools/python.bats new file mode 100644 index 0000000000..1940b342ce --- /dev/null +++ b/test/bash/tools/python.bats @@ -0,0 +1,155 @@ +setup_file () { + export TEST_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")" >/dev/null 2>&1 && pwd)" + + # set up the cache + load "$TEST_DIR/../cache.sh" + export BUILDPACK_CACHE_DIR="$(create_temp_dir TEST_CACHE_DIR)" +} + +setup() { + load '../../../node_modules/bats-support/load' + load '../../../node_modules/bats-assert/load' + + TEST_ROOT_DIR=$(mktemp -u) + + load "$TEST_DIR/../../../src/usr/local/buildpack/util.sh" + + # load v2 overwrites + load "$TEST_DIR/../../../src/usr/local/buildpack/utils/v2/overrides.sh" + + # load test overwrites + load "$TEST_DIR/../util.sh" + + # set directories for test + ROOT_DIR="${TEST_ROOT_DIR}/root" + BIN_DIR="${TEST_ROOT_DIR}/bin" + + setup_directories + + # set default test user + TEST_ROOT_USER=1000 + + # load python + load "$TEST_DIR/../../../src/usr/local/buildpack/tools/v2/python.sh" + +} + +teardown() { + rm -rf "${TEST_ROOT_DIR}" +} + +teardown_file () { + clean_temp_dir $BUILDPACK_CACHE_DIR TEST_CACHE_DIR +} + +@test "python: check_tool_requirements" { + TOOL_NAME=python + + TOOL_VERSION=foobar \ + run check_tool_requirements + assert_failure + + TOOL_VERSION=1.2.3 \ + run check_tool_requirements + assert_success +} + +@test "python: check_tool_installed" { + local TOOL_NAME=python + local TOOL_VERSION + + # renovate: datasource=github-releases lookupName=containerbase/python-prebuild + TOOL_VERSION=3.10.5 + + run check_tool_installed + assert_failure + + run install_tool + assert_success + + run check_tool_installed + assert_success +} + +@test "python: install_tool" { + local TOOL_NAME=python + local TOOL_VERSION + + # renovate: datasource=github-releases lookupName=containerbase/python-prebuild + TOOL_VERSION=3.10.5 + + run install_tool + assert_success + + local versioned_tool_path=$(find_versioned_tool_path) + + PATH="${versioned_tool_path}/bin" \ + run python --version + assert_success + assert_output --partial "${TOOL_VERSION}" + + # don't update + TOOL_VERSION=3.10.4 + + run install_tool + assert_success + + local versioned_tool_path=$(find_versioned_tool_path) + + PATH="${versioned_tool_path}/bin" \ + run python --version + assert_success + assert_output --partial "${TOOL_VERSION}" +} + +@test "python: link_tool" { + local TOOL_NAME=python + local TOOL_VERSION + local bin_path=$(get_bin_path) + + # renovate: datasource=github-releases lookupName=containerbase/python-prebuild + TOOL_VERSION=3.10.5 + + run install_tool + assert_success + + PATH="${bin_path}:$PATH" \ + run link_tool + assert_success + assert_output --partial "${TOOL_VERSION}" + + PATH="${bin_path}" \ + run python --version + assert_success + assert_output --partial "${TOOL_VERSION}" + + local versioned_tool_path=$(find_versioned_tool_path) + + PATH="${versioned_tool_path}/bin" \ + run python --version + assert_success + assert_output --partial "${TOOL_VERSION}" + + # don't update + TOOL_VERSION=3.10.4 + + run install_tool + assert_success + + PATH="${bin_path}:$PATH" \ + run link_tool + assert_success + assert_output --partial "${TOOL_VERSION}" + + local versioned_tool_path=$(find_versioned_tool_path) + + PATH="${versioned_tool_path}/bin" \ + run python --version + assert_success + assert_output --partial "${TOOL_VERSION}" + + PATH="${bin_path}" \ + run python --version + assert_success + assert_output --partial "${TOOL_VERSION}" +} From 22b8678ffc6d41a302f905bfcbefb6840244eefb Mon Sep 17 00:00:00 2001 From: Michael Kriese Date: Mon, 13 Jun 2022 21:19:43 +0200 Subject: [PATCH 2/4] Apply suggestions from code review --- src/usr/local/buildpack/tools/v2/python.sh | 23 ++-------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/usr/local/buildpack/tools/v2/python.sh b/src/usr/local/buildpack/tools/v2/python.sh index f956478b23..20493e8153 100644 --- a/src/usr/local/buildpack/tools/v2/python.sh +++ b/src/usr/local/buildpack/tools/v2/python.sh @@ -19,26 +19,6 @@ fix_python_shebangs() { done < <(find "${versioned_tool_path}/bin" -type f -exec grep -Iq . {} \; -print0) } -function prepare_tool() { - apt_install \ - build-essential \ - libbz2-dev \ - libffi-dev \ - liblzma-dev \ - libreadline-dev \ - libsqlite3-dev \ - libssl-dev \ - zlib1g-dev \ - ; - if [[ ! -x "$(command -v python-build)" ]]; then - git clone https://github.com/pyenv/pyenv.git - pushd pyenv/plugins/python-build || exit - ./install.sh - popd || exit - rm -rf pyenv - fi -} - function install_tool () { local versioned_tool_path local file @@ -62,7 +42,8 @@ function install_tool () { echo 'Using prebuild python' tar -C "${versioned_tool_path}" --strip 1 -xf "${file}" else - python-build "$TOOL_VERSION" "${versioned_tool_path}/${TOOL_VERSION}" + echo 'No prebuild python found' >&2 + exit 1 fi fix_python_shebangs From 78d804cff783ebf9c37c220e4563d2835f4a6fa6 Mon Sep 17 00:00:00 2001 From: Chumper Date: Mon, 13 Jun 2022 22:41:50 +0200 Subject: [PATCH 3/4] chore: remove semver checking from v2 python tool --- src/usr/local/buildpack/tools/v2/python.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/usr/local/buildpack/tools/v2/python.sh b/src/usr/local/buildpack/tools/v2/python.sh index 20493e8153..8d5758dcad 100644 --- a/src/usr/local/buildpack/tools/v2/python.sh +++ b/src/usr/local/buildpack/tools/v2/python.sh @@ -59,9 +59,6 @@ function link_tool () { local versioned_tool_path versioned_tool_path=$(find_versioned_tool_path) - # get semver -> major, minor, patch - check_semver "${TOOL_VERSION}" - reset_tool_env # export python vars From 110f72691baa168801042872d4015a3ed977642d Mon Sep 17 00:00:00 2001 From: Chumper Date: Mon, 13 Jun 2022 23:51:42 +0200 Subject: [PATCH 4/4] fix: use correct test order for bats test --- src/usr/local/buildpack/tools/v2/python.sh | 3 --- test/bash/tools/python.bats | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/usr/local/buildpack/tools/v2/python.sh b/src/usr/local/buildpack/tools/v2/python.sh index 8d5758dcad..88ec3bbee5 100644 --- a/src/usr/local/buildpack/tools/v2/python.sh +++ b/src/usr/local/buildpack/tools/v2/python.sh @@ -26,9 +26,6 @@ function install_tool () { local arch local version_codename - # get semver -> major, minor, patch - check_semver "${TOOL_VERSION}" - versioned_tool_path=$(create_versioned_tool_path) arch=$(uname -p) url="https://github.com/containerbase/python-prebuild/releases/download" diff --git a/test/bash/tools/python.bats b/test/bash/tools/python.bats index 1940b342ce..7c2c9361b6 100644 --- a/test/bash/tools/python.bats +++ b/test/bash/tools/python.bats @@ -64,6 +64,10 @@ teardown_file () { run check_tool_installed assert_failure + # needed to export versions + check_tool_requirements + + run install_tool assert_success @@ -78,6 +82,9 @@ teardown_file () { # renovate: datasource=github-releases lookupName=containerbase/python-prebuild TOOL_VERSION=3.10.5 + # needed to export versions + check_tool_requirements + run install_tool assert_success @@ -91,6 +98,9 @@ teardown_file () { # don't update TOOL_VERSION=3.10.4 + # needed to export versions + check_tool_requirements + run install_tool assert_success @@ -110,6 +120,9 @@ teardown_file () { # renovate: datasource=github-releases lookupName=containerbase/python-prebuild TOOL_VERSION=3.10.5 + # needed to export versions + check_tool_requirements + run install_tool assert_success @@ -133,6 +146,9 @@ teardown_file () { # don't update TOOL_VERSION=3.10.4 + # needed to export versions + check_tool_requirements + run install_tool assert_success