mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-19 01:43:25 -05:00
feat: narrow an embedded install to its board
This commit is contained in:
1 parent
51032c272b
commit
14f78ab634
5 files changed
+92
-10
No files matched your search
+1
-1
@@ -8,7 +8,7 @@ param(
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
$defaultInstallSha256 = "c997339fd3efb879983937ed9dea6d0190d4689dedf627906c622f329587b757"
|
||||
$defaultInstallSha256 = "b163e90cc3101ce499e1f01899a398fbea27656054fb2fb9b31f07631d15f19a"
|
||||
$maximumInstallerBytes = 2MB
|
||||
$installerExit = 0
|
||||
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
|
||||
|
||||
+51
-7
@@ -591,6 +591,32 @@ def _parse_bash_var(path: Path, key: str) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
# Where an embedded system names the board it was built for, in the words
|
||||
# of our target lists: batocera-system.mk writes BATOCERA_SYSTEM_ARCH,
|
||||
# recalbox-system.mk RECALBOX_SYSTEM_PLATFORM, ROCKNIX's scripts/image puts
|
||||
# HW_DEVICE in os-release (RK3326, our rk3326).
|
||||
_BOARD_SOURCES: dict[str, tuple[str, str]] = {
|
||||
"batocera": ("file", "/usr/share/batocera/batocera.arch"),
|
||||
"recalbox": ("file", "/recalbox/recalbox.arch"),
|
||||
"rocknix": ("os_release", "HW_DEVICE"),
|
||||
}
|
||||
|
||||
|
||||
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, ("", ""))
|
||||
if kind == "file":
|
||||
try:
|
||||
value = Path(where).read_text(encoding="utf-8", errors="replace")
|
||||
except OSError:
|
||||
return None
|
||||
elif kind == "os_release":
|
||||
value = _parse_os_release().get(where, "")
|
||||
else:
|
||||
return None
|
||||
return value.strip().lower() or None
|
||||
|
||||
|
||||
def _parse_json_path(path: Path, *keys: str) -> str | None:
|
||||
"""Extract a nested string value from a JSON file."""
|
||||
if not path.exists():
|
||||
@@ -2942,7 +2968,13 @@ def main() -> None:
|
||||
)
|
||||
parser.add_argument(
|
||||
"--target",
|
||||
help="hardware target for core filtering (switch, rpi4, ...)",
|
||||
help="hardware target for core filtering (switch, rpi4, ...); "
|
||||
"on Batocera, Recalbox and ROCKNIX the board is read from the system",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--every-board",
|
||||
action="store_true",
|
||||
help="install the files of every board, not only the detected one",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--check",
|
||||
@@ -3054,6 +3086,8 @@ def main() -> None:
|
||||
or args.list_systems or args.list_cores
|
||||
):
|
||||
parser.error("--quiet applies to an install, not to --check, --dry-run or a listing")
|
||||
if args.every_board and args.target:
|
||||
parser.error("--every-board installs every board; --target names one")
|
||||
if not args.quiet:
|
||||
_install(args, sys.stdout)
|
||||
return
|
||||
@@ -3202,18 +3236,28 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
print(f" {t} ({label})")
|
||||
continue
|
||||
|
||||
# Target filtering
|
||||
if args.target:
|
||||
# Target filtering. With no --target, a system that names its board
|
||||
# narrows to it: a Batocera RPi4 took 8.6 GiB where its board needs
|
||||
# 5.5. Only on the device itself, where the board file exists.
|
||||
target = args.target
|
||||
if not target and not args.every_board and args.dest is None:
|
||||
board = detect_board(plat_name)
|
||||
if board:
|
||||
known = fetch_targets(plat_name) or {}
|
||||
if board in known:
|
||||
target = board
|
||||
print(f" Board {board} detected (--every-board installs all boards)")
|
||||
if target:
|
||||
targets = fetch_targets(plat_name)
|
||||
if targets is None:
|
||||
sys.exit(1)
|
||||
target_info = targets.get(args.target)
|
||||
target_info = targets.get(target)
|
||||
if target_info is None:
|
||||
# Carrying on would install every file, which is the opposite
|
||||
# of what a filter was asked for: a 4 GB download instead of
|
||||
# the subset the target needs. Refuse rather than ignore.
|
||||
print(
|
||||
f"Error: unknown target '{args.target}' for {plat_name}.",
|
||||
f"Error: unknown target '{target}' for {plat_name}.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
if targets:
|
||||
@@ -3227,7 +3271,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
sys.exit(1)
|
||||
elif target_info.get("cores") is None:
|
||||
print(
|
||||
f" Target '{args.target}' publishes no core list; "
|
||||
f" Target '{target}' publishes no core list; "
|
||||
"installing every file"
|
||||
)
|
||||
else:
|
||||
@@ -3235,7 +3279,7 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
files, omitted_files = narrow_to_cores(
|
||||
manifest, target_info["cores"], files, omitted_files
|
||||
)
|
||||
print(f" Filtered {before} -> {len(files)} files for target {args.target}")
|
||||
print(f" Filtered {before} -> {len(files)} files for target {target}")
|
||||
|
||||
found_cores = cores_found.get((plat_name, bios_path), [])
|
||||
if "system_cores" not in manifest:
|
||||
|
||||
+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="c997339fd3efb879983937ed9dea6d0190d4689dedf627906c622f329587b757"
|
||||
DEFAULT_INSTALL_SHA256="b163e90cc3101ce499e1f01899a398fbea27656054fb2fb9b31f07631d15f19a"
|
||||
MAX_INSTALLER_BYTES=2097152
|
||||
|
||||
cleanup() {
|
||||
|
||||
@@ -2281,5 +2281,42 @@ class AnUnreadableRetroDeckConfigIsSaid(unittest.TestCase):
|
||||
self.assertIn("could not read paths.rd_home_path", err.getvalue())
|
||||
|
||||
|
||||
|
||||
class TheBoardTheSystemNamesIsTheTarget(unittest.TestCase):
|
||||
"""Batocera, Recalbox and ROCKNIX each write the board they were built
|
||||
for; the installer read none of them, so a Batocera RPi4 installed
|
||||
every board's files (8.6 GiB where bcm2711 needs 5.5)."""
|
||||
|
||||
def test_each_source_is_read(self):
|
||||
root = Path(_tempdir(self))
|
||||
arch = root / "batocera.arch"
|
||||
arch.write_text("bcm2711")
|
||||
with unittest.mock.patch.dict(install._BOARD_SOURCES, {"batocera": ("file", str(arch))}):
|
||||
self.assertEqual(install.detect_board("batocera"), "bcm2711")
|
||||
with unittest.mock.patch.object(install, "_parse_os_release",
|
||||
return_value={"HW_DEVICE": "RK3326"}):
|
||||
self.assertEqual(install.detect_board("rocknix"), "rk3326")
|
||||
self.assertIsNone(install.detect_board("retroarch"))
|
||||
|
||||
def test_every_board_and_target_are_refused_together(self):
|
||||
result = subprocess.run(
|
||||
[sys.executable, str(REPO_ROOT / "install.py"), "--every-board",
|
||||
"--target", "bcm2711", "--platform", "batocera", "--dry-run"],
|
||||
capture_output=True, text=True, timeout=120,
|
||||
)
|
||||
self.assertEqual(result.returncode, 2)
|
||||
self.assertIn("--every-board", result.stderr)
|
||||
|
||||
def test_the_sources_name_our_target_lists(self):
|
||||
import yaml # noqa: PLC0415
|
||||
|
||||
for platform in install._BOARD_SOURCES:
|
||||
with self.subTest(platform=platform):
|
||||
targets = yaml.safe_load(
|
||||
(REPO_ROOT / "platforms" / "targets" / f"{platform}.yml").read_text()
|
||||
)["targets"]
|
||||
self.assertTrue(targets)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
+2
-1
@@ -209,7 +209,8 @@ what the options name, everything by default.
|
||||
|--------|--------|
|
||||
| `--platform NAME` | Install for this platform instead of the detected one. Unknown names are refused with the available list |
|
||||
| `--dest PATH` | Destination directory, overriding detection. With `--dest` alone the file list is RetroArch's |
|
||||
| `--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 |
|
||||
| `--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 and ROCKNIX the board is read from the system (`batocera.arch`, `recalbox.arch`, `HW_DEVICE`) 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 |
|
||||
| `--installed-cores` | Keep only what the cores already installed read (RetroArch, Lakka, RetroPie); see [Installed cores](#installed-cores) |
|
||||
| `--system NAMES` | Install only these systems. Comma-separated or repeated; `--list-systems` prints the names, `other` included |
|
||||
| `--core NAMES` | Keep the platform's own list and only the extra files these cores load; `--list-cores` prints the names |
|
||||
|
||||
Reference in new issue
Block a user