blob: ef727fd461a0428a8798a1c3afa31e623770a372 [file] [log] [blame]
#!/usr/bin/bash
# Copyright 2023 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Create a version of the Python CIPD package where all library files are
# stored in a single zip archive. Useful to drastically limit the number
# of input files in Bazel actions that depend on a custom Python toolchain
# target wrapping the content of this package.
#
# For example, the final output would look like:
#
# $PREFIX/
# bin/
# lib_python3.8.zip
# Zip archive containing all standard Python modules.
#
# python3
# ---symlink---> python3.8
#
# python3.8-real
# Real python interpreter binary (stripped).
#
# python3.8
# Wrapper script that invokes python3.8-real after adjusting
# PYTHONPATH to point to lib_python3.8.zip to find standard
# modules.
#
# All other files in bin/ (e.g. 'pip3') are python scripts and need no
# adjustments.
#
set -euxo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
PREFIX="$1"
## Copy the whole bin/ directory to $PREFIX/bin/
cp -Rpf bin "${PREFIX}/"
## Copy the whole include/ directory as well
cp -Rpf include "${PREFIX}/"
# Find the real interpreter executable and copy a stripped version to
# $PREFIX/bin/python<version>-real
#
# NOTE: strip -xS works on both Linux and OSX.
python_versioned="$(readlink "${PREFIX}"/bin/python3)"
strip -xS -o "${PREFIX}/bin/${python_versioned}-real" "${PREFIX}"/bin/${python_versioned}
## Generate library archive.
LIBDIR=lib/${python_versioned}
ARCHIVE_NAME=lib_${python_versioned}.zip
# Change the timestamp of all files that go into the zip
# archive to 1980-01-01 00:00:00
find "${LIBDIR}" -type f | xargs touch -t 198001010000.00
(cd "${LIBDIR}" && zip -0qrD ${ARCHIVE_NAME} .)
cp "${LIBDIR}/${ARCHIVE_NAME}" "${PREFIX}/bin/${ARCHIVE_NAME}"
# Overwrite $PREFIX/bin/python<version> with a wrapper script that invokes
# the real interperter.
#
# - PYTHONHOME is set to _script_dir to ensure sys.path only contains paths
# relative to it. Otherwise, some hard-coded paths in the interpreter
# binary will be used (e.g. `/work/out/python3`), which could lead to bad
# surprises.
#
# - PYTHONPATH is extended to point to the zip archive, and allows the
# interpreter to find all system modules from it.
#
# - The `-S` flag disables site-specific module lookups.
#
# - The `-s` flag disables user-specific module lookups.
#
# Note that `python3` also supports the `-I` flag to run in "isolated" mode,
# where PYTHONPATH and PYTHONHOME are ignored, but this forces sys.path to
# strictly hard-coded values that are unusable here.
#
rm -f "${PREFIX}/bin/${python_versioned}"
cat > "${PREFIX}/bin/${python_versioned}" <<EOF
#!/bin/sh
# AUTO-GENERATED - DO NOT EDIT
if [ -n "\${BASH_VERSION}" ]; then
readonly _script_dir="\$(dirname "\${BASH_SOURCE[0]}")"
elif [ -n "\${ZSH_VERSION}" ]; then
_script_dir="\${0:a:h}"
else
_script_dir="\$(dirname "\$0")"
fi
PYTHONPATH="\${_script_dir}/${ARCHIVE_NAME}:\${PYTHONPATH}" \\
PYTHONHOME="\${_script_dir}" \\
exec "\${_script_dir}/${python_versioned}-real" -S -s "\$@"
EOF
chmod a+x "${PREFIX}/bin/${python_versioned}"
## Copy license file.
cp "${SCRIPT_DIR}"/LICENSE "${PREFIX}/LICENSE"
## Generate README.fuchsia
sed -e 's|@PYTHON_VERSION@|'"${_3PP_VERSION}"'|g' \
-e 's|@PLATFORM@|'"${_3PP_PLATFORM}"'|g' \
"${SCRIPT_DIR}"/README.fuchsia.template > "${PREFIX}/README.fuchsia"