From dda057f45f64da210a6d3b110c1d98bff90b8824 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Sun, 18 Oct 2026 13:55:06 +0200 Subject: [PATCH] fix: key cross-reference slots by the build's path --- scripts/cross_reference.py | 20 +++++++++++++------- tests/test_standalone_mode.py | 26 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/scripts/cross_reference.py b/scripts/cross_reference.py index 215566b1..1fc0c729 100644 --- a/scripts/cross_reference.py +++ b/scripts/cross_reference.py @@ -453,14 +453,19 @@ def _first_hash(entry: dict) -> str: return "" -def slot_key(f: dict) -> tuple: +def slot_key(f: dict, standalone: bool = False) -> tuple: """The slot a profile entry fills: its entries on one slot are the - versions its code accepts there, and holding any of them fills it.""" + versions its code accepts there, and holding any of them fills it. + + The path is the one the running build reads: b2's standalone build + reads MOS 3.20 and 3.50 from two directories, two slots, while the + entries share a name and no `path:`.""" fname = f.get("name", "") + where = (f.get("standalone_path") if standalone else None) or f.get("path") return ( fname, f.get("archive"), - f.get("path") or fname, + where or fname, f.get("system"), f.get("variant_group"), f.get("mode", "both"), @@ -517,8 +522,8 @@ def _cross_reference_profile( # accepts there (raze's ten DUKE3D.GRP): holding any of them fills the # slot, as verify --emulator credits it. versions: dict[tuple, list[dict]] = {} - for f in emu_files: - versions.setdefault(slot_key(f), []).append(f) + for f, is_standalone in layout_files: + versions.setdefault(slot_key(f, is_standalone), []).append(f) for f, is_standalone in layout_files: fname = f.get("name", "") @@ -530,7 +535,8 @@ def _cross_reference_profile( effective_path = f.get("standalone_path") or f.get("path") or fname else: effective_path = f.get("path") or fname - seen_key = slot_key(f) + slot = slot_key(f, is_standalone) + seen_key = slot if len(layouts) > 1: # One file read at one path by both builds counts once. seen_key = (effective_path.casefold(), seen_key) @@ -613,7 +619,7 @@ def _cross_reference_profile( else: source = next( ( - found for version in versions[seen_key] + found for version in versions[slot] if (found := entry_source(version, index)) is not None ), "missing", diff --git a/tests/test_standalone_mode.py b/tests/test_standalone_mode.py index 720a0db8..5e885c2c 100644 --- a/tests/test_standalone_mode.py +++ b/tests/test_standalone_mode.py @@ -90,5 +90,31 @@ class CrossReferenceReadsTheBuildThePlatformRuns(unittest.TestCase): self.assertEqual(self._gaps(set()), ["both.bin", "libretro.bin"]) + def test_a_platform_running_both_builds(self): + # The dual layout keyed seen files by (path, slot) and then looked + # the pair up in the slot table: KeyError on Batocera's dolphin. + from common import DUAL_MODE_PREFIX + + self.assertEqual( + self._gaps({"dual", DUAL_MODE_PREFIX + "dual"}), + ["both.bin", "libretro.bin", "standalone.bin"], + ) + + def test_standalone_paths_are_separate_slots(self): + # b2 reads MOS 3.20 and 3.50 ROMs under one name from two + # directories: two slots, not two versions of one. + profile = { + "emulator": "B", "type": "standalone", "systems": ["sys"], + "files": [ + {"name": "dfs.rom", "standalone_path": "m128/3.20/dfs.rom"}, + {"name": "dfs.rom", "standalone_path": "m128/3.50/dfs.rom"}, + ], + } + report = cross_reference( + {"b": profile}, {}, {"files": {}, "indexes": {}}, standalone_cores={"b"} + ) + self.assertEqual(len(report["b"]["gap_details"]), 2) + + if __name__ == "__main__": unittest.main()