xref: /aosp_15_r20/external/pigweed/pw_build/py/pw_build/generate_python_wheel.py (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1# Copyright 2023 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Generate a Python wheel for a pw_python_package or pw_python_distribution."""
15
16import argparse
17import hashlib
18from pathlib import Path
19import shutil
20import subprocess
21import sys
22
23try:
24    from pw_build.python_package import PythonPackage
25
26except ImportError:
27    # Load from python_package from this directory if pw_build is not available.
28    from python_package import PythonPackage  # type: ignore
29
30
31def _parse_args() -> argparse.Namespace:
32    parser = argparse.ArgumentParser(description=__doc__)
33    parser.add_argument(
34        '--package-dir',
35        type=Path,
36        required=True,
37        help='Path to the root gn build dir.',
38    )
39    parser.add_argument(
40        '--out-dir',
41        type=Path,
42        required=True,
43        help='requirement file to generate',
44    )
45    parser.add_argument(
46        '--generate-hashes',
47        action='store_true',
48        help='Generate sha256 sums for the requirements.txt file.',
49    )
50    return parser.parse_args()
51
52
53def main(
54    package_dir: Path,
55    out_dir: Path,
56    generate_hashes: bool,
57) -> int:
58    """Build a Python wheel."""
59
60    # Delete existing wheels from the out dir, there may be stale versions.
61    shutil.rmtree(out_dir, ignore_errors=True)
62    out_dir.mkdir(parents=True, exist_ok=True)
63
64    # Find the target package name and version.
65    pkg = PythonPackage(
66        sources=[],
67        setup_sources=[package_dir / 'setup.cfg'],
68        tests=[],
69        inputs=[],
70    )
71    requirement_lines = f'{pkg.package_name}=={pkg.package_version}'
72
73    # Build the wheel.
74    subprocess.run(
75        [
76            sys.executable,
77            "-m",
78            "build",
79            str(package_dir),
80            "--wheel",
81            "--no-isolation",
82            "--outdir",
83            str(out_dir),
84        ],
85        check=True,
86    )
87
88    if generate_hashes:
89        # Cacluate the sha256
90        for wheel_path in out_dir.glob('**/*.whl'):
91            wheel_sha256 = hashlib.sha256()
92            wheel_sha256.update(wheel_path.read_bytes())
93            sha256 = wheel_sha256.hexdigest()
94            requirement_lines += ' \\\n    '
95            requirement_lines += f'--hash=sha256:{sha256}'
96            break
97
98    # Save a requirements file for this wheel and hash value.
99    requirement_file = out_dir / 'requirements.txt'
100    requirement_file.write_text(requirement_lines, encoding='utf-8')
101
102    return 0
103
104
105if __name__ == '__main__':
106    sys.exit(main(**vars(_parse_args())))
107