mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-06 10:03:49 -06:00
feat: add AmberELEC hardware targets
AmberELEC's metapackage adds LIBRETRO_CORES_EXTRA (bsnes, Mesen, melonDS, geolith) only on RG552, RG353 and RG503, and deletes those cores from es_systems.cfg on every other device (packages/amberelec/package.mk:23-31, 45-58 at a21975bf). The new target scraper reads the Makefile's device images, that test and es_systems.cfg the way the platform scraper does: RG351P, RG351V and RG351MP list 125 cores, the other three 136. The installer reads the device from COREELEC_DEVICE in os-release (scripts/image:168).
This commit is contained in:
1 parent
8107564631
commit
43cb0f84ab
11 files changed
+1895
-18
No files matched your search
@@ -0,0 +1,157 @@
|
||||
"""Scraper for AmberELEC per-device emulator availability.
|
||||
|
||||
Sources (AmberELEC/AmberELEC, at the commit platforms/amberelec.yml names):
|
||||
- Makefile -- one `DEVICE=<name> ARCH=<arch> ./scripts/build_distro` target
|
||||
per image (RG351P, RG351V, RG351MP, RG552, RG353, RG503 at a21975bf)
|
||||
- packages/amberelec/package.mk -- LIBRETRO_CORES_EXTRA joins PKG_EMUS
|
||||
only on the devices its `if` names (lines 23-31 at a21975bf: RG552,
|
||||
RG353, RG503), and on every other device makeinstall_target deletes
|
||||
each of those cores from es_systems.cfg (lines 45-58)
|
||||
- packages/ui/emulationstation/config/es_systems.cfg -- read the way the
|
||||
platform scraper reads it, after that deletion
|
||||
|
||||
An RG351P image carries neither melonDS nor bsnes: without a target list,
|
||||
its pack shipped the Nintendo DS firmware anyway.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import yaml
|
||||
|
||||
from . import BaseTargetScraper
|
||||
|
||||
PLATFORM_NAME = "amberelec"
|
||||
|
||||
RAW_BASE = "https://raw.githubusercontent.com/AmberELEC/AmberELEC/{ref}"
|
||||
META_MK = "packages/amberelec/package.mk"
|
||||
|
||||
try:
|
||||
from ..amberelec_scraper import BUILDS_OF, ES_SYSTEMS_TEMPLATE, RUNNERS
|
||||
from ..base_scraper import fetch_bytes
|
||||
from ..batocera_scraper import _not_cores
|
||||
from ..es_emulators import es_cores, xml_systems
|
||||
except ImportError:
|
||||
from scraper.amberelec_scraper import BUILDS_OF, ES_SYSTEMS_TEMPLATE, RUNNERS
|
||||
from scraper.base_scraper import fetch_bytes
|
||||
from scraper.batocera_scraper import _not_cores
|
||||
from scraper.es_emulators import es_cores, xml_systems
|
||||
|
||||
_DEVICE_RE = re.compile(
|
||||
r"^(\w+):\n\tDEVICE=(\w+) ARCH=(\w+) \./scripts/build_distro$", re.MULTILINE
|
||||
)
|
||||
_EXTRA_RE = re.compile(r'LIBRETRO_CORES_EXTRA="([^"]*)"')
|
||||
# The `if` whose body adds the extra cores to PKG_EMUS.
|
||||
_EXTRA_IF_RE = re.compile(
|
||||
r"if \[\[ (?P<test>[^\n]*?) \]\]; then\s*\n\s*PKG_EMUS\+=\" \$\{LIBRETRO_CORES_EXTRA\}\""
|
||||
)
|
||||
# What makeinstall_target does to es_systems.cfg on the other devices.
|
||||
_REMOVAL_LINES = (
|
||||
"for CORE in ${LIBRETRO_CORES_EXTRA}; do",
|
||||
'sed -i "s|<core>$CORE</core>||g"',
|
||||
r"sed -i -e '/<emulator name/{:a;N;/<\/emulator>/!ba;/melonds/d}'",
|
||||
)
|
||||
_EMULATOR_BLOCK_RE = re.compile(r"[^\n]*<emulator name.*?</emulator>[^\n]*\n?", re.DOTALL)
|
||||
|
||||
|
||||
def devices(makefile: str) -> dict[str, str]:
|
||||
"""{device: architecture} of each image the Makefile builds."""
|
||||
found = {device: arch for target, device, arch in _DEVICE_RE.findall(makefile)
|
||||
if target == device}
|
||||
if not found:
|
||||
raise RuntimeError("the AmberELEC Makefile builds no device image")
|
||||
return found
|
||||
|
||||
|
||||
def extra_cores(package_mk: str) -> tuple[list[str], set[str]]:
|
||||
"""(the extra cores, the devices that keep them) from the metapackage."""
|
||||
listed = _EXTRA_RE.search(package_mk)
|
||||
test = _EXTRA_IF_RE.search(package_mk)
|
||||
if listed is None or test is None:
|
||||
raise RuntimeError(f"{META_MK}: no LIBRETRO_CORES_EXTRA or no test adding it")
|
||||
missing = [line for line in _REMOVAL_LINES if line not in package_mk]
|
||||
if missing:
|
||||
raise RuntimeError(f"{META_MK}: makeinstall_target no longer reads {missing[0]!r}")
|
||||
keep = set(re.findall(r'"\$\{DEVICE\}" == "(\w+)"', test.group("test")))
|
||||
for alternatives in re.findall(r'"\$\{DEVICE\}" =~ \^\(([\w|]+)\)\$', test.group("test")):
|
||||
keep.update(alternatives.split("|"))
|
||||
if not keep:
|
||||
raise RuntimeError(f"{META_MK}: the test adding the extra cores names no device")
|
||||
return listed.group(1).split(), keep
|
||||
|
||||
|
||||
def without_cores(es_systems: str, cores: list[str]) -> str:
|
||||
"""es_systems.cfg as makeinstall_target leaves it on a device without them."""
|
||||
for core in cores:
|
||||
if core == "melonds":
|
||||
es_systems = _EMULATOR_BLOCK_RE.sub(
|
||||
lambda block: "" if "melonds" in block.group(0) else block.group(0),
|
||||
es_systems,
|
||||
)
|
||||
es_systems = es_systems.replace(f"<core>{core}</core>", "")
|
||||
return es_systems
|
||||
|
||||
|
||||
def device_cores(es_systems: str, extra: list[str], keeps_extra: bool) -> list[str]:
|
||||
"""Every core and standalone emulator one device's es_systems.cfg offers."""
|
||||
text = es_systems if keeps_extra else without_cores(es_systems, extra)
|
||||
cores, _standalone, _dual = es_cores(
|
||||
xml_systems(text), RUNNERS, BUILDS_OF, _not_cores(PLATFORM_NAME)
|
||||
)
|
||||
return sorted(set(cores))
|
||||
|
||||
|
||||
class Scraper(BaseTargetScraper):
|
||||
"""Per-device core lists from AmberELEC's metapackage."""
|
||||
|
||||
def __init__(self, url: str = "https://github.com/AmberELEC/AmberELEC") -> None:
|
||||
super().__init__(url=url)
|
||||
self.ref = ""
|
||||
|
||||
def _raw(self, path: str) -> str:
|
||||
return fetch_bytes(f"{RAW_BASE.format(ref=self.ref)}/{path}").decode("utf-8")
|
||||
|
||||
def fetch_targets(self) -> dict:
|
||||
self.ref = self.pinned_revision(PLATFORM_NAME)
|
||||
extra, keep = extra_cores(self._raw(META_MK))
|
||||
es_systems = fetch_bytes(ES_SYSTEMS_TEMPLATE.format(ref=self.ref)).decode("utf-8")
|
||||
targets: dict[str, dict] = {}
|
||||
for device, arch in sorted(devices(self._raw("Makefile")).items()):
|
||||
cores = device_cores(es_systems, extra, device in keep)
|
||||
targets[device.lower()] = {"architecture": arch, "cores": cores}
|
||||
print(f" {device.lower()} ({arch}): {len(cores)} cores", file=sys.stderr)
|
||||
return {
|
||||
"platform": PLATFORM_NAME,
|
||||
"source": f"{self.url}/blob/{self.ref}/{META_MK}",
|
||||
"scraped_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
"targets": targets,
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False, description="Scrape AmberELEC per-device cores"
|
||||
)
|
||||
parser.add_argument("--dry-run", action="store_true", help="Show target summary")
|
||||
parser.add_argument("--output", "-o", help="Output YAML file")
|
||||
args = parser.parse_args()
|
||||
|
||||
scraper = Scraper()
|
||||
data = scraper.fetch_targets()
|
||||
if args.dry_run:
|
||||
for name, info in data["targets"].items():
|
||||
print(f" {name} ({info['architecture']}): {len(info['cores'])} cores")
|
||||
return
|
||||
if args.output:
|
||||
scraper.write_output(data, args.output)
|
||||
print(f"Written to {args.output}")
|
||||
return
|
||||
print(yaml.dump(data, default_flow_style=False, sort_keys=False))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user