fix: compare a card's BIOS folder by folders

--dest NOTMUOS/bios ended with MUOS/bios as text and passed as a muOS
card's folder. A card two systems claim now says so in one line, and
the system named among them decides the folder.
This commit is contained in:
Abdessamad Derraz committed 2026-10-23 20:43:38 +02:00
1 parent 246b6c6efc
commit ccc8af7a47
4 files changed
+58 -8

No files matched your search

+1 -1
View File
@@ -11,7 +11,7 @@
$ErrorActionPreference = "Stop"
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
$defaultInstallSha256 = "1097dfe33e56238089af275bfea662d29613ff592f68ecdb427a86b5bcbc3e81"
$defaultInstallSha256 = "2103f380bac5e2dc6ab91183283d268cccce81971da89f2963bab752d1518ef2"
$maximumInstallerBytes = 2MB
$installerExit = 0
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
+28 -6
View File
@@ -8667,16 +8667,29 @@ def card_system(root: Path) -> tuple[str, Path, str] | None:
plat = card_platform(root)
if plat:
return plat, root, display_name(plat)
matched = [rule for rule in _card_rules() if _card_rule_matches(rule, root)]
bases = {rule.base for rule in matched if rule.base}
matched = [rule for rule in matched if rule.name not in bases]
targets = {(rule.manifest, rule.bios) for rule in matched}
if len(targets) != 1:
matched = _card_matches(root)
if len({(rule.manifest, rule.bios) for rule in matched}) != 1:
return None
rule = matched[0]
return rule.manifest, root / rule.bios, rule.name
def _card_matches(root: Path) -> list[_OsRule]:
"""The card rules root matches, a system another one is built on left
out for it."""
matched = [rule for rule in _card_rules() if _card_rule_matches(rule, root)]
bases = {rule.base for rule in matched if rule.base}
return [rule for rule in matched if rule.name not in bases]
def _ends_with(path: Path, relative: str) -> bool:
"""Whether path's last folders are relative's, compared folder by folder
and without case: NOTMUOS/bios does not end with MUOS/bios."""
tail = [part.casefold() for part in PurePosixPath(relative).parts]
parts = [part.casefold() for part in path.parts]
return len(parts) >= len(tail) and parts[len(parts) - len(tail):] == tail
def card_dest(named: str, plat: str, dest: Path) -> tuple[str, Path]:
"""The file list and folder for a --dest that names a handheld's card.
@@ -8694,12 +8707,21 @@ def card_dest(named: str, plat: str, dest: Path) -> tuple[str, Path]:
key = _name_key(named)
rule = next((rule for rule in _card_rules() if key and key == _name_key(rule.name)
and key != _name_key(display_name(rule.manifest))), None)
matched = [] if found else _card_matches(dest)
if rule is None or found:
if len({(match.manifest, match.bios) for match in matched}) > 1:
names = " and ".join(sorted({match.name for match in matched}))
print(f" {screen_text(str(dest))} holds the files of {names}: installing into "
"it as named. Name the card's BIOS folder with --dest to write there.")
return plat, dest
# Its folder on the card, or one its device reads (/run/muos/storage/bios).
own = {device.bios for device in _EMBEDDED_RULES if device.name == rule.name}
if dest.as_posix() in own or dest.as_posix().casefold().endswith(rule.bios.casefold()):
if dest.as_posix() in own or _ends_with(dest, rule.bios):
return plat, dest
if any(match.name == rule.name for match in matched):
# A card two systems claim, the one named among them.
print(f" {rule.name} card: {display_name(plat)} files, in {dest / rule.bios}")
return plat, dest / rule.bios
marker = rule.values[0].split("/")[0]
print(f"Error: {dest} is not a {rule.name} card: it holds no {marker}. "
f"{rule.name} reads its BIOS files from {rule.bios} on its card: name the card's "
+1 -1
View File
@@ -18,7 +18,7 @@ esac
TEMP_INSTALLER=""
TEMP_DIRECTORY=""
DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
DEFAULT_INSTALL_SHA256="1097dfe33e56238089af275bfea662d29613ff592f68ecdb427a86b5bcbc3e81"
DEFAULT_INSTALL_SHA256="2103f380bac5e2dc6ab91183283d268cccce81971da89f2963bab752d1518ef2"
MAX_INSTALLER_BYTES=2097152
cleanup() {
+28
View File
@@ -10,6 +10,7 @@ installs it).
from __future__ import annotations
import argparse
import contextlib
import errno
import fcntl
import functools
@@ -2122,6 +2123,33 @@ class AuditRoundThree(unittest.TestCase):
self.assertEqual(install.card_dest("retroarch", "retroarch", root),
("retroarch", root))
def test_p1_1_the_folder_named_is_compared_by_folders(self):
"""NOTMUOS/bios ended with MUOS/bios as text and was taken for a
muOS card's folder."""
root = self.card({"roms/": ""})
stray = root / "NOTMUOS" / "bios"
with self.assertRaises(SystemExit), \
contextlib.redirect_stderr(io.StringIO()) as err:
install.card_dest("muos", "retroarch", stray)
self.assertIn("is not a muOS card", err.getvalue())
self.assertEqual(install.card_dest("muos", "retroarch", root / "muos" / "BIOS"),
("retroarch", root / "muos" / "BIOS"))
def test_p1_1_a_card_two_systems_claim_says_so(self):
root = self.card({"MUOS/": "", "spruce/": ""})
self.assertIsNone(install.card_system(root))
with contextlib.redirect_stdout(io.StringIO()) as out:
self.assertEqual(install.card_dest("retroarch", "retroarch", root),
("retroarch", root))
lines = out.getvalue().splitlines()
self.assertEqual(len(lines), 1, lines)
self.assertIn("holds the files of muOS and spruceOS", lines[0])
# The system named among them decides.
with contextlib.redirect_stdout(io.StringIO()) as out:
self.assertEqual(install.card_dest("muos", "retroarch", root),
("retroarch", root / "MUOS/bios"))
self.assertIn("muOS card", out.getvalue())
# P1-2: Space is X on PortMaster and Y on muxterm.
def test_p1_2_space_on_install_opens_the_confirm_screen(self):