From ba36d9586f0d7d938e5a0e0eecd28f7f159674f0 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Sun, 18 Oct 2026 09:53:44 +0200 Subject: [PATCH] fix: print full hashes on collection cards --- scripts/generate_site.py | 22 +++++++--------------- scripts/profile_sync.py | 2 +- tests/test_audit_regressions.py | 17 +++++++++++++++++ tests/test_site_exports.py | 2 +- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/scripts/generate_site.py b/scripts/generate_site.py index 62cac939..7b95ce5e 100644 --- a/scripts/generate_site.py +++ b/scripts/generate_site.py @@ -1492,7 +1492,6 @@ def generate_platform_page( hash_type = config.get("hash_type", "") base_dest = config.get("base_destination", "") - pct_val = cov["present"] / cov["total"] * 100 if cov["total"] else 0 mode_badge = ( "rb-badge-success" if reads_file_contents(mode) else "rb-badge-info" ) @@ -1899,8 +1898,6 @@ def _system_file_card(f: dict, consumers: FileConsumers) -> list[str]: # 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 "-" anchor = f"sha1-{sha1_full[:12]}" if sha1_full != "unknown" else "" id_attr = f' id="{anchor}"' if anchor else "" @@ -1913,8 +1910,13 @@ def _system_file_card(f: dict, consumers: FileConsumers) -> list[str]: # get it: a user missing scph5501.bin found the reference and no way # to the bytes. lines.append(f"- Collection path: `{f['path']}` ([download]({_fetch_url(f['path'])}))") - lines.append(f'- SHA1: `{sha1_short}...`') - lines.append(f'- MD5: `{md5_short}...`') + # Every hash in full: the site search indexes text, not a title + # attribute, so a pasted md5 or crc32 (what clrmamepro, RomVault or an + # emulator log prints) found nothing behind a 12-character prefix. + for label, value in (("SHA1", sha1_full), ("MD5", md5_full), + ("CRC32", f.get("crc32")), ("SHA256", f.get("sha256"))): + if value and value != "unknown": + lines.append(f'- {label}: `{value}`') if plats: plat_badges = " ".join( f'[{p}](../platforms/{p}.md)' @@ -2187,14 +2189,10 @@ def _render_emulator_file( required = f.get("required", False) in_repo = _file_available(f) source_ref = f.get("source_ref", "") - mode = f.get("mode", "") - hle = f.get("hle_fallback", False) aliases = f.get("aliases", []) - category = f.get("category", "") validation = f.get("validation", []) size = f.get("size") fnote = f.get("note", f.get("notes", "")) - storage = f.get("storage", "") fmd5 = f.get("md5", "") fsha1 = f.get("sha1", "") fcrc32 = f.get("crc32", "") @@ -2203,19 +2201,13 @@ def _render_emulator_file( fmin = f.get("min_size") fmax = f.get("max_size") desc = f.get("description", "") - region = f.get("region", "") - archive = f.get("archive", "") fpath = f.get("path", "") fsystem = f.get("system", "") priority = f.get("priority") fast_boot = f.get("fast_boot") - bundled = f.get("bundled", False) - embedded = f.get("embedded", False) - has_builtin = f.get("has_builtin", False) contents = f.get("contents", []) config_key = f.get("config_key", "") dest = f.get("dest", f.get("destination", "")) - ftype = f.get("type", "") fpattern = f.get("pattern", "") region_check = f.get("region_check") size_note = f.get("size_note", "") diff --git a/scripts/profile_sync.py b/scripts/profile_sync.py index 7edce262..6e1baac3 100644 --- a/scripts/profile_sync.py +++ b/scripts/profile_sync.py @@ -1609,7 +1609,7 @@ def build_report( try: views = select_views(profile, cache_dir, offline) - except upstream.GoneError as exc: + except upstream.GoneError: if stated_gone: # The profile says the forge is gone and the forge agrees. That is # a recorded fact, not an open problem: the refs describe the last diff --git a/tests/test_audit_regressions.py b/tests/test_audit_regressions.py index 09e6aa40..3f18cbc6 100644 --- a/tests/test_audit_regressions.py +++ b/tests/test_audit_regressions.py @@ -4534,5 +4534,22 @@ class CollectionCardsSayWhereToGetTheFile(unittest.TestCase): )) + +class CollectionCardsCarryFullHashes(unittest.TestCase): + """A pasted md5 or crc32 found nothing: cards showed 12 characters of + SHA1 and MD5 (the rest in a title the search does not index) and no + CRC32 or SHA256.""" + + def test_every_hash_in_full(self): + from scripts.generate_site import FileConsumers, _system_file_card + + entry = {"name": "DUKE.RTS", "path": "bios/x/DUKE.RTS", "size": 10, + "sha1": "a" * 40, "md5": "9d29f9673bbdb56068acf7645c13749c", + "crc32": "504086c1", "sha256": "b" * 64} + text = "\n".join(_system_file_card(entry, FileConsumers({}, {}))) + for value in (entry["sha1"], entry["md5"], entry["crc32"], entry["sha256"]): + self.assertIn(f"`{value}`", text) + + if __name__ == "__main__": unittest.main() diff --git a/tests/test_site_exports.py b/tests/test_site_exports.py index 9ec5f5ed..48629e11 100644 --- a/tests/test_site_exports.py +++ b/tests/test_site_exports.py @@ -354,7 +354,7 @@ class AVariantShowsWhoPinsIt(unittest.TestCase): self.assertIn(" - Collection path: `bios/Entex/Adventure Vision/.variants/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('`' + "c" * 40 + '`', block) self.assertIn("Verified dump", block) if __name__ == "__main__":