Choose the asset that matches the machine
Batocera runs on x86_64 mini-PCs, on the Raspberry Pi and on the ARM handhelds alike. A cartridge is data for an emulator and runs anywhere, which is why this store has been portable so far — but a native build only starts on the architecture it was built for, and an x86_64 binary installed on a Pi is worse than one never offered. `kind` and `ext` may now be a map from architecture to value, with `*` as a fallback; a plain string still means "the same everywhere", so existing configs are untouched. The detected architecture is reported at the top of `list` and as `detected_arch` in `config`, and a title with no asset for the running machine is skipped with a reason that names it. Verified on aarch64 against the live catalog: the cartridge config behaves exactly as before, a bevy entry mapped per architecture pulls bevydemo-1.0.0-linux-arm64.zip, and the binary inside is an AArch64 ELF. A map without an entry for the machine skips and says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -149,7 +149,7 @@ counts, favourites and scraped media, and two stores can share one gamelist.
|
||||
| `catalog.statuses` | `["released", "archived"]` | catalog `status` values to install |
|
||||
| `catalog.owner_id` | `null` | restrict to one publisher (`/api/software?owner_id=`) |
|
||||
| `catalog.only` / `catalog.exclude` | `[]` | software-name allow / deny lists |
|
||||
| `platforms` | c64, tic80 | platform → system, asset kind, extension, enabled |
|
||||
| `platforms` | c64, tic80 | platform → system, asset kind, extension, enabled; the kind may be per-architecture |
|
||||
| `behavior.prune` | `true` | remove games that left the catalog or the filters |
|
||||
| `behavior.timeout` | `30` | HTTP timeout, seconds |
|
||||
| `behavior.insecure` | `false` | skip TLS verification (self-hosted test instances) |
|
||||
@@ -172,6 +172,32 @@ launches, so they are not mapped by default. Adding one is a config edit:
|
||||
"platforms": { "godot": { "system": "godot", "kind": "linux_x64", "ext": ".zip", "enabled": true } }
|
||||
```
|
||||
|
||||
### Per-architecture assets
|
||||
|
||||
Batocera runs on x86_64 mini-PCs, on the Raspberry Pi and on the ARM handhelds
|
||||
alike, and a native binary only starts on the architecture it was built for —
|
||||
an x86_64 build installs on a Pi and then does nothing. A cartridge is data for
|
||||
an emulator, so it is architecture-independent; a native build is not.
|
||||
|
||||
Where the right asset depends on the machine, `kind` (and `ext`, if it differs)
|
||||
can be a map instead of a string. `*` is the fallback:
|
||||
|
||||
```json
|
||||
"platforms": {
|
||||
"bevy": {
|
||||
"system": "bevy",
|
||||
"kind": { "x86_64": "linux_x64", "aarch64": "linux_arm64" },
|
||||
"ext": ".zip",
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The engine reports the architecture it detected — `x86_64`, `aarch64`, `armhf`,
|
||||
`x86` — at the top of `list`, and `config` prints it as `detected_arch`. With no
|
||||
entry for the running machine and no `*`, the title is skipped and says so:
|
||||
`skipped bevydemo: bevy has no asset kind for aarch64`.
|
||||
|
||||
A platform is also skipped when the box has no ROM folder for its system —
|
||||
`list` reports that as `skipped <name>: no '<system>' ROM folder`.
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ Standard library only — Batocera ships python3 but no pip packages.
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
@@ -281,6 +282,37 @@ def fetch_catalog(cfg, use_cache=False):
|
||||
die(f"cannot fetch catalog from {url}: {exc}")
|
||||
|
||||
|
||||
def machine():
|
||||
"""A gep architekturaja, `uname -m` szerint, normalizalt neven.
|
||||
|
||||
A gazdaplatform ugyanaz (Batocera), a gep viszont nem: x86_64 mini-PC,
|
||||
Raspberry Pi es kezikonzol egyaránt. Egy x86_64 binaris ARM-on feltelepul,
|
||||
de nem indul el, ezért a kiadasvalasztasnak tudnia kell, min fut.
|
||||
"""
|
||||
m = (platform.machine() or "").lower()
|
||||
if m in ("x86_64", "amd64"):
|
||||
return "x86_64"
|
||||
if m in ("aarch64", "arm64"):
|
||||
return "aarch64"
|
||||
if m.startswith("armv") or m == "arm":
|
||||
return "armhf"
|
||||
if m in ("i386", "i486", "i586", "i686"):
|
||||
return "x86"
|
||||
return m or "unknown"
|
||||
|
||||
|
||||
def resolve_for_arch(value, arch):
|
||||
"""Egy config-erteket architekturara oldunk fel.
|
||||
|
||||
A `kind` es az `ext` lehet egyszeru string (minden gepen ugyanaz — igy
|
||||
mukodik a cartridge), vagy architektura -> ertek leképezes. Az utóbbinal
|
||||
a `"*"` kulcs szolgal tartaleknak.
|
||||
"""
|
||||
if not isinstance(value, dict):
|
||||
return value
|
||||
return value.get(arch, value.get("*"))
|
||||
|
||||
|
||||
def asset_basename(path):
|
||||
"""`/file/blessingofra-2.0.0.prg` -> `blessingofra-2.0.0.prg`."""
|
||||
return os.path.basename(path.rstrip("/"))
|
||||
@@ -317,8 +349,9 @@ def pick_release(entry, kind, ext):
|
||||
return None, None
|
||||
|
||||
|
||||
def select_games(cfg, catalog, available_systems):
|
||||
def select_games(cfg, catalog, available_systems, arch=None):
|
||||
"""Catalog -> list of installable game dicts, plus a list of skip reasons."""
|
||||
arch = arch or machine()
|
||||
statuses = {s.lower() for s in cfg["catalog"].get("statuses") or []}
|
||||
only = {n.lower() for n in cfg["catalog"].get("only") or []}
|
||||
exclude = {n.lower() for n in cfg["catalog"].get("exclude") or []}
|
||||
@@ -344,9 +377,15 @@ def select_games(cfg, catalog, available_systems):
|
||||
if name.lower() in exclude:
|
||||
continue
|
||||
|
||||
release, file_name = pick_release(entry, spec["kind"], spec.get("ext", ""))
|
||||
kind = resolve_for_arch(spec["kind"], arch)
|
||||
if not kind:
|
||||
skipped.append(f"{name}: {sw.get('platform')} has no asset kind for {arch}")
|
||||
continue
|
||||
ext = resolve_for_arch(spec.get("ext", ""), arch) or ""
|
||||
|
||||
release, file_name = pick_release(entry, kind, ext)
|
||||
if not release:
|
||||
skipped.append(f"{name}: no '{spec['kind']}' asset in any release")
|
||||
skipped.append(f"{name}: no '{kind}' asset in any release")
|
||||
continue
|
||||
|
||||
games.append(
|
||||
@@ -793,7 +832,9 @@ def cmd_apply_gamelists(cfg, args):
|
||||
def cmd_list(cfg, args):
|
||||
systems = detect_systems(cfg)
|
||||
catalog = fetch_catalog(cfg, use_cache=True)
|
||||
games, skipped = select_games(cfg, catalog, systems)
|
||||
arch = machine()
|
||||
log(f"architecture: {arch}")
|
||||
games, skipped = select_games(cfg, catalog, systems, arch)
|
||||
installed = load_state()["installed"]
|
||||
|
||||
if not games:
|
||||
@@ -844,7 +885,9 @@ def cmd_config(cfg, args):
|
||||
write_json(args.config, DEFAULT_CONFIG)
|
||||
log(f"wrote default config to {args.config}")
|
||||
return 0
|
||||
print(json.dumps(cfg, indent=2, ensure_ascii=False))
|
||||
# A felismert architektura nem a configbol jon, de az asset-valasztast
|
||||
# eldonti, ezert itt is lathatonak kell lennie.
|
||||
print(json.dumps({"detected_arch": machine(), **cfg}, indent=2, ensure_ascii=False))
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user