| |
|
|
| import argparse |
| import re |
| import sys |
| from pathlib import Path |
| from typing import Sequence |
|
|
| _PYTHON_RUNTIME_VERSION_PATTERN = re.compile(r"[0-9]+\.[0-9]+\.[0-9]+(?:a[0-9]+(?:\.post[0-9]+)?)?") |
| _NORMALIZED_CODEX_VERSION_PATTERN = re.compile( |
| r"[0-9]+(?:\.[0-9]+)*(?:(?:a|b|rc)[0-9]+)?(?:\.post[0-9]+)?" |
| ) |
|
|
|
|
| def main(argv: Sequence[str] | None = None) -> int: |
| parser = argparse.ArgumentParser( |
| description="Resolve a Python runtime version or Codex release tag to both versions." |
| ) |
| parser.add_argument("python_version") |
| parser.add_argument("--github-output", type=Path, required=True) |
| args = parser.parse_args(argv) |
|
|
| try: |
| python_version, release_tag = resolve_python_runtime_release( |
| normalize_codex_version(args.python_version) |
| ) |
| except RuntimeError as exc: |
| print(exc, file=sys.stderr) |
| return 1 |
|
|
| with args.github_output.open("a", encoding="utf-8") as output: |
| print(f"python_version={python_version}", file=output) |
| print(f"release_tag={release_tag}", file=output) |
| return 0 |
|
|
|
|
| def resolve_python_runtime_release(python_version: str) -> tuple[str, str]: |
| if _PYTHON_RUNTIME_VERSION_PATTERN.fullmatch(python_version) is None: |
| raise RuntimeError( |
| "Python runtime version must be stable, a numbered alpha, or an " |
| "alpha post-release, for example 0.136.0, 0.136.0a2, or " |
| f"0.136.0a2.post1; found {python_version}" |
| ) |
| return python_version, codex_release_tag(python_version) |
|
|
|
|
| def codex_release_tag(version: str) -> str: |
| return f"rust-v{codex_release_version(version)}" |
|
|
|
|
| def codex_release_version(version: str) -> str: |
| normalized = normalize_codex_version(version) |
| alpha_hotfix = re.fullmatch( |
| r"([0-9]+(?:\.[0-9]+)*)a([0-9]+)\.post([0-9]+)", |
| normalized, |
| ) |
| if alpha_hotfix is not None: |
| base, alpha, hotfix = alpha_hotfix.groups() |
| return f"{base}-alpha.{alpha}.{hotfix}" |
|
|
| prerelease = re.fullmatch(r"([0-9]+(?:\.[0-9]+)*)(a|b|rc)([0-9]+)", normalized) |
| if prerelease is None: |
| return normalized |
|
|
| base, prerelease_kind, number = prerelease.groups() |
| prerelease_name = {"a": "alpha", "b": "beta", "rc": "rc"}[prerelease_kind] |
| return f"{base}-{prerelease_name}.{number}" |
|
|
|
|
| def normalize_codex_version(version: str) -> str: |
| normalized = version.strip() |
| if normalized.startswith("rust-v"): |
| normalized = normalized.removeprefix("rust-v") |
| elif normalized.startswith("v"): |
| normalized = normalized.removeprefix("v") |
|
|
| normalized = re.sub(r"-alpha\.?([0-9]+)\.([0-9]+)$", r"a\1.post\2", normalized) |
| normalized = re.sub(r"-alpha\.?([0-9]+)$", r"a\1", normalized) |
| normalized = re.sub(r"-beta\.?([0-9]+)$", r"b\1", normalized) |
| normalized = re.sub(r"-rc\.?([0-9]+)$", r"rc\1", normalized) |
|
|
| if _NORMALIZED_CODEX_VERSION_PATTERN.fullmatch(normalized) is None: |
| raise RuntimeError(f"Could not normalize Codex version {version!r} to a PEP 440 version") |
| return normalized |
|
|
|
|
| if __name__ == "__main__": |
| raise SystemExit(main()) |
|
|