From 6427e46e2575b702280efcb7fca939b73bf09887 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Fri, 6 Nov 2026 03:59:07 +0100 Subject: [PATCH] fix: an empty or HTML original fails the export fetch checked archives only, so a System.dat served as an HTML page with 200, or a 0-byte cache, reached render() as a file with no entries. System.dat, es_bios.xml, RetroBat and RomM then rebuilt the platform's file from our data and reported OK. Such an original is now refused, before it is cached and when read from the cache, and a format that needs its original fails when none was read. --- scripts/export_native.py | 25 +++++++++++++++++++++++-- tests/test_exporters.py | 22 ++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/scripts/export_native.py b/scripts/export_native.py index 6a1330a95..42d529eba 100644 --- a/scripts/export_native.py +++ b/scripts/export_native.py @@ -105,6 +105,25 @@ def _read_archive(unpack: Callable[[bytes], dict[str, str]], payload: bytes) -> ) from exc +def _read_text(payload: bytes) -> str: + """A text original, refused when it cannot be the platform's file. + + An empty body or an HTML error page served with 200 parsed as a file + with no entries, and four exporters rebuilt the platform's file from our + data alone and said OK: libretro's quoted names and Recalbox's comments + were gone. + """ + text = payload.decode("utf-8", errors="replace") + head = text.lstrip()[:64].lower() + if not head: + raise OriginalUnreadable("empty file: --refresh-cache downloads it again") + if head.startswith(("Too Many Requests", + "\n"): + with self.subTest(body=body): + url = self._upstream("served.txt", body) + originals, missing = collect_originals( + _OneFileExporter(url), {}, self.cache, True, refresh=True + ) + self.assertEqual(originals, {}) + self.assertEqual(len(missing), 1) + cached = self.cache / "plat" / "list.txt" + cached.parent.mkdir(parents=True, exist_ok=True) + cached.write_text(body, encoding="utf-8") + _, missing = collect_originals( + _OneFileExporter(url), {}, self.cache, False + ) + self.assertEqual(len(missing), 1) + cached.unlink() + def test_offline_serves_what_is_cached_and_names_what_is_not(self): url = self._upstream("v1.txt", "one") _, missing = collect_originals(_OneFileExporter(url), {}, self.cache, False)