diff --git a/scripts/generate_site.py b/scripts/generate_site.py index 2c7ff7c60..c1eff29ed 100644 --- a/scripts/generate_site.py +++ b/scripts/generate_site.py @@ -2834,6 +2834,36 @@ def emulator_file_aliases(files: list[dict], anchors: list[str]) -> list[str]: return aliases +# A commit id: hexadecimal with a letter and a digit, 7 to 40 long. A version +# that holds one (0.8.139-2-g25e1ee2fd5) names no release. +_COMMIT_ID = re.compile( + r"(? dict[str, str]: + """The `core_version` of a profile by build mode ("" when one covers + every build), kept only where it names a release: a number and no + commit id. A commit id of digits only reads as a number, so a run that + starts one of the profile's own pins is one too (supermodel3's + "0.3a-1481545-mm").""" + pins = [str(value).casefold() + for field in ("source_commit", "upstream_commit") + for value in (profile[field].values() if isinstance(profile.get(field), dict) + else [profile.get(field)]) + if value] + + def names_a_commit(value: str) -> bool: + return bool(_COMMIT_ID.search(value)) or any( + pin.startswith(run) for run in re.findall(r"[0-9a-f]{7,40}", value.casefold()) + for pin in pins) + + stated = profile.get("core_version") + pairs = stated.items() if isinstance(stated, dict) else [("", stated)] + versions = {str(mode): str(value or "").strip() for mode, value in pairs} + return {mode: value for mode, value in versions.items() + if re.search(r"[0-9]", value) and not names_a_commit(value)} + + def emulator_structured_data(profile: dict) -> dict: """What an emulator page states, for a reader of its JSON-LD. @@ -2841,27 +2871,26 @@ def emulator_structured_data(profile: dict) -> dict: the core loads, their hashes, the source read or when. """ data: dict = {} - # Every repository the profile reads, each with its own pin: xemu's - # libretro build lives in another repository at another commit, and a - # port's upstream_commit was never published. + # Every repository the profile reads. The source repository carries the + # release the profile describes, never a commit id: a pin is no version. + # The upstream of a port is another code base and states none. + versions = release_versions(profile) about = [] seen: set[str] = set() for field in ("source", "upstream"): urls = profile.get(field) - pins = profile.get(f"{field}_commit") for mode, url in (urls.items() if isinstance(urls, dict) else [("", urls)]): if not url or not str(url).startswith("http") or str(url) in seen: continue seen.add(str(url)) - pin = pins.get(mode) if isinstance(pins, dict) else pins entry = { "@type": "SoftwareSourceCode", "name": str(profile.get("emulator", "")), "codeRepository": str(url), - "description": " ".join(filter(None, [mode, field])), } - if pin: - entry["version"] = str(pin) + version = (versions.get(mode) or versions.get("")) if field == "source" else None + if version: + entry["version"] = version about.append(entry) if about: data["about"] = about[0] if len(about) == 1 else about @@ -3083,6 +3112,10 @@ def decorate_markdown_pages(docs: Path) -> dict[str, str]: }, **PAGE_DATA.get(relative.as_posix(), {}), } + if schema_type == "WebSite": + # The home page is the site: named as the site, part of nothing. + structured["name"] = SITE_NAME + del structured["isPartOf"] target, text = sitestarlight.finalize_page( relative.as_posix(), markdown, level=level, weight=search_weight(relative, level), diff --git a/tests/test_audit_regressions.py b/tests/test_audit_regressions.py index 28c95c2ae..9aad3b0e5 100644 --- a/tests/test_audit_regressions.py +++ b/tests/test_audit_regressions.py @@ -4360,31 +4360,44 @@ class EmulatorPagesStateTheirDataForMachines(unittest.TestCase): data = emulator_structured_data({ "emulator": "DuckStation", "source": "https://github.com/stenzek/duckstation", - "source_commit": "4122fed9", "profiled_date": "2026-03-23", + "source_commit": "4122fed9", "core_version": "v0.1-12070", + "profiled_date": "2026-03-23", "files": [{"name": "scph5501.bin", "md5": "490F666E", "sha1": ["a" * 40]}, {"name": "free.bin"}], }) self.assertEqual(data["about"]["codeRepository"], "https://github.com/stenzek/duckstation") - self.assertEqual(data["about"]["version"], "4122fed9") + # The release the profile describes, never the pin (round 5, 3.5). + self.assertEqual(data["about"]["version"], "v0.1-12070") + self.assertNotIn("description", data["about"]) self.assertEqual(data["dateModified"], "2026-03-23") self.assertEqual(data["hasPart"][0]["identifier"], ["sha1:" + "a" * 40, "md5:490f666e"]) self.assertNotIn("identifier", data["hasPart"][1]) - def test_every_repository_with_its_own_pin(self): - """xemu's libretro build lives in another repository at another - commit, and a port's upstream_commit was never published.""" + def test_every_repository_with_its_own_release(self): + """xemu's libretro build lives in another repository. Each source + repository states the release of its build, a version holding a + commit id states none, and a port's upstream is another code base.""" from scripts.generate_site import emulator_structured_data data = emulator_structured_data({ - "emulator": "xemu", - "source": {"standalone": "https://github.com/xemu-project/xemu", - "libretro": "https://github.com/LibretroAdmin/xemu-libretro"}, + "emulator": "MesenCE", + "source": {"standalone": "https://github.com/nesdev-org/MesenCE", + "libretro": "https://github.com/libretro/MesenCE"}, "source_commit": {"standalone": "f9b14039", "libretro": "d9804db7"}, - "upstream": "https://github.com/mborgerson/xemu", "upstream_commit": "aa11", + "core_version": {"standalone": "2.2.1", "libretro": "2.0.0"}, + "upstream": "https://github.com/SourMesen/Mesen2", "upstream_commit": "aa11", }) self.assertEqual( [(a["codeRepository"].rsplit("/", 1)[1], a.get("version")) for a in data["about"]], - [("xemu", "f9b14039"), ("xemu-libretro", "d9804db7"), ("xemu", "aa11")]) + [("MesenCE", "2.2.1"), ("MesenCE", "2.0.0"), ("Mesen2", None)]) + xemu = emulator_structured_data({ + "emulator": "xemu", + "source": {"standalone": "https://github.com/xemu-project/xemu", + "libretro": "https://github.com/LibretroAdmin/xemu-libretro"}, + "core_version": {"standalone": "0.8.139-2-g25e1ee2fd5", + "libretro": "libretro-experimental"}, + }) + self.assertEqual([a.get("version") for a in xemu["about"]], [None, None])