#!/usr/bin/env python3 """Do the files the docs cite actually exist in the repo? An answer whose evidence is not committed cannot be used by anyone without a disc and an emulator, which is the whole point of the reference data. This walks every markdown file under docs/ and resolves each relative link, reporting the ones that point at nothing. Skips external links (http, mailto) and pure anchors. Reports missing targets and, separately, committed-but-EMPTY files, which are the sneakier failure -- a link that resolves to a zero-byte file looks fine in every listing. doc_link_check.py [docs-root] """ import os, re, sys ROOT = sys.argv[1] if len(sys.argv) > 1 else "docs" LINK = re.compile(r"\[[^\]]*\]\(([^)\s]+)\)") missing, empty, ok = [], [], 0 for dirpath, _dirs, files in os.walk(ROOT): for f in files: if not f.endswith(".md"): continue src = os.path.join(dirpath, f) try: body = open(src, encoding="utf-8").read() except Exception: continue for target in LINK.findall(body): if target.startswith(("http://", "https://", "mailto:", "#")): continue path = os.path.normpath(os.path.join(dirpath, target.split("#")[0])) if not path: continue if not os.path.exists(path): missing.append((src, target)) elif os.path.isfile(path) and os.path.getsize(path) == 0: empty.append((src, target)) else: ok += 1 print(f"{ok} link(s) resolve") if missing: print(f"\n{len(missing)} MISSING target(s):") for s, t in sorted(missing): print(f" {s} -> {t}") if empty: print(f"\n{len(empty)} link(s) resolve to an EMPTY file:") for s, t in sorted(empty): print(f" {s} -> {t}") sys.exit(1 if (missing or empty) else 0)