From f6de9a0ae304de2950770f79727d00db1fd2fb69 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Thu, 5 Nov 2026 12:07:25 +0100 Subject: [PATCH] feat: answer ES-DE, LaunchBox and Android by name --- install.ps1 | 2 +- install.py | 17 ++++++++++++++++- install.sh | 2 +- install/launchers/index.json | 16 ++++++++-------- tests/test_install.py | 16 +++++++++++++++- wiki/installer.md | 2 +- 6 files changed, 42 insertions(+), 13 deletions(-) diff --git a/install.ps1 b/install.ps1 index 3c579f68a..ec3802e36 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 = "08be74d479990f072bd16033f258108a583b34baddfd75d9d9be11f23ae77dac" + $defaultInstallSha256 = "ca1c3c0d721787ee0fd9ab750839893d64f9313885dde6c1f88c5174d4281ce0" $maximumInstallerBytes = 2MB $installerExit = 0 $installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null } diff --git a/install.py b/install.py index a3a6e48aa..4b3be9c4d 100644 --- a/install.py +++ b/install.py @@ -3079,6 +3079,12 @@ def refuse_name(platform: str, *lines: str) -> NoReturn: sys.exit(2) +# Frontends and systems that keep no BIOS folder of their own: each +# emulator they start reads its own, which a run without --platform finds. +# --platform es-de was "Unknown platform", the answer left unsaid. +_NO_BIOS_FOLDER = ("ES-DE", "LaunchBox", "Android") + + def normalize_platform(name: str, say: bool = True) -> str: """Return the canonical platform id for user-supplied input. @@ -3098,6 +3104,11 @@ def normalize_platform(name: str, say: bool = True) -> str: print(f" {rule.name} gets the {display_name(rule.manifest)} file list: " f"--platform {rule.manifest}.") return rule.manifest + for frontend in _NO_BIOS_FOLDER: + if key and key == _name_key(frontend): + refuse_name(name.strip(), f"{frontend} has no BIOS folder of its own: run again " + "without --platform, and the installer fills the folder of each " + "emulator it finds here.") # --list-platforms prints TrimUI with why it gets no folder, and naming # it answered "Unknown platform". for rule in _EMBEDDED_RULES: @@ -3110,7 +3121,8 @@ def normalize_platform(name: str, say: bool = True) -> str: # and the count is the one the listing shows. known = list(AVAILABLE_PLATFORMS) + list(dict.fromkeys( rule.name for rule in _EMBEDDED_RULES - if _name_key(rule.name) not in {_name_key(plat) for plat in AVAILABLE_PLATFORMS})) + if _name_key(rule.name) not in {_name_key(plat) for plat in AVAILABLE_PLATFORMS} + )) + list(_NO_BIOS_FOLDER) refuse_name(name.strip(), f"Unknown platform '{name.strip()}'. " + did_you_mean([name], known, "--list-platforms")) @@ -14490,6 +14502,9 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None: "(--platform takes either name):") for line in _system_lines(): print(f" {line}") + print("\nNo BIOS folder of their own, each emulator reading its own (run without " + "--platform):") + print(f" {', '.join(_NO_BIOS_FOLDER)}") detected = detect_platforms(os_type) if detected: print("\nDetected on this system:") diff --git a/install.sh b/install.sh index 1641ace5d..960eda7b7 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="08be74d479990f072bd16033f258108a583b34baddfd75d9d9be11f23ae77dac" +DEFAULT_INSTALL_SHA256="ca1c3c0d721787ee0fd9ab750839893d64f9313885dde6c1f88c5174d4281ce0" MAX_INSTALLER_BYTES=2097152 cleanup() { diff --git a/install/launchers/index.json b/install/launchers/index.json index 39e53cb3d..eca4e3fc3 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": 1083185, - "sha256": "08be74d479990f072bd16033f258108a583b34baddfd75d9d9be11f23ae77dac", + "size": 1083967, + "sha256": "ca1c3c0d721787ee0fd9ab750839893d64f9313885dde6c1f88c5174d4281ce0", "executable": false }, { @@ -71,8 +71,8 @@ "muos": { "archive": { "dest": "ARCHIVE/RetroBIOS.muxapp", - "size": 1136812, - "sha256": "070626dc9a11addef163495858e5e1ad6808e46522c9570fc4aa2909398b650d" + "size": 1137594, + "sha256": "433caee0f48148c8c25122e3cfa4a6d4577160a2b4ddcf2267415ebd21beb843" }, "members": [ { @@ -92,8 +92,8 @@ { "name": "RetroBIOS/install.py", "repo_path": "install.py", - "size": 1083185, - "sha256": "08be74d479990f072bd16033f258108a583b34baddfd75d9d9be11f23ae77dac", + "size": 1083967, + "sha256": "ca1c3c0d721787ee0fd9ab750839893d64f9313885dde6c1f88c5174d4281ce0", "executable": false }, { @@ -166,8 +166,8 @@ { "dest": ".config/modules/retrobios/install.py", "repo_path": "install.py", - "size": 1083185, - "sha256": "08be74d479990f072bd16033f258108a583b34baddfd75d9d9be11f23ae77dac", + "size": 1083967, + "sha256": "ca1c3c0d721787ee0fd9ab750839893d64f9313885dde6c1f88c5174d4281ce0", "executable": false }, { diff --git a/tests/test_install.py b/tests/test_install.py index 08283b0ee..c42477b7d 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -4020,6 +4020,19 @@ class ATypoGetsTheClosestName(unittest.TestCase): self.assertNotIn("Unknown platform", err.getvalue()) self.assertIn("--platform retroarch --dest FOLDER", err.getvalue()) + def test_a_frontend_without_a_bios_folder_says_what_to_do(self): + """ES-DE, LaunchBox and Android have no BIOS folder: each emulator + reads its own, and --platform es-de was "Unknown platform".""" + for typed, said in (("es-de", "ES-DE"), ("esde", "ES-DE"), + ("launchbox", "LaunchBox"), ("android", "Android")): + err = io.StringIO() + with self.subTest(typed=typed), contextlib.redirect_stderr(err), \ + self.assertRaises(SystemExit) as raised: + install.normalize_platform(typed) + self.assertEqual(raised.exception.code, 2) + self.assertIn(f"{said} has no BIOS folder of its own: run again without " + "--platform", err.getvalue()) + def test_a_system_name_is_suggested(self): err = io.StringIO() with contextlib.redirect_stderr(err), self.assertRaises(SystemExit): @@ -4028,7 +4041,8 @@ class ATypoGetsTheClosestName(unittest.TestCase): # The distinct names --list-platforms prints: Batocera is both a # platform and a system it recognises. names = [*install.AVAILABLE_PLATFORMS, - *(line.split(":")[0] for line in install._system_lines())] + *(line.split(":")[0] for line in install._system_lines()), + *install._NO_BIOS_FOLDER] listed = len({install._name_key(name) for name in names}) self.assertIn(f"lists all {listed}.", err.getvalue()) diff --git a/wiki/installer.md b/wiki/installer.md index da92d321c..d7d04be39 100644 --- a/wiki/installer.md +++ b/wiki/installer.md @@ -950,7 +950,7 @@ what the options name, everything by default. | Option | Effect | |--------|--------| -| `--platform NAME` | Install for this platform instead of the detected one. A system `--list-platforms` names under its own files (`muos`, `arkos`) stands for the file list it gets, and the run says which. Unknown names are refused with the closest ones | +| `--platform NAME` | Install for this platform instead of the detected one. A system `--list-platforms` names under its own files (`muos`, `arkos`) stands for the file list it gets, and the run says which. ES-DE, LaunchBox and Android, which keep no BIOS folder, are answered with the run that fills each emulator's folder. Unknown names are refused with the closest ones | | `--dest PATH` | Destination directory, overriding detection. Without `--platform`, the file list is the platform detected here: at a terminal the installer asks, Enter taking the one found, and otherwise it uses the one found, RetroArch's when nothing is found, and refuses when several are. The run prints whose list it is. A folder that does not exist is named with the nearest one that does, then created, except for a system that runs from its SD card, which refuses it. When more than its last level is missing (a mistyped path), a run at a terminal asks first, and the answer defaults to no | | `--target NAME` | Keep only the files the cores of that hardware target need, and the systems they emulate. An unknown target is refused rather than ignored, since carrying on would install everything. On Batocera, Recalbox, ROCKNIX and Lakka the board is read from the system (`batocera.arch`, `recalbox.arch`, `HW_DEVICE`, `LIBREELEC_DEVICE` or `LIBREELEC_PROJECT`) and applied when no `--target` is given | | `--every-board` | Install the files of every board instead of the one the system names, for a card that moves between devices |