xref: /aosp_15_r20/external/tink/python/tools/distribution/create_release.sh (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1#!/bin/bash
2# Copyright 2020 Google LLC
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15################################################################################
16
17# This script creates the release artifacts of Tink Python which includes a
18# source distribution and binary wheels for Linux and macOS.  All Python tests
19# are exectued for each binary wheel and the source distribution.
20
21set -euox pipefail
22
23declare -a PYTHON_VERSIONS=
24PYTHON_VERSIONS+=("3.7")
25PYTHON_VERSIONS+=("3.8")
26PYTHON_VERSIONS+=("3.9")
27PYTHON_VERSIONS+=("3.10")
28readonly PYTHON_VERSIONS
29
30readonly PLATFORM="$(uname | tr '[:upper:]' '[:lower:]')"
31
32export TINK_PYTHON_ROOT_PATH="${PWD}"
33readonly TINK_VERSION="$(grep ^TINK "${TINK_PYTHON_ROOT_PATH}/VERSION" \
34  | awk '{gsub(/"/, "", $3); print $3}')"
35
36readonly IMAGE_NAME="quay.io/pypa/manylinux2014_x86_64"
37readonly IMAGE_DIGEST="sha256:31d7d1cbbb8ea93ac64c3113bceaa0e9e13d65198229a25eee16dc70e8bf9cf7"
38readonly IMAGE="${IMAGE_NAME}@${IMAGE_DIGEST}"
39
40#######################################
41# Builds Tink Python built distribution (Wheel) [1].
42#
43# This function must be called from within the Tink Python's root folder.
44#
45# [1] https://packaging.python.org/en/latest/glossary/#term-Built-Distribution
46# Globals:
47#   None
48# Arguments:
49#   None
50#######################################
51__create_and_test_wheels_for_linux() {
52  echo "### Building and testing Linux binary wheels ###"
53  # Use signatures for getting images from registry (see
54  # https://docs.docker.com/engine/security/trust/content_trust/).
55  export DOCKER_CONTENT_TRUST=1
56
57  # We use setup.py to build wheels; setup.py makes changes to the WORKSPACE
58  # file so we save a copy for backup.
59  cp WORKSPACE WORKSPACE.bak
60
61  local -r tink_base_dir="/tmp/tink"
62  local -r tink_py_relative_path="${PWD##*/}"
63  local -r workdir="${tink_base_dir}/${tink_py_relative_path}"
64  # Build binary wheels.
65  docker run \
66    --volume "${TINK_PYTHON_ROOT_PATH}/..:${tink_base_dir}" \
67    --workdir "${workdir}" \
68    -e TINK_PYTHON_SETUPTOOLS_OVERRIDE_BASE_PATH="${tink_base_dir}" \
69    "${IMAGE}" \
70    "${workdir}/tools/distribution/build_linux_binary_wheels.sh"
71
72  ## Test binary wheels.
73  docker run \
74    --volume "${TINK_PYTHON_ROOT_PATH}/..:${tink_base_dir}" \
75    --workdir "${workdir}" \
76    "${IMAGE}" \
77    "${workdir}/tools/distribution/test_linux_binary_wheels.sh"
78
79  # Docker runs as root so we transfer ownership to the non-root user.
80  sudo chown -R "$(id -un):$(id -gn)" "${TINK_PYTHON_ROOT_PATH}"
81  # Restore the original WORKSPACE.
82  mv WORKSPACE.bak WORKSPACE
83}
84
85#######################################
86# Builds Tink Python source distribution [1].
87#
88# This function must be called from within the Tink Python's root folder.
89#
90# [1] https://packaging.python.org/en/latest/glossary/#term-Source-Distribution-or-sdist
91# Globals:
92#   PYTHON_VERSIONS
93# Arguments:
94#   None
95#######################################
96__create_and_test_sdist_for_linux() {
97  echo "### Building and testing Linux source distribution ###"
98  local sorted=( $( echo "${PYTHON_VERSIONS[@]}" \
99    | xargs -n1 | sort -V | xargs ) )
100  local latest="${sorted[${#sorted[@]}-1]}"
101  enable_py_version "${latest}"
102
103  # Patch the workspace to use http_archive rules which specify the release tag.
104  #
105  # This is done so that an already patched version of WORKSPACE is present in
106  # the sdist. Then, when building from the sdist, the default patching logic
107  # in performed by setup.py will be a no-op.
108  #
109  # TODO(b/281635529): Use a container for a more hermetic testing environment.
110  cp WORKSPACE WORKSPACE.bak
111
112  # Build source distribution.
113  TINK_PYTHON_SETUPTOOLS_TAGGED_VERSION="${TINK_VERSION}" \
114    python3 setup.py sdist --owner=root --group=root
115  local sdist_filename="tink-${TINK_VERSION}.tar.gz"
116  cp "dist/${sdist_filename}" release/
117
118  # Restore the original WORKSPACE.
119  mv WORKSPACE.bak WORKSPACE
120
121  # Test install from source distribution.
122  python3 --version
123  python3 -m pip list
124  # Install Tink dependencies.
125  python3 -m pip install --require-hashes -r requirements.txt
126  python3 -m pip install --no-deps --no-index -v "release/${sdist_filename}"
127  python3 -m pip list
128  find tink/ -not -path "*cc/pybind*" -type f -name "*_test.py" -print0 \
129    | xargs -0 -n1 python3
130}
131
132#######################################
133# Creates a Tink Python distribution for Linux.
134#
135# This function must be called from within the Tink Python's root folder.
136#
137# Globals:
138#   None
139# Arguments:
140#   None
141#######################################
142create_distribution_for_linux() {
143  __create_and_test_wheels_for_linux
144  __create_and_test_sdist_for_linux
145}
146
147#######################################
148# Creates a Tink Python distribution for MacOS.
149#
150# This function must be called from within the Tink Python's root folder.
151#
152# Globals:
153#   PYTHON_VERSIONS
154# Arguments:
155#   None
156#######################################
157create_distribution_for_macos() {
158  echo "### Building macOS binary wheels ###"
159
160  for v in "${PYTHON_VERSIONS[@]}"; do
161    enable_py_version "${v}"
162
163    # Build binary wheel.
164    python3 -m pip wheel -w release .
165
166    # Test binary wheel.
167    # TODO(ckl): Implement test.
168  done
169}
170
171enable_py_version() {
172  # A partial version number (e.g. "3.9").
173  local partial_version="$1"
174
175  # The latest installed Python version that matches the partial version number
176  # (e.g. "3.9.5").
177  local version="$(pyenv versions --bare | grep "${partial_version}" | tail -1)"
178
179  # Set current Python version via environment variable.
180  pyenv shell "${version}"
181
182  # Update environment.
183  python3 -m pip install --require-hashes -r \
184    "${TINK_PYTHON_ROOT_PATH}/tools/distribution/requirements.txt"
185}
186
187main() {
188  eval "$(pyenv init -)"
189  mkdir -p release
190
191  if [[ "${PLATFORM}" == 'linux' ]]; then
192    create_distribution_for_linux
193  elif [[ "${PLATFORM}" == 'darwin' ]]; then
194    create_distribution_for_macos
195  else
196    echo "${PLATFORM} is not a supported platform."
197    exit 1
198  fi
199}
200
201main "$@"
202