feat: each citation names the code that asks

A profile that reads a libretro core and the original emulator cited both trees alike, and readers could not tell whether the core or the emulator asked for a file. A cited path now opens with source or upstream, the repository its lines are in. Emulator code a port carries is attributed upstream when the original holds the same value on the cited line.

profile_sync --attribute-refs writes the words from where the lines are found and follows a word already written. The site links each citation to that repository's pin, labels it libretro core or upstream emulator, and says on each file card whose code asks for it. A recale keeps the word, and mame_ref_audit reads the tree it names.
This commit is contained in:
Abdessamad Derraz committed 2026-10-20 05:52:13 +02:00
1 parent adea35e12a
commit dec0fdc163
9 files changed
+306 -21

No files matched your search

+24 -12
View File
@@ -30,7 +30,8 @@ import upstream
from safeparse import yaml_load
from scraper.mame_parser import _MACHINE_MACROS, strip_comments
DRIVER_REF = re.compile(r"^(src/[\w./+-]+):(\d+)$")
# An optional role word names the repository the lines are in.
DRIVER_REF = re.compile(r"^(?:(source|upstream) )?(src/[\w./+-]+):(\d+)$")
@dataclass(frozen=True)
@@ -39,6 +40,10 @@ class Finding:
path: str
cited: int
declared: int
role: str = ""
def ref(self, line: int) -> str:
return f"{self.role} {self.path}:{line}" if self.role else f"{self.path}:{line}"
def declares(line: str, set_name: str) -> bool:
@@ -57,11 +62,14 @@ def audit(
"""Findings, plus counts of refs that agree and of unjudgeable ones."""
with open(os.path.join(emulators_dir, f"{name}.yml"), encoding="utf-8") as handle:
document = yaml_load(handle) or {}
repo = upstream.parse_repo(str(document.get("source") or ""))
pin = str(document.get("source_commit") or "")
if repo is None or not pin:
trees = {
role: (upstream.parse_repo(str(document.get(role) or "")),
str(document.get(f"{role}_commit") or ""))
for role in ("source", "upstream")
}
if trees["source"][0] is None or not trees["source"][1]:
return [], 0, 0
sources: dict[str, list[str] | None] = {}
sources: dict[tuple[str, str], list[str] | None] = {}
findings: list[Finding] = []
agreed = unjudged = 0
for entry in document.get("files", []) or []:
@@ -69,10 +77,14 @@ def audit(
match = DRIVER_REF.match(str(entry.get("source_ref") or ""))
if not (entry_name.endswith(".zip") and match):
continue
path, cited = match.group(1), int(match.group(2))
if path not in sources:
sources[path] = upstream.fetch_file(repo, pin, path, cache_dir, offline)
lines = sources[path]
role, path, cited = match.group(1) or "", match.group(2), int(match.group(3))
repo, pin = trees[role or "source"]
if repo is None or not pin:
unjudged += 1
continue
if (role, path) not in sources:
sources[(role, path)] = upstream.fetch_file(repo, pin, path, cache_dir, offline)
lines = sources[(role, path)]
if lines is None:
continue
set_name = entry_name[:-4]
@@ -85,7 +97,7 @@ def audit(
# declares the name twice and only a reader can choose.
unjudged += 1
continue
findings.append(Finding(set_name, path, cited, found[0]))
findings.append(Finding(set_name, path, cited, found[0], role))
return findings, agreed, unjudged
@@ -97,14 +109,14 @@ def rewrite(name: str, emulators_dir: str, findings: list[Finding]) -> int:
written = 0
for finding in findings:
anchor = f"- name: {finding.set_name}.zip"
old = f'source_ref: "{finding.path}:{finding.cited}"'
old = f'source_ref: "{finding.ref(finding.cited)}"'
start = text.find(anchor)
if start < 0:
continue
at = text.find(old, start)
if at < 0:
continue
new = f'source_ref: "{finding.path}:{finding.declared}"'
new = f'source_ref: "{finding.ref(finding.declared)}"'
text = text[:at] + new + text[at + len(old):]
written += 1
if written: