blob: 71d0e8a64a9f0005bd6f3e09d550f7d667a7c19d [file] [log] [blame]
# Copyright 2023 The Pigweed Authors
#
# 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
#
# https://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.
"""Download all Python packages required for a pw_python_venv."""
import argparse
import logging
from pathlib import Path
import shlex
import subprocess
import sys
_LOG = logging.getLogger('pw_build.generate_python_wheel_cache')
def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
'--pip-download-log',
type=Path,
required=True,
help='Path to the root gn build dir.',
)
parser.add_argument(
'--wheel-dir',
type=Path,
required=True,
help='Path to save wheel files.',
)
parser.add_argument(
'--download-all-platforms',
action='store_true',
help='Download Python precompiled wheels for all platforms.',
)
parser.add_argument(
'-r',
'--requirement',
type=Path,
nargs='+',
required=True,
help='Requirements files',
)
return parser.parse_args()
def main(
pip_download_log: Path,
wheel_dir: Path,
requirement: list[Path],
download_all_platforms: bool = False,
) -> int:
"""Download all Python packages required for a pw_python_venv."""
# Delete existing wheels from the out dir, there may be stale versions.
# shutil.rmtree(wheel_dir, ignore_errors=True)
wheel_dir.mkdir(parents=True, exist_ok=True)
pip_download_args = [
sys.executable,
"-m",
"pip",
"--log",
str(pip_download_log),
"download",
"--dest",
str(wheel_dir),
]
for req in requirement:
pip_download_args.extend(["--requirement", str(req)])
if not download_all_platforms:
# Download for the current platform only.
quoted_pip_download_args = ' '.join(
shlex.quote(arg) for arg in pip_download_args
)
_LOG.info('Run ==> %s', quoted_pip_download_args)
# Download packages
subprocess.run(pip_download_args, check=True)
return 0
# DOCSTAG: [wheel-platform-args]
# These platform args are derived from the cffi pypi package:
# https://pypi.org/project/cffi/#files
# See also these pages on Python wheel filename format:
# https://peps.python.org/pep-0491/#file-name-convention
# and Platform compatibility tags:
# https://packaging.python.org/en/latest/specifications/
# platform-compatibility-tags/
platform_args = [
'--platform=any',
'--platform=macosx_10_9_universal2',
'--platform=macosx_10_9_x86_64',
'--platform=macosx_11_0_arm64',
'--platform=manylinux2010_x86_64',
'--platform=manylinux2014_aarch64',
'--platform=manylinux2014_x86_64',
'--platform=manylinux_2_17_aarch64',
'--platform=manylinux_2_17_x86_64',
'--platform=musllinux_1_1_x86_64',
'--platform=win_amd64',
# Note: These 32bit platforms are omitted
# '--platform=manylinux2010_i686',
# '--platform=manylinux2014_i686',
# '--platform=manylinux_2_12_i686'
# '--platform=musllinux_1_1_i686',
# '--platform=win32',
]
# Pigweed supports Python 3.8 and up.
python_version_args = [
[
'--implementation=py3',
'--abi=none',
],
[
'--implementation=cp',
'--python-version=3.8',
'--abi=cp38',
],
[
'--implementation=cp',
'--python-version=3.9',
'--abi=cp39',
],
[
'--implementation=cp',
'--python-version=3.10',
'--abi=cp310',
],
[
'--implementation=cp',
'--python-version=3.11',
'--abi=cp311',
],
]
# DOCSTAG: [wheel-platform-args]
# --no-deps is required when downloading binary packages for different
# platforms other than the current one. The requirements.txt files already
# has the fully expanded deps list using pip-compile so this is not a
# problem.
pip_download_args.append('--no-deps')
# Run pip download once for each Python version. Multiple platform args can
# be added to the same command.
for py_version_args in python_version_args:
for platform_arg in platform_args:
final_pip_download_args = list(pip_download_args)
final_pip_download_args.append(platform_arg)
final_pip_download_args.extend(py_version_args)
quoted_pip_download_args = ' '.join(
shlex.quote(arg) for arg in final_pip_download_args
)
_LOG.info('')
_LOG.info('Fetching packages for:')
_LOG.info(
'Python %s and Platforms: %s', py_version_args, platform_args
)
_LOG.info('Run ==> %s', quoted_pip_download_args)
# Download packages
subprocess.run(final_pip_download_args, check=True)
return 0
if __name__ == '__main__':
logging.basicConfig(format='%(message)s', level=logging.DEBUG)
sys.exit(main(**vars(_parse_args())))