Files
2026-09-17 22:59:47 +03:00

124 lines
5.3 KiB
Python

#!/usr/bin/env python3
"""Пути к установленному MAME; исходники fork приложению не нужны."""
from __future__ import annotations
from dataclasses import dataclass
import os
from pathlib import Path
import sys
import xml.etree.ElementTree as ET
@dataclass(frozen=True)
class MameProfile:
home: Path | None
binary: Path | None
rompath: Path | None
dss_image: Path | None
system_hdd_image: Path | None
bios: str
@classmethod
def resolve(cls, overrides: dict[str, str | None] | None = None) -> "MameProfile":
values = dict(os.environ)
values.update({key: value for key, value in (overrides or {}).items()
if value is not None})
home = _path(values.get("MAME_HOME"))
def selected(key: str, suffix: str) -> Path | None:
return _path(values.get(key)) or (home / suffix if home else None)
binary = _path(values.get("MAME_BIN"))
if binary is None and home:
# Новая Sprinter-сборка MAME.HT называется sprinter;
# старые установленные среды по-прежнему содержат mame.arm.
binary = next((home / name for name in ("sprinter", "mame.arm")
if (home / name).is_file()), home / "sprinter")
return cls(home=home,
binary=binary,
rompath=selected("MAME_ROMPATH", "roms"),
dss_image=selected("MAME_DSS_IMAGE", "IMG/dss171u.img"),
system_hdd_image=selected("MAME_SYSTEM_HDD_IMAGE", "IMG/sp_hdd_sys.chd"),
bios=values.get("MAME_BIOS") or "v3.06")
def validate(self, *, dss: bool = False, system_hdd: bool = True) -> None:
paths = {"MAME_BIN": self.binary, "MAME_ROMPATH": self.rompath}
if dss:
paths["MAME_DSS_IMAGE"] = self.dss_image
if system_hdd:
paths["MAME_SYSTEM_HDD_IMAGE"] = self.system_hdd_image
for variable, path in paths.items():
if path is None:
raise ValueError(f"задайте MAME_HOME или {variable}")
if not path.exists():
raise ValueError(f"{variable}: файл/каталог не найден: {path}")
if self.binary and not self.binary.is_file():
raise ValueError(f"MAME_BIN не является файлом: {self.binary}")
if self.rompath and not self.rompath.is_dir():
raise ValueError(f"MAME_ROMPATH не является каталогом: {self.rompath}")
def _path(value: str | None) -> Path | None:
if not value:
return None
return Path(os.path.expanduser(value)).resolve()
def add_arguments(parser) -> None:
"""Одинаковые аргументы для обычного запуска, автотеста и DAP."""
for option in ("mame-home", "mame-bin", "mame-rompath", "mame-dss-image",
"mame-system-hdd-image", "mame-bios"):
parser.add_argument("--" + option, default=None)
def from_arguments(args) -> MameProfile:
names = ("MAME_HOME", "MAME_BIN", "MAME_ROMPATH", "MAME_DSS_IMAGE",
"MAME_SYSTEM_HDD_IMAGE", "MAME_BIOS")
return MameProfile.resolve({name: getattr(args, name.lower(), None)
for name in names})
KEYBOARD_TAGS = (":", ":kbd:ms_naturl")
def write_keyboard_config(cfg_directory: Path) -> None:
"""Включить обе клавиатуры Sprinter, включая прямой ввод в DSS.
Если в каталоге уже лежит sprinter.cfg (например, скопированный из
MAME_HOME/cfg), остальные его настройки сохраняются, а в копии
включаются только нужные клавиатуры.
"""
cfg_directory.mkdir(parents=True, exist_ok=True)
path = cfg_directory / "sprinter.cfg"
root = None
if path.is_file():
try:
root = ET.parse(path).getroot()
except ET.ParseError as error:
print(f"mame_profile: {path} не разобран ({error}), создаётся заново",
file=sys.stderr)
if root is None or root.tag != "mameconfig":
root = ET.Element("mameconfig", version="10")
system = next((item for item in root.findall("system")
if item.get("name") == "sprinter"), None)
if system is None:
system = ET.SubElement(root, "system", name="sprinter")
input_node = system.find("input")
if input_node is None:
input_node = ET.SubElement(system, "input")
keyboards = {item.get("tag"): item for item in input_node.findall("keyboard")}
for tag in KEYBOARD_TAGS:
keyboard = keyboards.get(tag)
if keyboard is None:
keyboard = ET.Element("keyboard", tag=tag)
# MAME ожидает keyboard перед port внутри input.
position = sum(1 for item in input_node if item.tag == "keyboard")
input_node.insert(position, keyboard)
keyboard.set("enabled", "1")
tree = ET.ElementTree(root)
ET.indent(tree, space=" ")
tree.write(path, encoding="utf-8", xml_declaration=True)
with path.open("a", encoding="utf-8") as stream:
stream.write("\n")