diff --git a/scripts/generate_site.py b/scripts/generate_site.py index 93b8e63b..8cdda8f9 100644 --- a/scripts/generate_site.py +++ b/scripts/generate_site.py @@ -1764,6 +1764,45 @@ def generate_provenance_page(db: dict, report: dict) -> str: return "\n".join(lines) + "\n" +def _system_file_card(f: dict, consumers: FileConsumers) -> list[str]: + """One file of a system page: hashes, who reads it, its provenance.""" + name = f["name"] + sha1_full = f.get("sha1", "unknown") + md5_full = f.get("md5", "unknown") + size = _fmt_size(f.get("size", 0)) + # Who reads this file, not who reads a file of this name + plats = sorted(consumers.platforms.get(sha1_full, ())) + emus = sorted(consumers.emulators.get(sha1_full, ())) + sha1_short = sha1_full[:12] if sha1_full != "unknown" else "-" + md5_short = md5_full[:12] if md5_full != "unknown" else "-" + + lines = ['
', ""] + lines.append(f'**`{name}`** {size}') + lines.append("") + if "/.variants/" in f.get("path", ""): + lines.append(f"- Stored as: `{f['path'].rsplit('/', 1)[-1]}`") + lines.append(f'- SHA1: `{sha1_short}...`') + lines.append(f'- MD5: `{md5_short}...`') + if plats: + plat_badges = " ".join( + f'[{p}](../platforms/{p}.md)' + for p in plats + ) + lines.append(f"- Platforms: {plat_badges}") + if emus: + lines.append(f"- Emulators: {', '.join(_emulator_link(e, '../') for e in emus)}") + provenance = f.get("provenance", {}) + if provenance: + prov_badges = " ".join( + f'' + f"[{_PROVENANCE_LABELS.get(s, s)}](../provenance.md#{s})" + for s, data in sorted(provenance.items()) + ) + lines.append(f"- Verified dump: {prov_badges}") + lines.extend(["", "
", ""]) + return lines + + def generate_system_page( manufacturer: str, consoles: dict[str, list], @@ -1785,70 +1824,18 @@ def generate_system_page( variant_files = [f for f in files if "/.variants/" in f["path"]] for f in sorted(main_files, key=lambda x: x["name"]): - name = f["name"] - sha1_full = f.get("sha1", "unknown") - md5_full = f.get("md5", "unknown") - size = _fmt_size(f.get("size", 0)) - - # Who reads this file, not who reads a file of this name - plats = sorted(consumers.platforms.get(sha1_full, ())) - emus = sorted(consumers.emulators.get(sha1_full, ())) - - # Truncated hashes for readability - sha1_short = sha1_full[:12] if sha1_full != "unknown" else "-" - md5_short = md5_full[:12] if md5_full != "unknown" else "-" - - lines.append('
') - lines.append("") - lines.append( - f'**`{name}`** ' - f'{size}' - ) - lines.append("") - lines.append( - f'- SHA1: `{sha1_short}...`' - ) - lines.append( - f'- MD5: `{md5_short}...`' - ) - if plats: - plat_badges = " ".join( - f'' - f"[{p}](../platforms/{p}.md)" - for p in plats - ) - lines.append(f"- Platforms: {plat_badges}") - if emus: - emu_links = [_emulator_link(e, "../") for e in emus] - lines.append(f"- Emulators: {', '.join(emu_links)}") - provenance = f.get("provenance", {}) - if provenance: - prov_badges = " ".join( - f'' - f"[{_PROVENANCE_LABELS.get(s, s)}](../provenance.md#{s})" - for s, data in sorted(provenance.items()) - ) - lines.append(f"- Verified dump: {prov_badges}") - lines.append("") - lines.append("
") - lines.append("") + lines.extend(_system_file_card(f, consumers)) if variant_files: - lines.append( - f'??? note "Variants ({len(variant_files)})"' - ) + # A variant gets the same card as a primary: the revision a + # platform pins is the one a reader comes to find, and showed as + # a name and a truncated MD5, nothing said who pins it. + lines.append(f'??? note "Variants ({len(variant_files)})"') lines.append("") - for v in sorted(variant_files, key=lambda x: x["name"]): - vname = v["name"] - vmd5 = v.get("md5", "unknown") - vmd5_short = vmd5[:12] if vmd5 != "unknown" else "-" - lines.append( - f' - `{vname}` ' - f'' - f"MD5: {vmd5_short}..." + for v in sorted(variant_files, key=lambda x: (x["name"], x["path"])): + lines.extend( + f" {line}" if line else "" + for line in _system_file_card(v, consumers) ) lines.append("") diff --git a/tests/test_site_exports.py b/tests/test_site_exports.py index 968f0550..bfc12912 100644 --- a/tests/test_site_exports.py +++ b/tests/test_site_exports.py @@ -330,5 +330,32 @@ class APlatformPageSaysWhereEachFileGoes(unittest.TestCase): self.assertIn(f"- `IPL.bin` at `dolphin-emu/Sys/GC/{region}/IPL.bin` - OK", "\n".join(lines)) + +class AVariantShowsWhoPinsIt(unittest.TestCase): + """A .variants/ file showed a name and a truncated MD5: the advision.zip + Batocera and RetroBat pin named no platform.""" + + def test_the_variant_card_names_its_readers(self): + import types # noqa: PLC0415 + + import generate_site # noqa: PLC0415 + + primary = {"name": "advision.zip", "path": "bios/Entex/Adventure Vision/advision.zip", + "sha1": "a" * 40, "md5": "b" * 32, "size": 3000} + variant = {"name": "advision.zip", + "path": "bios/Entex/Adventure Vision/.variants/advision.zip.1c086064", + "sha1": "c" * 40, "md5": "1c086064" + "0" * 24, "size": 3000, + "provenance": {"tosec": {"name": "x"}}} + consumers = types.SimpleNamespace( + platforms={"c" * 40: {"batocera", "retrobat"}}, emulators={"a" * 40: {"mame"}}) + page = generate_site.generate_system_page( + "Entex", {"Adventure Vision": [primary, variant]}, consumers) + block = page[page.index('??? note "Variants (1)"'):] + self.assertIn(" - Stored as: `advision.zip.1c086064`", block) + self.assertIn("[batocera](../platforms/batocera.md)", block) + self.assertIn("[retrobat](../platforms/retrobat.md)", block) + self.assertIn('title="' + "c" * 40 + '"', block) + self.assertIn("Verified dump", block) + if __name__ == "__main__": unittest.main()