|
9 | 9 | """ |
10 | 10 |
|
11 | 11 | import argparse |
| 12 | +import hashlib |
12 | 13 | import json |
13 | 14 | import os |
14 | 15 | import re |
@@ -121,6 +122,39 @@ def check_node(dry_run): |
121 | 122 |
|
122 | 123 |
|
123 | 124 | # --- Python --- |
| 125 | +def fetch_python_sha256(version): |
| 126 | + tarball_url = f"https://www.python.org/ftp/python/{version}/Python-{version}.tar.xz" |
| 127 | + try: |
| 128 | + releases = fetch_json(f"https://www.python.org/api/v2/downloads/release/?name=Python+{version}") |
| 129 | + if not releases: |
| 130 | + return '' |
| 131 | + release_id = releases[0].get('resource_uri', '').rstrip('/').split('/')[-1] |
| 132 | + files = fetch_json(f"https://www.python.org/api/v2/downloads/release_file/?release={release_id}") |
| 133 | + for f in files: |
| 134 | + if f.get('url', '').endswith('.tar.xz'): |
| 135 | + sha = f.get('sha256_sum', '') |
| 136 | + if sha: |
| 137 | + return sha.upper() |
| 138 | + tarball_url = f.get('url', tarball_url) |
| 139 | + break |
| 140 | + except Exception as e: |
| 141 | + print(f" WARNING: API lookup failed for Python {version}: {e}") |
| 142 | + # Fallback: download tarball and compute SHA256 when API field is empty |
| 143 | + try: |
| 144 | + req = urllib.request.Request(tarball_url, headers={'User-Agent': 'Oryx-AutoUpdate/1.0'}) |
| 145 | + h = hashlib.sha256() |
| 146 | + with urllib.request.urlopen(req, timeout=120) as resp: |
| 147 | + while True: |
| 148 | + chunk = resp.read(65536) |
| 149 | + if not chunk: |
| 150 | + break |
| 151 | + h.update(chunk) |
| 152 | + return h.hexdigest().upper() |
| 153 | + except Exception as e: |
| 154 | + print(f" WARNING: Failed to compute SHA256 for Python {version}: {e}") |
| 155 | + return '' |
| 156 | + |
| 157 | + |
124 | 158 | def check_python(dry_run): |
125 | 159 | print("=== Python ===") |
126 | 160 | content = read_constants() |
@@ -151,11 +185,20 @@ def check_python(dry_run): |
151 | 185 | for minor, ver in updates.items(): |
152 | 186 | key = f'python{minor.replace(".", "")}Version' |
153 | 187 | print(f" Python {minor}: {tracked[minor]} -> {ver}") |
| 188 | + # SHA256 is only needed for Python 3.14+ onward |
| 189 | + needs_sha = version_tuple(minor) >= version_tuple('3.14') |
| 190 | + sha = fetch_python_sha256(ver) if needs_sha else '' |
| 191 | + if needs_sha and not sha: |
| 192 | + print(f" WARNING: No SHA256 found for Python {ver}, skipping versionsToBuild update") |
154 | 193 | if not dry_run: |
155 | 194 | content = update_constant(content, key, ver) |
156 | 195 | gpg = get_current_version(content, f'python{minor.replace(".", "")}_GPG_keys') or '' |
157 | 196 | for flavor in get_os_flavors(content, 'python', minor): |
158 | | - append_to_versions_to_build('python', flavor, f'{ver}, {gpg},') |
| 197 | + if needs_sha: |
| 198 | + if sha: |
| 199 | + append_to_versions_to_build('python', flavor, f'{ver}, {gpg}, {sha},') |
| 200 | + else: |
| 201 | + append_to_versions_to_build('python', flavor, f'{ver}, {gpg},') |
159 | 202 |
|
160 | 203 | if not dry_run: |
161 | 204 | write_constants(content) |
|
0 commit comments