17db96d56Sopenharmony_ci#! /usr/bin/env python3 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ci""" 47db96d56Sopenharmony_ciCompare checksums for wheels in :mod:`ensurepip` against the Cheeseshop. 57db96d56Sopenharmony_ci 67db96d56Sopenharmony_ciWhen GitHub Actions executes the script, output is formatted accordingly. 77db96d56Sopenharmony_cihttps://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-notice-message 87db96d56Sopenharmony_ci""" 97db96d56Sopenharmony_ci 107db96d56Sopenharmony_ciimport hashlib 117db96d56Sopenharmony_ciimport json 127db96d56Sopenharmony_ciimport os 137db96d56Sopenharmony_ciimport re 147db96d56Sopenharmony_cifrom pathlib import Path 157db96d56Sopenharmony_cifrom urllib.request import urlopen 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ciPACKAGE_NAMES = ("pip", "setuptools") 187db96d56Sopenharmony_ciENSURE_PIP_ROOT = Path(__file__).parent.parent.parent / "Lib/ensurepip" 197db96d56Sopenharmony_ciWHEEL_DIR = ENSURE_PIP_ROOT / "_bundled" 207db96d56Sopenharmony_ciENSURE_PIP_INIT_PY_TEXT = (ENSURE_PIP_ROOT / "__init__.py").read_text(encoding="utf-8") 217db96d56Sopenharmony_ciGITHUB_ACTIONS = os.getenv("GITHUB_ACTIONS") == "true" 227db96d56Sopenharmony_ci 237db96d56Sopenharmony_ci 247db96d56Sopenharmony_cidef print_notice(file_path: str, message: str) -> None: 257db96d56Sopenharmony_ci if GITHUB_ACTIONS: 267db96d56Sopenharmony_ci message = f"::notice file={file_path}::{message}" 277db96d56Sopenharmony_ci print(message, end="\n\n") 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ci 307db96d56Sopenharmony_cidef print_error(file_path: str, message: str) -> None: 317db96d56Sopenharmony_ci if GITHUB_ACTIONS: 327db96d56Sopenharmony_ci message = f"::error file={file_path}::{message}" 337db96d56Sopenharmony_ci print(message, end="\n\n") 347db96d56Sopenharmony_ci 357db96d56Sopenharmony_ci 367db96d56Sopenharmony_cidef verify_wheel(package_name: str) -> bool: 377db96d56Sopenharmony_ci # Find the package on disk 387db96d56Sopenharmony_ci package_path = next(WHEEL_DIR.glob(f"{package_name}*.whl"), None) 397db96d56Sopenharmony_ci if not package_path: 407db96d56Sopenharmony_ci print_error("", f"Could not find a {package_name} wheel on disk.") 417db96d56Sopenharmony_ci return False 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_ci print(f"Verifying checksum for {package_path}.") 447db96d56Sopenharmony_ci 457db96d56Sopenharmony_ci # Find the version of the package used by ensurepip 467db96d56Sopenharmony_ci package_version_match = re.search( 477db96d56Sopenharmony_ci f'_{package_name.upper()}_VERSION = "([^"]+)', ENSURE_PIP_INIT_PY_TEXT 487db96d56Sopenharmony_ci ) 497db96d56Sopenharmony_ci if not package_version_match: 507db96d56Sopenharmony_ci print_error( 517db96d56Sopenharmony_ci package_path, 527db96d56Sopenharmony_ci f"No {package_name} version found in Lib/ensurepip/__init__.py.", 537db96d56Sopenharmony_ci ) 547db96d56Sopenharmony_ci return False 557db96d56Sopenharmony_ci package_version = package_version_match[1] 567db96d56Sopenharmony_ci 577db96d56Sopenharmony_ci # Get the SHA 256 digest from the Cheeseshop 587db96d56Sopenharmony_ci try: 597db96d56Sopenharmony_ci raw_text = urlopen(f"https://pypi.org/pypi/{package_name}/json").read() 607db96d56Sopenharmony_ci except (OSError, ValueError): 617db96d56Sopenharmony_ci print_error(package_path, f"Could not fetch JSON metadata for {package_name}.") 627db96d56Sopenharmony_ci return False 637db96d56Sopenharmony_ci 647db96d56Sopenharmony_ci release_files = json.loads(raw_text)["releases"][package_version] 657db96d56Sopenharmony_ci for release_info in release_files: 667db96d56Sopenharmony_ci if package_path.name != release_info["filename"]: 677db96d56Sopenharmony_ci continue 687db96d56Sopenharmony_ci expected_digest = release_info["digests"].get("sha256", "") 697db96d56Sopenharmony_ci break 707db96d56Sopenharmony_ci else: 717db96d56Sopenharmony_ci print_error(package_path, f"No digest for {package_name} found from PyPI.") 727db96d56Sopenharmony_ci return False 737db96d56Sopenharmony_ci 747db96d56Sopenharmony_ci # Compute the SHA 256 digest of the wheel on disk 757db96d56Sopenharmony_ci actual_digest = hashlib.sha256(package_path.read_bytes()).hexdigest() 767db96d56Sopenharmony_ci 777db96d56Sopenharmony_ci print(f"Expected digest: {expected_digest}") 787db96d56Sopenharmony_ci print(f"Actual digest: {actual_digest}") 797db96d56Sopenharmony_ci 807db96d56Sopenharmony_ci if actual_digest != expected_digest: 817db96d56Sopenharmony_ci print_error( 827db96d56Sopenharmony_ci package_path, f"Failed to verify the checksum of the {package_name} wheel." 837db96d56Sopenharmony_ci ) 847db96d56Sopenharmony_ci return False 857db96d56Sopenharmony_ci 867db96d56Sopenharmony_ci print_notice( 877db96d56Sopenharmony_ci package_path, 887db96d56Sopenharmony_ci f"Successfully verified the checksum of the {package_name} wheel.", 897db96d56Sopenharmony_ci ) 907db96d56Sopenharmony_ci return True 917db96d56Sopenharmony_ci 927db96d56Sopenharmony_ci 937db96d56Sopenharmony_ciif __name__ == "__main__": 947db96d56Sopenharmony_ci exit_status = 0 957db96d56Sopenharmony_ci for package_name in PACKAGE_NAMES: 967db96d56Sopenharmony_ci if not verify_wheel(package_name): 977db96d56Sopenharmony_ci exit_status = 1 987db96d56Sopenharmony_ci raise SystemExit(exit_status) 99