diff --git a/scripts/exporter/recalbox_exporter.py b/scripts/exporter/recalbox_exporter.py index 676a30fa..b85ccf9f 100644 --- a/scripts/exporter/recalbox_exporter.py +++ b/scripts/exporter/recalbox_exporter.py @@ -52,12 +52,15 @@ class Exporter(BaseExporter): def native_sources() -> dict[str, str]: return {"es_bios.xml": SOURCE_URL, "es_bios.xsd": SCHEMA_URL} - def _path(self, fe: NativeFile, native_id: str) -> str: + def _path(self, fe: NativeFile) -> str: """The path Recalbox reads, pipe-joined when it accepts several. A path Recalbox already states is reproduced exactly: several of its entries sit at the BIOS root with no directory at all, and prefixing - them with the system would point the frontend somewhere else. + them with the system would point the frontend somewhere else. An + addition goes where the core reads it, relative to the BIOS directory + Recalbox gives its cores: DuckStation reads scph5000.bin at the root, + not under psx/. """ if fe.platform is not None: path = str(fe.platform.get("destination") or fe.name) @@ -65,11 +68,10 @@ class Exporter(BaseExporter): if alternatives: return "|".join([path, *[str(a) for a in alternatives]]) return path - dest = fe.destination or fe.name - return dest if "/" in dest else f"{native_id}/{dest}" + return fe.destination or fe.name def _bios_element(self, fe: NativeFile, native_id: str) -> str: - attrs = [f"path={quoteattr(self._path(fe, native_id))}"] + attrs = [f"path={quoteattr(self._path(fe))}"] attrs.append(f'md5={quoteattr(",".join(fe.hashes("md5")))}') attrs.append(f'core={quoteattr(",".join(fe.cores()))}') @@ -162,6 +164,6 @@ class Exporter(BaseExporter): for fe in system.files: if not self.writable(fe): continue - if self._path(fe, system.native_id).casefold() not in exported: + if self._path(fe).casefold() not in exported: issues.append(f"absent: {system.native_id}/{fe.name}") return issues diff --git a/tests/test_exporters.py b/tests/test_exporters.py index d98a04ac..f79fa884 100644 --- a/tests/test_exporters.py +++ b/tests/test_exporters.py @@ -574,6 +574,22 @@ class RecalboxExport(unittest.TestCase): exporter, systems, produced = self._render() self.assertEqual(exporter.validate(systems, produced), []) + def test_an_addition_goes_where_the_core_reads_it(self): + """DuckStation reads scph5000.bin at the BIOS root; the export wrote + psx/scph5000.bin, a path no core opens.""" + import copy # noqa: PLC0415 + + truth = copy.deepcopy(TRUTH) + truth["systems"]["sony-playstation"]["files"].append({ + "name": "scph5000.bin", "md5": "57a06303dfa9cf9351222dfcbb4a29d9", + "size": 524288, "required": False, "_cores": ["duckstation"], + }) + systems, report = build_native_model(truth, SCRAPED) + produced = discover_exporters()["recalbox"]().render(systems, report, {}, None) + paths = {e.get("path") for e in ET.fromstring(produced["es_bios.xml"]).iter("bios")} + self.assertIn("scph5000.bin", paths) + self.assertNotIn("psx/scph5000.bin", paths) + def test_a_truncated_export_is_reported(self): exporter, systems, _ = self._render() empty = {