Skip to content

Commit 66bce58

Browse files
authored
pypi_riscv64_check: support providing a list or file to check against (#319)
* ci_scripts: pypi_riscv64_check: add list-based registry scan and report Allow an optional '--packages' or '--packages-file' argument for indicating to the script that a specific set of module names should be checked for riscv64 compatibility, against both the PyPI and RISE registries. This can make use of the pre-existing create_issues flag to automatically generate issues to track completeness, like with the automated top-50 check. Co-developed-by: Claude Sonnet 5 Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com> * workflows: pypi-riscv64-check: allow running manually with package list Co-developed-by: Claude Sonnet 5 Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com> --------- Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
1 parent 80bd874 commit 66bce58

2 files changed

Lines changed: 97 additions & 10 deletions

File tree

.github/workflows/pypi-riscv64-check.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ on:
77
schedule:
88
- cron: '0 2 2 * *'
99
workflow_dispatch:
10+
inputs:
11+
packages:
12+
description: 'Comma-separated package names to check instead of the top-50 list'
13+
required: false
14+
default: ''
1015
push:
1116
paths:
1217
- 'ci_scripts/pypi_riscv64_check.py'
@@ -29,4 +34,10 @@ jobs:
2934
- name: Run riscv64 wheel check and open issues for new gaps
3035
env:
3136
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
32-
run: python3 ci_scripts/pypi_riscv64_check.py --create-issues
37+
PACKAGES: ${{ inputs.packages }}
38+
run: |
39+
if [ -n "$PACKAGES" ]; then
40+
python3 ci_scripts/pypi_riscv64_check.py --create-issues --packages "$PACKAGES"
41+
else
42+
python3 ci_scripts/pypi_riscv64_check.py --create-issues
43+
fi

ci_scripts/pypi_riscv64_check.py

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,11 @@ def open_issues_for_missing(packages: list[str]) -> dict[str, int]:
110110
return issues
111111

112112

113-
def open_summary_issue(report: str, issue_map: dict[str, int]) -> None:
114-
"""Open (or skip, if one already exists) a monthly summary issue linking
113+
def open_summary_issue(report: str, issue_map: dict[str, int], title: str | None = None) -> None:
114+
"""Open (or skip, if one already exists) a summary issue linking
115115
to each per-package issue and notifying the maintainers."""
116-
title = f"PyPI riscv64 check - {time.strftime('%Y-%m')}"
116+
if title is None:
117+
title = f"PyPI riscv64 check - {time.strftime('%Y-%m')}"
117118
if find_existing_issue(title) is not None:
118119
print(f" [=] Summary issue for {title!r} already open, skipping")
119120
return
@@ -175,11 +176,15 @@ def fetch_json(url: str) -> dict | list:
175176
return json.loads(r.read())
176177

177178

178-
def analyse_package(name: str, download_count: int) -> dict | None:
179+
def analyse_package(
180+
name: str, download_count: int | None = None, require_binary: bool = True
181+
) -> dict | None:
179182
"""
180-
Returns a result dict if the package ships at least one binary wheel,
181-
otherwise None (pure-Python or fetch error).
182-
183+
Returns a result dict describing the package's wheel situation, or None on
184+
fetch error (or, when require_binary, if it ships no binary wheel at all —
185+
pure-Python packages need no riscv64 wheel and are dropped from the top-N
186+
binary-wheel report).
187+
183188
A binary wheel is any .whl file whose filename does NOT end with
184189
'none-any.whl' (the platform-independent tag).
185190
"""
@@ -188,7 +193,7 @@ def analyse_package(name: str, download_count: int) -> dict | None:
188193
except Exception as exc:
189194
print(f" [WARN] Could not fetch {name}: {exc}")
190195
return None
191-
196+
192197
wheel_files = [
193198
u["filename"]
194199
for u in info.get("urls", [])
@@ -197,19 +202,66 @@ def analyse_package(name: str, download_count: int) -> dict | None:
197202

198203
binary_wheels = [f for f in wheel_files if not f.endswith("none-any.whl")]
199204
if not binary_wheels:
200-
return None # pure-Python or no wheels at all
205+
if require_binary:
206+
return None # pure-Python or no wheels at all
207+
return {
208+
"project": name,
209+
"download_count": download_count,
210+
"pure_python": True,
211+
"has_riscv64": False,
212+
"in_rise_registry": None,
213+
}
201214

202215
riscv64_wheels = [f for f in wheel_files if "riscv64" in f.lower()]
203216
has_riscv64 = len(riscv64_wheels) > 0
204217

205218
return {
206219
"project": name,
207220
"download_count": download_count,
221+
"pure_python": False,
208222
"has_riscv64": has_riscv64,
209223
"in_rise_registry": None if has_riscv64 else in_rise_registry(name),
210224
}
211225

212226

227+
def check_package_list(names: list[str], create_issues: bool) -> None:
228+
"""Check a maintainer-supplied package list: OK if it has a riscv64 wheel
229+
or is pure-Python (nothing to build), otherwise flagged as needing a port."""
230+
report_lines = [
231+
f"{'Package':<35} {'Status':<40}",
232+
"-" * 76,
233+
]
234+
needs_work = []
235+
for name in names:
236+
result = analyse_package(name, require_binary=False)
237+
if result is None:
238+
report_lines.append(f"{name:<35} {'ERROR (could not fetch from PyPI)':<40}")
239+
continue
240+
241+
if result["has_riscv64"]:
242+
status = "OK - riscv64 wheel on PyPI"
243+
elif result["pure_python"]:
244+
status = "OK - pure Python (py3-none-any)"
245+
elif result["in_rise_registry"]:
246+
status = "NEEDS PORT - already in RISE registry"
247+
else:
248+
status = "NEEDS PORT - no riscv64 wheel, not in registry"
249+
needs_work.append(name)
250+
report_lines.append(f"{name:<35} {status:<40}")
251+
252+
report_lines += ["", f"{len(needs_work)}/{len(names)} package(s) need a riscv64 port and are untracked."]
253+
report = "\n".join(report_lines)
254+
print(report)
255+
256+
if create_issues and needs_work:
257+
print()
258+
issue_map = open_issues_for_missing(needs_work)
259+
open_summary_issue(
260+
report, issue_map,
261+
title=f"PyPI riscv64 check (custom list) - {time.strftime('%Y-%m-%d')}",
262+
)
263+
264+
213265
def fmt_count(n: int) -> str:
214266
"""Format large numbers with M/B suffixes."""
215267
if n >= 1_000_000_000:
@@ -234,8 +286,32 @@ def main():
234286
help="Open a GitHub issue for each package missing riscv64 wheels "
235287
"upstream and in the RISE registry, unless one is already open"
236288
)
289+
parser.add_argument(
290+
"--packages",
291+
help="Comma-separated package names to check instead of the top-N "
292+
"list (e.g. a maintainer-supplied audit list)"
293+
)
294+
parser.add_argument(
295+
"--packages-file",
296+
help="Path to a file with one package name per line (# comments and "
297+
"blank lines ignored), instead of the top-N list"
298+
)
237299
args = parser.parse_args()
238300

301+
if args.packages or args.packages_file:
302+
names = []
303+
if args.packages:
304+
names += [n.strip() for n in args.packages.split(",") if n.strip()]
305+
if args.packages_file:
306+
with open(args.packages_file) as f:
307+
names += [
308+
line.split("#", 1)[0].strip()
309+
for line in f
310+
if line.split("#", 1)[0].strip()
311+
]
312+
check_package_list(names, create_issues=args.create_issues)
313+
return
314+
239315
print("Fetching top-packages dataset …")
240316
dataset = fetch_json(TOP_PACKAGES_URL)
241317
all_packages = dataset["rows"]

0 commit comments

Comments
 (0)