#!/bin/bash # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ################################################################################ # This script creates the release artifacts of Tink Python which includes a # source distribution and binary wheels for Linux and macOS. All Python tests # are exectued for each binary wheel and the source distribution. set -euox pipefail declare -a PYTHON_VERSIONS= PYTHON_VERSIONS+=("3.7") PYTHON_VERSIONS+=("3.8") PYTHON_VERSIONS+=("3.9") PYTHON_VERSIONS+=("3.10") readonly PYTHON_VERSIONS readonly PLATFORM="$(uname | tr '[:upper:]' '[:lower:]')" export TINK_PYTHON_ROOT_PATH="${PWD}" readonly TINK_VERSION="$(grep ^TINK "${TINK_PYTHON_ROOT_PATH}/VERSION" \ | awk '{gsub(/"/, "", $3); print $3}')" readonly IMAGE_NAME="quay.io/pypa/manylinux2014_x86_64" readonly IMAGE_DIGEST="sha256:31d7d1cbbb8ea93ac64c3113bceaa0e9e13d65198229a25eee16dc70e8bf9cf7" readonly IMAGE="${IMAGE_NAME}@${IMAGE_DIGEST}" ####################################### # Builds Tink Python built distribution (Wheel) [1]. # # This function must be called from within the Tink Python's root folder. # # [1] https://packaging.python.org/en/latest/glossary/#term-Built-Distribution # Globals: # None # Arguments: # None ####################################### __create_and_test_wheels_for_linux() { echo "### Building and testing Linux binary wheels ###" # Use signatures for getting images from registry (see # https://docs.docker.com/engine/security/trust/content_trust/). export DOCKER_CONTENT_TRUST=1 # We use setup.py to build wheels; setup.py makes changes to the WORKSPACE # file so we save a copy for backup. cp WORKSPACE WORKSPACE.bak local -r tink_base_dir="/tmp/tink" local -r tink_py_relative_path="${PWD##*/}" local -r workdir="${tink_base_dir}/${tink_py_relative_path}" # Build binary wheels. docker run \ --volume "${TINK_PYTHON_ROOT_PATH}/..:${tink_base_dir}" \ --workdir "${workdir}" \ -e TINK_PYTHON_SETUPTOOLS_OVERRIDE_BASE_PATH="${tink_base_dir}" \ "${IMAGE}" \ "${workdir}/tools/distribution/build_linux_binary_wheels.sh" ## Test binary wheels. docker run \ --volume "${TINK_PYTHON_ROOT_PATH}/..:${tink_base_dir}" \ --workdir "${workdir}" \ "${IMAGE}" \ "${workdir}/tools/distribution/test_linux_binary_wheels.sh" # Docker runs as root so we transfer ownership to the non-root user. sudo chown -R "$(id -un):$(id -gn)" "${TINK_PYTHON_ROOT_PATH}" # Restore the original WORKSPACE. mv WORKSPACE.bak WORKSPACE } ####################################### # Builds Tink Python source distribution [1]. # # This function must be called from within the Tink Python's root folder. # # [1] https://packaging.python.org/en/latest/glossary/#term-Source-Distribution-or-sdist # Globals: # PYTHON_VERSIONS # Arguments: # None ####################################### __create_and_test_sdist_for_linux() { echo "### Building and testing Linux source distribution ###" local sorted=( $( echo "${PYTHON_VERSIONS[@]}" \ | xargs -n1 | sort -V | xargs ) ) local latest="${sorted[${#sorted[@]}-1]}" enable_py_version "${latest}" # Patch the workspace to use http_archive rules which specify the release tag. # # This is done so that an already patched version of WORKSPACE is present in # the sdist. Then, when building from the sdist, the default patching logic # in performed by setup.py will be a no-op. # # TODO(b/281635529): Use a container for a more hermetic testing environment. cp WORKSPACE WORKSPACE.bak # Build source distribution. TINK_PYTHON_SETUPTOOLS_TAGGED_VERSION="${TINK_VERSION}" \ python3 setup.py sdist --owner=root --group=root local sdist_filename="tink-${TINK_VERSION}.tar.gz" cp "dist/${sdist_filename}" release/ # Restore the original WORKSPACE. mv WORKSPACE.bak WORKSPACE # Test install from source distribution. python3 --version python3 -m pip list # Install Tink dependencies. python3 -m pip install --require-hashes -r requirements.txt python3 -m pip install --no-deps --no-index -v "release/${sdist_filename}" python3 -m pip list find tink/ -not -path "*cc/pybind*" -type f -name "*_test.py" -print0 \ | xargs -0 -n1 python3 } ####################################### # Creates a Tink Python distribution for Linux. # # This function must be called from within the Tink Python's root folder. # # Globals: # None # Arguments: # None ####################################### create_distribution_for_linux() { __create_and_test_wheels_for_linux __create_and_test_sdist_for_linux } ####################################### # Creates a Tink Python distribution for MacOS. # # This function must be called from within the Tink Python's root folder. # # Globals: # PYTHON_VERSIONS # Arguments: # None ####################################### create_distribution_for_macos() { echo "### Building macOS binary wheels ###" for v in "${PYTHON_VERSIONS[@]}"; do enable_py_version "${v}" # Build binary wheel. python3 -m pip wheel -w release . # Test binary wheel. # TODO(ckl): Implement test. done } enable_py_version() { # A partial version number (e.g. "3.9"). local partial_version="$1" # The latest installed Python version that matches the partial version number # (e.g. "3.9.5"). local version="$(pyenv versions --bare | grep "${partial_version}" | tail -1)" # Set current Python version via environment variable. pyenv shell "${version}" # Update environment. python3 -m pip install --require-hashes -r \ "${TINK_PYTHON_ROOT_PATH}/tools/distribution/requirements.txt" } main() { eval "$(pyenv init -)" mkdir -p release if [[ "${PLATFORM}" == 'linux' ]]; then create_distribution_for_linux elif [[ "${PLATFORM}" == 'darwin' ]]; then create_distribution_for_macos else echo "${PLATFORM} is not a supported platform." exit 1 fi } main "$@"