mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-30 15:47:20 -05:00
feat: add knulli, amberelec and emuelec platforms
Each OS publishes Batocera's systems dict (knulli-systems, and batocera-systems at AmberELEC's newest prerelease commit and EmuELEC v4.8), read with the shared parser. Cores come from each OS's own ES list. AmberELEC and EmuELEC declare neogeo/ and ports/ beside bios/ from /storage/roms, so their packs extract there and core_destination puts core files under bios/.
This commit is contained in:
1 parent
2fc62bd249
commit
2bdac466a9
18 files changed
+12933
-24
No files matched your search
@@ -0,0 +1,46 @@
|
||||
"""Exporter for AmberELEC's batocera-systems.
|
||||
|
||||
Batocera's script shape, so only the systems dict is rewritten. Two things
|
||||
differ. Paths are relative to /storage/roms, where the list also names
|
||||
neogeo/ beside bios/, and our destinations start there too. No entry carries
|
||||
an emulator or core gate: coreExists() lets an ungated item through for
|
||||
every build, and an addition is written the same way.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .base_exporter import BaseExporter
|
||||
from .baseline import NativeFile
|
||||
from .batocera_exporter import Exporter as BatoceraExporter
|
||||
|
||||
SOURCE_URL = (
|
||||
"https://raw.githubusercontent.com/AmberELEC/AmberELEC/dev"
|
||||
"/packages/amberelec/sources/scripts/batocera-systems"
|
||||
)
|
||||
|
||||
|
||||
class Exporter(BatoceraExporter):
|
||||
"""Write AmberELEC's batocera-systems, corrected."""
|
||||
|
||||
PATH_PREFIX = ""
|
||||
|
||||
@classmethod
|
||||
def writable(cls, fe: NativeFile, require: str = "") -> bool:
|
||||
# The list gates nothing on a runner, so an addition needs none.
|
||||
return BaseExporter.writable.__func__(cls, fe, require)
|
||||
|
||||
def _addition_keys(self, fe: NativeFile) -> list[tuple[str, str | None]] | None:
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
def platform_name() -> str:
|
||||
return "amberelec"
|
||||
|
||||
@staticmethod
|
||||
def file_modes() -> dict[str, int]:
|
||||
# 100755 at a21975bf (git/trees).
|
||||
return {"batocera-systems": 0o755}
|
||||
|
||||
@staticmethod
|
||||
def native_sources() -> dict[str, str]:
|
||||
return {"batocera-systems": SOURCE_URL}
|
||||
@@ -35,6 +35,27 @@ def _commented(text: str, position: int) -> bool:
|
||||
return "#" in _STRING.sub("", text[line_start:position])
|
||||
|
||||
|
||||
def _closing_line(text: str, start: int) -> int | None:
|
||||
"""Index of the line holding the brace that closes `systems = {`.
|
||||
|
||||
Read from the parsed module, never executed. None when the script does
|
||||
not parse or names no such assignment at line `start`.
|
||||
"""
|
||||
try:
|
||||
tree = ast.parse(text)
|
||||
except SyntaxError:
|
||||
return None
|
||||
for node in tree.body:
|
||||
if (
|
||||
isinstance(node, ast.Assign)
|
||||
and node.lineno - 1 == start
|
||||
and isinstance(node.value, ast.Dict)
|
||||
and node.end_lineno is not None
|
||||
):
|
||||
return node.end_lineno - 1
|
||||
return None
|
||||
|
||||
|
||||
def _note_key(text: str) -> tuple[str, str]:
|
||||
"""(file, zippedFile) of the item a line holds, ("", "") for none."""
|
||||
path = re.search(r'"file"\s*:\s*"([^"]+)"', text)
|
||||
@@ -55,6 +76,11 @@ class Exporter(BaseExporter):
|
||||
# (duckstation-sa), which its checker does not know.
|
||||
STANDALONE_RUNNERS = True
|
||||
|
||||
# What the script's paths add in front of a destination. Batocera's
|
||||
# paths are relative to /userdata and our destinations to its bios/;
|
||||
# AmberELEC's and EmuELEC's destinations already start at /storage/roms.
|
||||
PATH_PREFIX = "bios/"
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
# The emulator and core each system entry of the original is gated
|
||||
@@ -200,8 +226,7 @@ class Exporter(BaseExporter):
|
||||
alt = fe.native("alt_md5", "")
|
||||
if alt:
|
||||
item.append(f'"altmd5": "{alt}"')
|
||||
declared = fe.native("native_path", "")
|
||||
path = str(declared) if declared else f"bios/{fe.destination}"
|
||||
path = self.declared_path(fe)
|
||||
item.append(f'"file": "{path}"')
|
||||
zipped = fe.native("zipped_file", "")
|
||||
if zipped:
|
||||
@@ -209,6 +234,12 @@ class Exporter(BaseExporter):
|
||||
item.extend(self._runner_keys(originals.get(path)) if runner is None else runner)
|
||||
return "{ " + ", ".join(item) + " }"
|
||||
|
||||
@classmethod
|
||||
def declared_path(cls, fe: NativeFile) -> str:
|
||||
"""The `file` the script names for an entry."""
|
||||
declared = fe.native("native_path", "")
|
||||
return str(declared) if declared else f"{cls.PATH_PREFIX}{fe.destination}"
|
||||
|
||||
@staticmethod
|
||||
def _own_entry(system: NativeSystem, before: dict | None) -> dict:
|
||||
"""The maintainer's entry for this system, out of the parsed pair."""
|
||||
@@ -396,6 +427,9 @@ class Exporter(BaseExporter):
|
||||
(i for i in range(start + 1, len(lines)) if lines[i].startswith("}")),
|
||||
None,
|
||||
)
|
||||
if end is None:
|
||||
# EmuELEC closes the dict with an indented brace.
|
||||
end = _closing_line(original, start)
|
||||
if end is None:
|
||||
raise ValueError("batocera-systems: the systems dict is not closed")
|
||||
return lines[: start + 1], lines[start + 1 : end], lines[end:]
|
||||
@@ -520,14 +554,12 @@ class Exporter(BaseExporter):
|
||||
content = produced[self.native_filename()]
|
||||
issues: list[str] = []
|
||||
|
||||
block = content.split("\nsystems = {", 1)
|
||||
if len(block) != 2:
|
||||
return ["no systems dict in the output"]
|
||||
end = block[1].find("\n}")
|
||||
if end < 0:
|
||||
return ["the systems dict is not closed"]
|
||||
try:
|
||||
exported = ast.literal_eval("{" + block[1][:end] + "\n}")
|
||||
_head, body, _tail = self._split_original(content)
|
||||
except ValueError as exc:
|
||||
return [str(exc)]
|
||||
try:
|
||||
exported = ast.literal_eval("{" + "\n".join(body) + "\n}")
|
||||
except (SyntaxError, ValueError) as exc:
|
||||
return [f"the systems dict does not parse: {exc}"]
|
||||
|
||||
@@ -541,8 +573,7 @@ class Exporter(BaseExporter):
|
||||
continue
|
||||
declared = {bios.get("file", "") for bios in entry.get("biosFiles", [])}
|
||||
for fe in files:
|
||||
path = str(fe.native("native_path", "")) or f"bios/{fe.destination}"
|
||||
if path not in declared:
|
||||
if self.declared_path(fe) not in declared:
|
||||
issues.append(f"absent: {system.native_id}/{fe.name}")
|
||||
|
||||
for native_id, entry in exported.items():
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
"""Exporter for EmuELEC's batocera-systems.
|
||||
|
||||
AmberELEC's case: paths relative to /storage/roms with ports/ and neogeo/
|
||||
beside bios/, and no runner gate, since EmuELEC's checkBios never reads one.
|
||||
The dict closes on an indented brace.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .amberelec_exporter import Exporter as AmberELECExporter
|
||||
|
||||
SOURCE_URL = (
|
||||
"https://raw.githubusercontent.com/EmuELEC/EmuELEC/master"
|
||||
"/packages/sx05re/emuelec/bin/batocera/batocera-systems"
|
||||
)
|
||||
|
||||
|
||||
class Exporter(AmberELECExporter):
|
||||
"""Write EmuELEC's batocera-systems, corrected."""
|
||||
|
||||
@staticmethod
|
||||
def platform_name() -> str:
|
||||
return "emuelec"
|
||||
|
||||
@staticmethod
|
||||
def file_modes() -> dict[str, int]:
|
||||
# 100755 at v4.8 (git/trees).
|
||||
return {"batocera-systems": 0o755}
|
||||
|
||||
@staticmethod
|
||||
def native_sources() -> dict[str, str]:
|
||||
return {"batocera-systems": SOURCE_URL}
|
||||
@@ -0,0 +1,31 @@
|
||||
"""Exporter for KNULLI's knulli-systems.
|
||||
|
||||
A fork of Batocera's script, checked the same way: es_systems names a
|
||||
libretro core under `libretro` and a standalone by itself, and entries carry
|
||||
Batocera's emulator and core gates.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .batocera_exporter import Exporter as BatoceraExporter
|
||||
|
||||
SOURCE_URL = (
|
||||
"https://raw.githubusercontent.com/knulli-cfw/knulli-linux/knulli-main"
|
||||
"/package/system/knulli-scripts/scripts/knulli-systems"
|
||||
)
|
||||
|
||||
|
||||
class Exporter(BatoceraExporter):
|
||||
"""Write KNULLI's knulli-systems, corrected."""
|
||||
|
||||
@staticmethod
|
||||
def platform_name() -> str:
|
||||
return "knulli"
|
||||
|
||||
@staticmethod
|
||||
def native_filename() -> str:
|
||||
return "knulli-systems"
|
||||
|
||||
@staticmethod
|
||||
def native_sources() -> dict[str, str]:
|
||||
return {"knulli-systems": SOURCE_URL}
|
||||
Reference in new issue
Block a user