Files
felhom.eu/scripts/reuse_refs_check.py
T

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)