From 0d5911f61422d6d3f574fee47e6f347c535b17cd Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Thu, 5 Nov 2026 12:12:03 +0100 Subject: [PATCH] fix: name only the platform's cores as readers --- install.ps1 | 2 +- install.py | 27 ++++++++++++++++++++++++--- install.sh | 2 +- install/launchers/index.json | 16 ++++++++-------- tests/test_install.py | 22 ++++++++++++++++++++++ 5 files changed, 56 insertions(+), 13 deletions(-) diff --git a/install.ps1 b/install.ps1 index 1c80b3ab1..d887d5509 100644 --- a/install.ps1 +++ b/install.ps1 @@ -16,7 +16,7 @@ # and Invoke-WebRequest throws on a cut transfer before the hash is read: # the site's build rewrites this line there (scripts/sitebootstrap.py). $mismatchAdvice = "The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that." - $defaultInstallSha256 = "3eb409c23f487f8b150c02591a33dbd2ea09343516daa388524c1dc66f860ebf" + $defaultInstallSha256 = "d3bfabb88e93d8ddf991965cd69929e73b0a254550f8f4c86a11ad34fe710a0b" $maximumInstallerBytes = 2MB $installerExit = 0 $installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null } diff --git a/install.py b/install.py index 00d54382b..c31c9288f 100644 --- a/install.py +++ b/install.py @@ -11832,15 +11832,36 @@ def _copies(entry: dict) -> list[dict]: *entry.get("declared_choices", [])] +# id(manifest) -> (manifest, the cores its entries name), read once per list. +_LISTED_CORES: dict[int, tuple[dict, frozenset]] = {} + + +def _listed_cores(manifest: dict) -> frozenset: + """Every core a copy of the list's entries names: the platform's own. + + system_cores reaches every profile, the target rule needing the cores off + the platform too, and the "read by" line named Recalbox's mame0258 on + Batocera and BizHawk on RetroArch. + """ + cached = _LISTED_CORES.get(id(manifest)) + if cached is None or cached[0] is not manifest: + cores = frozenset( + core for entry in [*manifest.get("files", []), *manifest.get("omitted_files", [])] + for copy in _copies(entry) for core in copy.get("cores") or []) + cached = _LISTED_CORES[id(manifest)] = (manifest, cores) + return cached[1] + + def readers(entry: dict, manifest: dict) -> list[str]: - """The cores that open an entry: as its copies name them, else every core - the platform runs for its systems.""" + """The cores that open an entry: as its copies name them, else the cores + of its systems that the platform's own list names.""" named = sorted({core for copy in _copies(entry) for core in copy.get("cores") or []}) if named: return named system_cores = manifest.get("system_cores") or {} + listed = _listed_cores(manifest) return sorted({core for system in entry_systems(entry) - for core in system_cores.get(system, [])}) + for core in system_cores.get(system, []) if core in listed}) def opened_line(entry: dict, manifest: dict, bios_path: Path) -> str: diff --git a/install.sh b/install.sh index f6681af45..86584bdd3 100755 --- a/install.sh +++ b/install.sh @@ -23,7 +23,7 @@ DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/ins # curl or wget stop on a cut transfer before the hash is read: the site's # build rewrites this line there (scripts/sitebootstrap.py). MISMATCH_ADVICE="The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that." -DEFAULT_INSTALL_SHA256="3eb409c23f487f8b150c02591a33dbd2ea09343516daa388524c1dc66f860ebf" +DEFAULT_INSTALL_SHA256="d3bfabb88e93d8ddf991965cd69929e73b0a254550f8f4c86a11ad34fe710a0b" MAX_INSTALLER_BYTES=2097152 cleanup() { diff --git a/install/launchers/index.json b/install/launchers/index.json index 4c9547932..b34898f37 100644 --- a/install/launchers/index.json +++ b/install/launchers/index.json @@ -27,8 +27,8 @@ { "dest": "roms/ports/retrobios/install.py", "repo_path": "install.py", - "size": 1085228, - "sha256": "3eb409c23f487f8b150c02591a33dbd2ea09343516daa388524c1dc66f860ebf", + "size": 1086137, + "sha256": "d3bfabb88e93d8ddf991965cd69929e73b0a254550f8f4c86a11ad34fe710a0b", "executable": false }, { @@ -71,8 +71,8 @@ "muos": { "archive": { "dest": "ARCHIVE/RetroBIOS.muxapp", - "size": 1138855, - "sha256": "373aebd78e83ec88a29e4a14a13c6be8f77d40c2b2f8834543bb40a8c254ec95" + "size": 1139764, + "sha256": "f9b58890f89971a8c0b9850ece3d132955cbc4823230e59a9224f04305055fba" }, "members": [ { @@ -92,8 +92,8 @@ { "name": "RetroBIOS/install.py", "repo_path": "install.py", - "size": 1085228, - "sha256": "3eb409c23f487f8b150c02591a33dbd2ea09343516daa388524c1dc66f860ebf", + "size": 1086137, + "sha256": "d3bfabb88e93d8ddf991965cd69929e73b0a254550f8f4c86a11ad34fe710a0b", "executable": false }, { @@ -166,8 +166,8 @@ { "dest": ".config/modules/retrobios/install.py", "repo_path": "install.py", - "size": 1085228, - "sha256": "3eb409c23f487f8b150c02591a33dbd2ea09343516daa388524c1dc66f860ebf", + "size": 1086137, + "sha256": "d3bfabb88e93d8ddf991965cd69929e73b0a254550f8f4c86a11ad34fe710a0b", "executable": false }, { diff --git a/tests/test_install.py b/tests/test_install.py index 6fb058ad4..f155ebaeb 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -4397,6 +4397,28 @@ class AQuestionLeftWithCtrlDOrCtrlCIsAStop(unittest.TestCase): self.assertIn("Stopped", out) +class ReadersAreThePlatformsCores(unittest.TestCase): + """--check said bbcb.zip is "read by clk, mame, mame0258, mame0278" on + Batocera: system_cores reaches every profile, Recalbox's builds too.""" + + def test_an_off_platform_core_is_not_named(self): + manifest = { + "system_cores": {"bbc": ["clk", "mame", "mame0258"]}, + "files": [{"dest": "bbcb.zip", "systems": ["bbc"], "cores": None}, + {"dest": "other.rom", "systems": ["x"], "cores": ["clk", "mame"]}], + } + self.assertEqual(install.readers(manifest["files"][0], manifest), ["clk", "mame"]) + + def test_on_the_real_lists(self): + for plat, dest, absent in (("batocera", "bbcb.zip", "mame0258"), + ("retroarch", "prboom.wad", "bizhawk")): + manifest = json.loads((REPO_ROOT / "install" / f"{plat}.json").read_text()) + [entry] = [e for e in manifest["files"] + manifest["omitted_files"] + if e["dest"] == dest] + with self.subTest(platform=plat): + self.assertNotIn(absent, install.readers(entry, manifest)) + + class WhatTheCollectionLacksSaysForWhom(unittest.TestCase): """Required files the installer cannot supply were listed by bare name: DARK.GOB, Data.rsdk, ... and 69 more, with no system and no emulator."""