From 6453a96d47d7acbb77643d97ae26541c36e4ab9b Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Sun, 4 Oct 2026 17:47:51 +0200 Subject: [PATCH] feat: read retropie version from its setup script --- platforms/retropie.yml | 1 + scripts/scraper/retropie_scraper.py | 26 +++++++++++++++++++++----- tests/test_scraper_contract.py | 22 ++++++++++++++++++++++ 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/platforms/retropie.yml b/platforms/retropie.yml index 27159962..50a888a4 100644 --- a/platforms/retropie.yml +++ b/platforms/retropie.yml @@ -1,5 +1,6 @@ inherits: retroarch platform: RetroPie +version: 4.8.12 homepage: "https://retropie.org.uk" source: "https://codeload.github.com/RetroPie/RetroPie-Setup/tar.gz/refs/heads/master" base_destination: BIOS diff --git a/scripts/scraper/retropie_scraper.py b/scripts/scraper/retropie_scraper.py index 9a090cca..5f49d7b9 100644 --- a/scripts/scraper/retropie_scraper.py +++ b/scripts/scraper/retropie_scraper.py @@ -39,6 +39,10 @@ GITHUB_REPO = "RetroPie/RetroPie-Setup" MAX_ARCHIVE = 64 * 1024 * 1024 _MODULE_ID = re.compile(r'^rp_module_id="([^"]+)"', re.MULTILINE) +# RetroPie updates in place from master, so its release tags stop at the last +# SD image. The version a user runs is the one this script declares. +_VERSION_FILE = "retropie_packages.sh" +_VERSION = re.compile(r'^__version="([^"]+)"', re.MULTILINE) # Sections RetroPie does not build as emulators: setup helpers, themes, # drivers and the like carry no core. _PACKAGE_DIRS = ("emulators", "libretrocores", "ports") @@ -50,6 +54,7 @@ class Scraper(BaseScraper): def __init__(self, url: str = SOURCE_URL): super().__init__(url=url) self._modules: list[str] | None = None + self._version = "" def _fetch_archive(self) -> bytes: request = urllib.request.Request( @@ -77,16 +82,24 @@ class Scraper(BaseScraper): continue relative = member.name.split("/", 1)[-1] parts = relative.split("/") - if len(parts) != 3 or parts[0] != "scriptmodules": - continue - if parts[1] not in _PACKAGE_DIRS: + is_version_file = relative == _VERSION_FILE + is_package = ( + len(parts) == 3 + and parts[0] == "scriptmodules" + and parts[1] in _PACKAGE_DIRS + ) + if not (is_version_file or is_package): continue handle = archive.extractfile(member) if handle is None: continue text = handle.read().decode("utf-8", errors="replace") - match = _MODULE_ID.search(text) - if match: + match = (_VERSION if is_version_file else _MODULE_ID).search(text) + if not match: + continue + if is_version_file: + self._version = match.group(1) + else: found.add(match.group(1)) self._modules = sorted(found) @@ -114,10 +127,13 @@ class Scraper(BaseScraper): # A libretro package is lr-; a standalone package is named # after the emulator itself. cores = sorted({module.removeprefix("lr-") for module in self.module_ids()}) + if not self._version: + raise ValueError(f"{self.url}: no __version in {_VERSION_FILE}") return { "inherits": "retroarch", "platform": "RetroPie", + "version": self._version, "homepage": "https://retropie.org.uk", "source": SOURCE_URL, "base_destination": "BIOS", diff --git a/tests/test_scraper_contract.py b/tests/test_scraper_contract.py index 0e10dbe9..36a45514 100644 --- a/tests/test_scraper_contract.py +++ b/tests/test_scraper_contract.py @@ -165,6 +165,7 @@ class RetroPiePackageList(unittest.TestCase): def test_the_core_list_drops_the_libretro_prefix(self): scraper = self._scraper( { + "retropie_packages.sh": '__version="4.8.12"\n', "scriptmodules/libretrocores/lr-mgba.sh": 'rp_module_id="lr-mgba"\n', "scriptmodules/emulators/openmsx.sh": 'rp_module_id="openmsx"\n', } @@ -174,6 +175,27 @@ class RetroPiePackageList(unittest.TestCase): self.assertEqual(config["inherits"], "retroarch") self.assertEqual(config["base_destination"], "BIOS") + def test_the_version_is_the_one_the_setup_script_declares(self): + scraper = self._scraper( + { + "retropie_packages.sh": '#!/bin/bash\n__version="4.8.12"\n', + "scriptmodules/libretrocores/lr-mgba.sh": 'rp_module_id="lr-mgba"\n', + } + ) + self.assertEqual(scraper.generate_platform_yaml()["version"], "4.8.12") + + def test_a_version_assigned_elsewhere_is_not_the_setup_version(self): + """Only the top-level retropie_packages.sh speaks for the release.""" + scraper = self._scraper( + { + "scriptmodules/emulators/openmsx.sh": ( + 'rp_module_id="openmsx"\n__version="1.0"\n' + ), + } + ) + with self.assertRaises(ValueError): + scraper.generate_platform_yaml() + def test_no_requirement_is_invented_from_prose(self): """RetroPie names BIOS in prose, without a hash to transcribe.""" scraper = self._scraper(