From 0dab8f47068ad4a1e3956f1d26c5f792b3563539 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Wed, 21 Oct 2026 05:29:42 +0200 Subject: [PATCH] fix: credit file readers through the data trees FileConsumers resolved profile entries without the data directory registry the builder uses. Dolphin's hashless codehandler.bin then took Dolphin-MMJR's copy by name, and the site listed Dolphin and Triforce as its readers while every pack serves data/dolphin-sys. blueMSX's RS232.ROM and MSX2P.rom were credited to bios/ copies the same way. The registry is now read by default, as the builder reads it. With it, bundled_only.py --strict (pipeline step 4d) names bios/Other/dolphin-mmjr/codehandler.bin: only dolphin-mmjr's bundled entry, which already carries its sha1 and size, reaches that copy. --- scripts/cross_reference.py | 18 ++++++++++++++++-- tests/test_file_consumers.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/scripts/cross_reference.py b/scripts/cross_reference.py index 5ba4cc83..171ea85d 100644 --- a/scripts/cross_reference.py +++ b/scripts/cross_reference.py @@ -30,6 +30,7 @@ from common import ( get_mame_clone_map, list_emulator_profiles, list_registered_platforms, + load_data_dir_registry, load_database, load_emulator_profiles, load_platform_config, @@ -325,9 +326,21 @@ class FileConsumers: file by the evidence the pack uses, so a homonym is nobody's file. """ - def __init__(self, db: dict, zip_contents: dict | None = None) -> None: + def __init__( + self, db: dict, zip_contents: dict | None = None, + data_dir_registry: dict | None = None, + ) -> None: self._db = db self._zip_contents = zip_contents + # The builder resolves with the data trees: Dolphin's codehandler.bin + # comes from data/dolphin-sys, and without them the name step gave it + # Dolphin-MMJR's copy, which the site then said Dolphin reads. + self._data_dir_registry = ( + data_dir_registry if data_dir_registry is not None + else load_data_dir_registry( + str(Path(__file__).resolve().parent.parent / DEFAULT_PLATFORMS_DIR) + ) + ) self._sha1_by_path = { path: sha1 for sha1, entry in db.get("files", {}).items() @@ -357,7 +370,8 @@ class FileConsumers: if owner: entry = {**entry, "source_profile": owner} path, status = resolve_local_file( - entry, self._db, self._zip_contents, dest_hint=dest + entry, self._db, self._zip_contents, dest_hint=dest, + data_dir_registry=self._data_dir_registry, ) if not path or status in ("not_found", "hash_mismatch"): return None diff --git a/tests/test_file_consumers.py b/tests/test_file_consumers.py index 3ef7a56c..94b23f13 100644 --- a/tests/test_file_consumers.py +++ b/tests/test_file_consumers.py @@ -83,6 +83,40 @@ class ReadersResolve(unittest.TestCase): self.assertNotIn("ioquake3", et) +class ReadersFollowTheDataTrees(unittest.TestCase): + """Dolphin names codehandler.bin without a hash. The pack takes it from + data/dolphin-sys, and the site credited Dolphin and Triforce with the + Dolphin-MMJR copy, another revision, because the consumers resolved + without the data trees. Reads the repository.""" + + def test_dolphin_does_not_read_the_mmjr_copy(self): + import os + + from common import load_database, load_emulator_profiles + + if not (REPO_ROOT / "database.json").is_file() or not ( + REPO_ROOT / "data" / "dolphin-sys" / "codehandler.bin" + ).is_file(): + self.skipTest("database.json or data/dolphin-sys is absent") + previous = os.getcwd() + os.chdir(REPO_ROOT) + try: + db = load_database("database.json") + profiles = load_emulator_profiles("emulators") + consumers = FileConsumers(db) + consumers.add_emulators({"dolphin": profiles["dolphin"]}) + finally: + os.chdir(previous) + mmjr = next( + (sha1 for sha1, entry in db["files"].items() + if entry["path"] == "bios/Other/dolphin-mmjr/codehandler.bin"), + None, + ) + if mmjr is None: + self.skipTest("the Dolphin-MMJR copy is not collected") + self.assertNotIn("dolphin", consumers.emulators.get(mmjr, set())) + + def tearDownModule(): _TMP.cleanup()