fix: name one file per search chain for RetroPie

This commit is contained in:
Abdessamad Derraz committed 2026-10-17 11:54:56 +02:00
1 parent ec4a06e872
commit 27ddd47b20
2 files changed
+65 -1

No files matched your search

+36 -1
View File
@@ -184,6 +184,34 @@ class Exporter(BaseExporter):
names.append(fe.name)
return names
@staticmethod
def _slot_of(fe: NativeFile) -> tuple[str, tuple[str, ...]] | None:
"""The search chain a file belongs to, or None when it is in none.
PicoDrive walks one ranked list per region and loads the first file
it finds: the files of one chain are alternatives, and naming two of
them in an enumeration that reads "requires a, b and c" says both
are needed. A file joins a chain only when its source ranks it and
names its territory.
"""
regions = (fe.truth or {}).get("region") or []
if fe.priority is None or not regions:
return None
return fe.native_system, tuple(sorted(str(r) for r in regions))
@classmethod
def _one_per_slot(cls, candidates: list[NativeFile], filled: set) -> list[NativeFile]:
"""The candidates whose chain the help leaves empty, best first."""
kept: list[NativeFile] = []
for fe in search_order(candidates):
slot = cls._slot_of(fe)
if slot is not None:
if slot in filled:
continue
filled.add(slot)
kept.append(fe)
return kept
@staticmethod
def _required_for(fe: NativeFile, core: str | None) -> bool:
"""Whether the package's own core needs the file.
@@ -290,7 +318,14 @@ class Exporter(BaseExporter):
)
& listed
]
missing = self._in_search_order(candidates)
filled = {
slot
for fe in files
if ({fe.name.lower()}
| {str(a).lower() for a in (fe.native("aliases", []) or [])}) & listed
and (slot := self._slot_of(fe)) is not None
}
missing = self._in_search_order(self._one_per_slot(candidates, filled))
if not missing:
continue
+29
View File
@@ -356,6 +356,35 @@ class SearchOrder(unittest.TestCase):
exporter._in_search_order(candidates), ["ranked.bin", "unranked.bin"]
)
def test_a_region_the_help_already_fills_gets_no_alternative(self):
"""PicoDrive loads the first file of each region's list. RetroPie
names one per region; the export appended three more, which the
sentence reads as three more required files."""
from exporter.baseline import NativeSystem # noqa: PLC0415
def cd(name, region, rank):
return NativeFile(name=name, destination=name, native_system="segacd", truth={
"name": name, "required": True, "md5": "0" * 32, "_cores": ["picodrive"],
"region": [region], "priority": rank})
files = [cd("us_scd2_9306.bin", "north-america", 1),
cd("us_scd1_9210.bin", "north-america", 3),
cd("eu_mcd2_9306.bin", "europe", 1),
cd("eu_mcd1_9210.bin", "europe", 3),
cd("jp_mcd2_921222.bin", "japan", 1),
cd("jp_mcd1_9112.bin", "japan", 2)]
script = ('rp_module_id="lr-picodrive"\nrp_module_help="The Sega CD requires the '
'BIOS files us_scd1_9210.bin, eu_mcd1_9210.bin copied to $biosdir"\n')
exporter = discover_exporters()["retropie"]()
produced = exporter.render(
{"segacd": NativeSystem("segacd", files=files)}, None,
{"scriptmodules/libretrocores/lr-picodrive.sh": script},
)["scriptmodules/libretrocores/lr-picodrive.sh"]
self.assertIn("us_scd1_9210.bin, eu_mcd1_9210.bin and jp_mcd2_921222.bin copied",
produced)
self.assertNotIn("us_scd2_9306", produced)
self.assertNotIn("jp_mcd1_9112", produced)
def test_cores_that_disagree_keep_the_best_rank(self):
"""Nothing is dropped on the rank here, so the best one wins.