d331eb26d1
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
55 lines
2.0 KiB
Python
55 lines
2.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""REUSE.md refs check — staleness defense for the per-repo reuse maps.
|
|
|
|
Usage: python scripts/reuse_refs_check.py <repo-root> [<repo-root> ...]
|
|
|
|
For each repo root given, parses <root>/REUSE.md, extracts every cited file path
|
|
(*.go, *.py, *.html, *.css, *.yml, *.yaml, *.sh) and verifies the file exists in
|
|
the tree. Only slash-containing (repo-relative) tokens are checked — bare filenames
|
|
are conventions, not citations. Prints offending lines; exits non-zero if any cited
|
|
path is missing. Symbols are NOT checked here — those are spot-verified by the
|
|
reviewer at file:line.
|
|
"""
|
|
import io, os, re, sys
|
|
|
|
# path-looking tokens ending in a checked extension; globs (*) are conventions, not refs
|
|
PATH_RE = re.compile(r'[A-Za-z0-9_][A-Za-z0-9_./\-]*/[A-Za-z0-9_./\-]*\.(?:go|py|html|css|yml|yaml|sh)\b')
|
|
|
|
fails = 0
|
|
|
|
|
|
def check_repo(root):
|
|
global fails
|
|
root = os.path.abspath(root)
|
|
reuse = os.path.join(root, "REUSE.md")
|
|
name = os.path.basename(root)
|
|
if not os.path.isfile(reuse):
|
|
print("FAIL [%s]: no REUSE.md at %s" % (name, reuse))
|
|
fails += 1
|
|
return
|
|
seen, missing = set(), 0
|
|
with io.open(reuse, encoding="utf-8") as f:
|
|
for lineno, line in enumerate(f, 1):
|
|
for m in PATH_RE.finditer(line):
|
|
p = m.group(0)
|
|
if "*" in line[max(0, m.start() - 2):m.end() + 2]:
|
|
continue # glob like scripts/*.py — a convention, not a file ref
|
|
if p in seen:
|
|
continue
|
|
seen.add(p)
|
|
if not os.path.isfile(os.path.join(root, p)):
|
|
print("FAIL [%s] line %d: cited path missing: %s" % (name, lineno, p))
|
|
missing += 1
|
|
if missing:
|
|
fails += missing
|
|
else:
|
|
print("OK [%s]: %d cited paths, all exist" % (name, len(seen)))
|
|
|
|
|
|
if len(sys.argv) < 2:
|
|
print(__doc__)
|
|
sys.exit(2)
|
|
for r in sys.argv[1:]:
|
|
check_repo(r)
|
|
sys.exit(1 if fails else 0)
|