From 51f3249a7dad4e2e96392d184559069ffe54e0b5 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Sat, 17 Oct 2026 08:27:08 +0200 Subject: [PATCH] fix: give a shared core slot to the pinned claim hypseus-singe asks for gamecontrollerdb.txt by name alone and, first in profile order, took the BIOS root of Batocera, RetroBat and RetroPie with C-Dogs' small table while Solarus pins its own by sha1. A destination two cores claim now goes to the one naming its content. --- scripts/packextras.py | 10 ++++++++++ tests/test_audit_regressions.py | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/scripts/packextras.py b/scripts/packextras.py index 83fe7264..b0475562 100644 --- a/scripts/packextras.py +++ b/scripts/packextras.py @@ -611,6 +611,11 @@ def _collect_emulator_extras( config, emulators_dir, db, emu_profiles, target_cores=target_cores, include_all=include_all, declared_names=yaml_names, ) + # A destination two cores claim goes to the one that names its content: + # hypseus-singe asks for gamecontrollerdb.txt by name alone and took the + # BIOS root before Solarus, which pins its own by sha1. Profile order + # still decides between claims of the same kind. + undeclared = sorted(undeclared, key=lambda u: not _names_content(u)) extras = [] seen_dests: set[str] = set(seen) # Destination -> the extra that took it, to record later claimants on. @@ -762,6 +767,11 @@ def _collect_emulator_extras( return extras +def _names_content(entry: dict) -> bool: + """Whether a report entry declares the bytes it wants, not only a name.""" + return any(entry.get(field) for field in ("sha1", "md5", "sha256", "crc32")) + + def _report_extra(u: dict, name: str, dest: str) -> dict: """The extra a cross-reference entry asks for at its destination.""" extra = { diff --git a/tests/test_audit_regressions.py b/tests/test_audit_regressions.py index ba65e4f5..792be739 100644 --- a/tests/test_audit_regressions.py +++ b/tests/test_audit_regressions.py @@ -2364,6 +2364,32 @@ class AnotherEmulatorsTreeProvesNothing(unittest.TestCase): self.assertFalse([d for d, p in overrides.items() if "/armsx2/" in p]) +class APinnedCoreFileTakesTheSlotFirst(unittest.TestCase): + """hypseus-singe asks for gamecontrollerdb.txt by name and took the BIOS + root of Batocera, RetroBat and RetroPie with C-Dogs' 26 KB table, where + Solarus pins its own by sha1.""" + + def test_the_content_naming_claim_is_placed_first(self): + from unittest import mock + + from scripts import packextras + + undeclared = [ + {"profile": "hypseus", "emulator": "hypseus", "name": "db.txt", + "path": "db.txt", "in_repo": True, "systems": ["a"]}, + {"profile": "solarus", "emulator": "solarus", "name": "db.txt", + "path": "db.txt", "in_repo": True, "systems": ["b"], "sha1": "a" * 40}, + ] + config = {"systems": {}, "base_destination": "bios"} + with mock.patch("verify.find_undeclared_files", return_value=undeclared), \ + mock.patch.object(packextras, "resolve_platform_cores", create=True, + return_value=set()): + extras = packextras._collect_emulator_extras( + config, "emulators", {"files": {}, "indexes": {}}, set(), "bios", {} + ) + self.assertEqual([e["source_profile"] for e in extras][:1], ["solarus"]) + + class TheDatabaseCacheIsWrittenWhole(unittest.TestCase): """A crash while serializing left a truncated db_cache.json behind, and the next run rehashed the whole collection from scratch."""