mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 20:29:06 -05:00
fix: detect Batocera and Knulli by build files
No Batocera build writes /etc/batocera-version: batocera-system.mk:21-22 (batocera.linux 38845725, unchanged since batocera-30) writes /usr/share/batocera/batocera.version. Knulli (knulli-linux 57afa662) adds OS_NAME=knulli to os-release, writes /usr/share/knulli/knulli.version and removes /usr/share/batocera, and no Knulli source writes /etc/knulli-release. Neither was detected. A Knulli board is named and not narrowed by Batocera's per-board lists, and an unlisted board is named.
This commit is contained in:
1 parent
edda080c59
commit
89c533e9ba
6 files changed
+102
-15
No files matched your search
+1
-1
@@ -11,7 +11,7 @@
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
$defaultInstallSha256 = "e85a34efb84620b8c65858d209c9741a715f8ff6a61397f9ee161c0931a9a049"
|
||||
$defaultInstallSha256 = "5ed37d4dabc5a6b28a9093f38a25506b20ec2f49c3587692efd695b017d1caf4"
|
||||
$maximumInstallerBytes = 2MB
|
||||
$installerExit = 0
|
||||
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
|
||||
|
||||
+42
-5
@@ -717,6 +717,28 @@ _BOARD_SOURCES: dict[str, tuple[str, str]] = {
|
||||
}
|
||||
|
||||
|
||||
# A derivative installed under a platform's name, with its own board file.
|
||||
# Knulli moves /usr/share/batocera to /usr/share/knulli (knulli-linux
|
||||
# 57afa662, board/scripts/post-build-script.sh:264-278) and writes its board
|
||||
# to knulli.arch (package/system/knulli-system/knulli-system.mk:98-99). Its
|
||||
# packages are its own, so Batocera's per-board core lists do not apply.
|
||||
_DERIVATIVE_BOARDS: dict[str, tuple[str, str]] = {
|
||||
"batocera": ("Knulli", "/usr/share/knulli/knulli.arch"),
|
||||
}
|
||||
|
||||
|
||||
def derivative_board(platform: str) -> tuple[str, str] | None:
|
||||
"""(derivative, board) when a derivative of the platform names its board."""
|
||||
name, where = _DERIVATIVE_BOARDS.get(platform, ("", ""))
|
||||
if not where:
|
||||
return None
|
||||
try:
|
||||
board = Path(where).read_text(encoding="utf-8", errors="replace").strip().lower()
|
||||
except OSError:
|
||||
return None
|
||||
return (name, board) if board else None
|
||||
|
||||
|
||||
def detect_board(platform: str) -> str | None:
|
||||
"""The board this system was built for, or None where it names none."""
|
||||
kind, where = _BOARD_SOURCES.get(platform, ("", ""))
|
||||
@@ -767,16 +789,22 @@ def _parse_ps1_var(path: Path, key: str) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
# Embedded systems, first match wins: Knulli also carries the Batocera
|
||||
# markers. The registry publishes the same rules as each manifest's
|
||||
# `detect`, and a test holds the two equal. MiSTer is a path rule below.
|
||||
# Embedded systems, first match wins. The registry publishes the same rules
|
||||
# as each manifest's `detect`, and a test holds the two equal. MiSTer is a
|
||||
# path rule below.
|
||||
_EMBEDDED_RULES: tuple[tuple[str, str, tuple[str, ...], str], ...] = (
|
||||
# ROCKNIX writes OS_NAME and no ID since 2025 (scripts/image). Older
|
||||
# images wrote ID=rocknix.
|
||||
("rocknix", "os_release", ("OS_NAME=rocknix", "ID=rocknix"), "/storage/roms/bios"),
|
||||
("batocera", "file_exists", ("/etc/knulli-release",), "/userdata/bios"),
|
||||
# Knulli (knulli-linux 57afa662): OS_NAME in os-release
|
||||
# (board/scripts/post-build-script.sh:233-236) and knulli.version
|
||||
# (package/system/knulli-system/knulli-system.mk:98-102).
|
||||
("batocera", "os_release", ("OS_NAME=knulli",), "/userdata/bios"),
|
||||
("batocera", "file_exists", ("/usr/share/knulli/knulli.version",), "/userdata/bios"),
|
||||
("lakka", "os_release", ("ID=lakka",), "/storage/system"),
|
||||
("batocera", "file_exists", ("/etc/batocera-version",), "/userdata/bios"),
|
||||
# batocera.linux 38845725, batocera-system.mk:21-22 (the same lines in
|
||||
# batocera-30): batocera.arch and batocera.version.
|
||||
("batocera", "file_exists", ("/usr/share/batocera/batocera.version",), "/userdata/bios"),
|
||||
("recalbox", "file_exists", ("/recalbox/recalbox.version",), "/recalbox/share/bios"),
|
||||
("recalbox", "file_exists", ("/usr/bin/recalbox-settings",), "/recalbox/share/bios"),
|
||||
("retroarch", "file_exists", ("/opt/muos",), "/run/muos/storage/bios"),
|
||||
@@ -4633,6 +4661,15 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
if board in known:
|
||||
target = board
|
||||
print(f" Board {board} detected (--every-board installs all boards)")
|
||||
else:
|
||||
print(f" Board {board} has no {PLATFORM_NAMES.get(plat_name, plat_name)} "
|
||||
"core list: installing the files of every board")
|
||||
else:
|
||||
derived = derivative_board(plat_name)
|
||||
if derived:
|
||||
print(f" {derived[0]} board {derived[1]} detected. {derived[0]} "
|
||||
"builds its own set of cores and publishes no core list "
|
||||
"per board: installing the files of every board")
|
||||
if target:
|
||||
targets = target_lists.get(plat_name)
|
||||
if targets is None:
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ esac
|
||||
TEMP_INSTALLER=""
|
||||
TEMP_DIRECTORY=""
|
||||
DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
DEFAULT_INSTALL_SHA256="e85a34efb84620b8c65858d209c9741a715f8ff6a61397f9ee161c0931a9a049"
|
||||
DEFAULT_INSTALL_SHA256="5ed37d4dabc5a6b28a9093f38a25506b20ec2f49c3587692efd695b017d1caf4"
|
||||
MAX_INSTALLER_BYTES=2097152
|
||||
|
||||
cleanup() {
|
||||
|
||||
+12
-4
@@ -313,14 +313,22 @@ platforms:
|
||||
target_source: https://github.com/batocera-linux/batocera.linux
|
||||
install:
|
||||
detect:
|
||||
# Knulli is a Batocera derivative and carries its markers too.
|
||||
# Knulli, a Batocera derivative (knulli-cfw/knulli-linux 57afa662):
|
||||
# OS_NAME in os-release (board/scripts/post-build-script.sh:233-236),
|
||||
# and knulli.version (package/system/knulli-system/knulli-system.mk:98-102).
|
||||
- os: linux
|
||||
method: file_exists
|
||||
file: /etc/knulli-release
|
||||
method: os_release
|
||||
match: [OS_NAME=knulli]
|
||||
bios_path: /userdata/bios
|
||||
- os: linux
|
||||
method: file_exists
|
||||
file: /etc/batocera-version
|
||||
file: /usr/share/knulli/knulli.version
|
||||
bios_path: /userdata/bios
|
||||
# batocera.linux 38845725, package/batocera/core/batocera-system/
|
||||
# batocera-system.mk:21-22 writes batocera.arch and batocera.version.
|
||||
- os: linux
|
||||
method: file_exists
|
||||
file: /usr/share/batocera/batocera.version
|
||||
bios_path: /userdata/bios
|
||||
standalone_copies: *standalone_copies
|
||||
recalbox:
|
||||
|
||||
+40
-1
@@ -1028,7 +1028,8 @@ class DetectionFollowsTheRegistry(unittest.TestCase):
|
||||
with unittest.mock.patch.object(install, "_parse_os_release", return_value={}), \
|
||||
unittest.mock.patch.object(
|
||||
Path, "exists",
|
||||
lambda p: str(p) in ("/etc/knulli-release", "/etc/batocera-version"),
|
||||
lambda p: str(p) in ("/usr/share/knulli/knulli.version",
|
||||
"/usr/share/batocera/batocera.version"),
|
||||
):
|
||||
self.assertEqual(install._detect_embedded(), [("batocera", Path("/userdata/bios"))])
|
||||
# What ROCKNIX writes since 2025: OS_NAME and HW_DEVICE, no ID.
|
||||
@@ -3952,5 +3953,43 @@ class MuOsIsReadFromItsRetroArchConfig(unittest.TestCase):
|
||||
self.assertEqual(rule[3], "/run/muos/storage/bios")
|
||||
|
||||
|
||||
class BatoceraAndKnulliByWhatTheirBuildsWrite(unittest.TestCase):
|
||||
"""No Batocera build writes /etc/batocera-version (batocera-system.mk
|
||||
writes /usr/share/batocera/batocera.version), and Knulli writes no
|
||||
/etc/knulli-release and removes /usr/share/batocera: neither was
|
||||
detected, and a Knulli board got every board's files without a word."""
|
||||
|
||||
def _detect(self, release: dict, files: tuple[str, ...]):
|
||||
with unittest.mock.patch.object(install, "_parse_os_release", return_value=release), \
|
||||
unittest.mock.patch.object(Path, "exists", lambda p: str(p) in files):
|
||||
return install._detect_embedded()
|
||||
|
||||
def test_batocera_by_its_version_file(self):
|
||||
self.assertEqual(self._detect({}, ("/usr/share/batocera/batocera.version",)),
|
||||
[("batocera", Path("/userdata/bios"))])
|
||||
self.assertEqual(self._detect({}, ("/etc/batocera-version",)), [])
|
||||
|
||||
def test_knulli_by_its_os_release_or_version_file(self):
|
||||
self.assertEqual(self._detect({"OS_NAME": "knulli"}, ()),
|
||||
[("batocera", Path("/userdata/bios"))])
|
||||
self.assertEqual(self._detect({}, ("/usr/share/knulli/knulli.version",)),
|
||||
[("batocera", Path("/userdata/bios"))])
|
||||
|
||||
def test_a_knulli_board_is_named_and_not_narrowed(self):
|
||||
board = Path(_tempdir(self)) / "knulli.arch"
|
||||
board.write_text("a133")
|
||||
with unittest.mock.patch.dict(install._DERIVATIVE_BOARDS,
|
||||
{"batocera": ("Knulli", str(board))}):
|
||||
self.assertEqual(install.derivative_board("batocera"), ("Knulli", "a133"))
|
||||
self.assertIsNone(install.derivative_board("recalbox"))
|
||||
|
||||
def test_the_run_says_why_every_board_is_installed(self):
|
||||
source = (REPO_ROOT / "install.py").read_text(encoding="utf-8")
|
||||
block = source[source.index("board = detect_board(plat_name)"):]
|
||||
block = block[:block.index("if target:")]
|
||||
self.assertIn("has no", block)
|
||||
self.assertIn("derivative_board(plat_name)", block)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
+6
-3
@@ -279,9 +279,9 @@ wins, since a machine is only one of them.
|
||||
| Evidence | Platform | BIOS directory |
|
||||
|----------|----------|----------------|
|
||||
| `/etc/os-release` `OS_NAME=ROCKNIX` (or `ID=rocknix` on images before 2025) | ROCKNIX | `/storage/roms/bios` |
|
||||
| `/etc/knulli-release` | Batocera | `/userdata/bios` |
|
||||
| `/etc/os-release` `OS_NAME=knulli` or `/usr/share/knulli/knulli.version` | Batocera (Knulli) | `/userdata/bios` |
|
||||
| `/etc/os-release` `ID=lakka` | Lakka | `/storage/system` |
|
||||
| `/etc/batocera-version` | Batocera | `/userdata/bios` |
|
||||
| `/usr/share/batocera/batocera.version` | Batocera | `/userdata/bios` |
|
||||
| `/recalbox/recalbox.version` or `/usr/bin/recalbox-settings` | Recalbox | `/recalbox/share/bios` |
|
||||
| `/opt/muos` | RetroArch (muOS) | `system_directory` of `/opt/muos/share/info/config/retroarch.cfg`, else of the default it is copied from: `/run/muos/storage/bios`, which muOS binds to `MUOS/bios` on the second card when that card holds one, else the first. Cores are read from that config's `libretro_directory` (`/opt/muos/share/core`) |
|
||||
| `/mnt/mmc/MUOS/` | RetroArch | `/mnt/mmc/MUOS/bios` |
|
||||
@@ -290,7 +290,10 @@ wins, since a machine is only one of them.
|
||||
|
||||
Batocera, Recalbox, ROCKNIX and Lakka also name the board they were built for, and
|
||||
that board narrows the install unless `--target` or `--every-board` says
|
||||
otherwise (see the options above).
|
||||
otherwise (see the options above). A board with no core list of its own is
|
||||
named and gets the files of every board. Knulli names its board in
|
||||
`/usr/share/knulli/knulli.arch` but builds its own set of cores, so Batocera's
|
||||
per-board lists are not applied to it and the run says so.
|
||||
|
||||
Some platforms keep their BIOS in a fixed directory, and that directory is the
|
||||
evidence. They are looked for after the configurations below, for a platform
|
||||
|
||||
Reference in new issue
Block a user