Подготовить автономную сборку и запуск перед разделением проектов
This commit is contained in:
@@ -20,7 +20,7 @@ mame_interactive.py — автотест .exe в MAME без участия че
|
||||
автоповтор (typematic) и слипание scancode'ов.
|
||||
- загрузка должна встать на приглашении C:\> (system.bat не должен
|
||||
автозапускать Flex Navigator/приложение).
|
||||
- перед запуском проверяем, что нет висящих копий MAME.
|
||||
- тестовый носитель, конфигурация и состояние MAME изолированы от других сессий.
|
||||
|
||||
Использование:
|
||||
python3 toolchain/mame_interactive.py [exe] [--data f ...] \
|
||||
@@ -53,27 +53,16 @@ mame_interactive.py — автотест .exe в MAME без участия че
|
||||
|
||||
import argparse
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import uuid
|
||||
|
||||
from mame_profile import MameProfile, add_arguments, from_arguments, write_keyboard_config
|
||||
|
||||
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
MAME_DIR = os.path.join(PROJECT_ROOT, "mame", "v306")
|
||||
IMG_DIR = os.path.join(MAME_DIR, "IMG")
|
||||
MC_IMG = os.path.join(IMG_DIR, "mc.img")
|
||||
SNAP_DIR = os.path.join(MAME_DIR, "snap_auto")
|
||||
LUA_SCRIPT = os.path.join(MAME_DIR, "_interactive_gen.lua")
|
||||
|
||||
COMMON_ARGS = [
|
||||
"-skip_gameinfo", "-video", "opengl", "-window", "-nofilter",
|
||||
"-beta:wd179x:0", "35hd", "-beta:wd179x:1", "35hd",
|
||||
"-flop1", MC_IMG, "-flop2", os.path.join(IMG_DIR, "dss171u.img"),
|
||||
"-isa0", "zxbus_adapter", "-isa0:zxbus_adapter:card", "neogs",
|
||||
"-hard1", os.path.join(IMG_DIR, "sp_hdd_sys.chd"),
|
||||
"-hard2", os.path.join(IMG_DIR, "sp_hdd_media.chd"),
|
||||
"-ata2:0", "cdrom", "-cdrom", os.path.join(IMG_DIR, "SprinterCD.iso"),
|
||||
"-bios", "v3.06",
|
||||
]
|
||||
|
||||
# --- Раскладка AT-клавиатуры :kbd:ms_naturl (tag, mask) ---
|
||||
# Снято дампом ioport-полей в MAME (см. docs/mame-autotest.md).
|
||||
@@ -207,21 +196,7 @@ emu.register_periodic(function()
|
||||
end
|
||||
end)
|
||||
"""
|
||||
with open(LUA_SCRIPT, "w") as f:
|
||||
f.write(lua)
|
||||
|
||||
|
||||
def check_no_stray_mame():
|
||||
# Ловим только запущенный ЭМУЛЯТОР (mame/mame.arm/mame.exe c машиной
|
||||
# sprinter), а не всё, где в командной строке встречается «mame»:
|
||||
# голый паттерн ложно срабатывал на параллельную сборку MAME из
|
||||
# исходников (clang/make с путями .../src/mame/...).
|
||||
out = subprocess.run(["pgrep", "-fl", r"mame[^ ]* sprinter( |$)"],
|
||||
capture_output=True, text=True).stdout
|
||||
if out.strip():
|
||||
print("ОШИБКА: есть запущенные копии MAME — закройте их:")
|
||||
print(out)
|
||||
sys.exit(1)
|
||||
return lua
|
||||
|
||||
|
||||
def parse_step(s):
|
||||
@@ -234,6 +209,7 @@ def parse_step(s):
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
add_arguments(ap)
|
||||
ap.add_argument("exe", nargs="?", help=".exe на дискету A: (авто-запуск)")
|
||||
ap.add_argument("--data", nargs="*", default=[], help="доп. файлы на дискету")
|
||||
ap.add_argument("--launch-at", type=float, default=8.0,
|
||||
@@ -242,9 +218,15 @@ def main():
|
||||
help="'T:TEXT' — в момент T сек напечатать TEXT (можно много)")
|
||||
ap.add_argument("--snap", default=None, help="секунды для скриншотов, через запятую")
|
||||
ap.add_argument("--timeout", type=float, default=None, help="сек эмуляции до выхода")
|
||||
ap.add_argument("--snapshot-dir", help="каталог кадров, по умолчанию build/mame-autotest")
|
||||
args = ap.parse_args()
|
||||
|
||||
check_no_stray_mame()
|
||||
profile = from_arguments(args)
|
||||
if profile.binary is None and (Path(PROJECT_ROOT)/"mame/v306/mame.arm").is_file():
|
||||
profile = MameProfile.resolve({"MAME_HOME":str(Path(PROJECT_ROOT)/"mame/v306")})
|
||||
try:
|
||||
profile.validate(dss=True)
|
||||
except ValueError as error:
|
||||
ap.error(str(error))
|
||||
|
||||
# Собираем шаги ввода: авто-запуск exe (печать пути) + пользовательские.
|
||||
steps = list(args.step)
|
||||
@@ -272,7 +254,7 @@ def main():
|
||||
snap_times = [last_ev_t + pad, last_ev_t + pad + 2.0]
|
||||
timeout = args.timeout if args.timeout is not None else (max(snap_times) + 1.5)
|
||||
|
||||
gen_lua(events, snap_times, timeout)
|
||||
lua_source = gen_lua(events, snap_times, timeout)
|
||||
|
||||
# Дискета БЕЗ авто-запускаемого bat → приглашение C:\>.
|
||||
disk_files = []
|
||||
@@ -280,34 +262,67 @@ def main():
|
||||
disk_files.append(exe_path)
|
||||
disk_files += [os.path.abspath(p) for p in args.data]
|
||||
|
||||
if os.path.exists(MC_IMG):
|
||||
shutil.copy(MC_IMG, MC_IMG + ".bak")
|
||||
make_disk_cmd = [sys.executable, os.path.join(MAME_DIR, "make_disk.py"), MC_IMG]
|
||||
subprocess.run(make_disk_cmd + disk_files, check=True, cwd=MAME_DIR)
|
||||
snapshot_base = Path(args.snapshot_dir or Path.cwd()/"build/mame-autotest")
|
||||
snapshot_root = snapshot_base.resolve()/uuid.uuid4().hex[:10]
|
||||
snapshot_root.mkdir(parents=True)
|
||||
with tempfile.TemporaryDirectory(prefix="sprinter-mame-autotest-") as directory:
|
||||
state = Path(directory)
|
||||
for name in ("cfg", "nvram", "diff"):
|
||||
(state/name).mkdir()
|
||||
write_keyboard_config(state/"cfg")
|
||||
disk = state/"test.img"
|
||||
subprocess.run([sys.executable, str(Path(PROJECT_ROOT)/"toolchain/make_disk.py"),
|
||||
str(disk), *disk_files], check=True)
|
||||
lua_script = state/"interactive.lua"
|
||||
lua_script.write_text(lua_source, encoding="utf-8")
|
||||
cmd = [str(profile.binary), "sprinter", "-noreadconfig",
|
||||
"-rompath", str(profile.rompath), "-bios", profile.bios,
|
||||
"-kbd", "ms_naturl,bios=sp2k", "-skip_gameinfo",
|
||||
"-video", "soft", "-window", "-beta:wd179x:0", "35hd",
|
||||
"-beta:wd179x:1", "35hd", "-flop1", str(disk),
|
||||
"-flop2", str(profile.dss_image),
|
||||
"-hard1", str(profile.system_hdd_image),
|
||||
"-isa0", "zxbus_adapter", "-isa0:zxbus_adapter:card", "neogs",
|
||||
"-snapshot_directory", str(snapshot_root),
|
||||
"-autoboot_script", str(lua_script)]
|
||||
for name in ("cfg", "nvram", "diff"):
|
||||
cmd += ["-"+name+"_directory", str(state/name)]
|
||||
if profile.home:
|
||||
media = profile.home/"IMG/sp_hdd_media.chd"
|
||||
optical = profile.home/"IMG/SprinterCD.iso"
|
||||
if media.is_file():
|
||||
test_media = state/"media.chd"
|
||||
shutil.copyfile(media, test_media)
|
||||
cmd += ["-hard2", str(test_media)]
|
||||
if optical.is_file():
|
||||
cmd += ["-ata2:0", "cdrom", "-cdrom", str(optical)]
|
||||
print("Ввод по шагам:", [(round(t, 2), repr(txt)) for t, txt in steps])
|
||||
print("Скриншоты (сек):", snap_times, " таймаут:", timeout)
|
||||
try:
|
||||
result = subprocess.run(cmd, cwd=state, capture_output=True,
|
||||
text=True, timeout=timeout+8)
|
||||
except subprocess.TimeoutExpired as error:
|
||||
print("MAME: истёк лимит времени", file=sys.stderr)
|
||||
output = error.stdout or ""
|
||||
stderr = error.stderr or ""
|
||||
if isinstance(output, bytes):
|
||||
output = output.decode(errors="replace")
|
||||
if isinstance(stderr, bytes):
|
||||
stderr = stderr.decode(errors="replace")
|
||||
result = subprocess.CompletedProcess(cmd, 124, output, stderr)
|
||||
for line in result.stdout.splitlines():
|
||||
if "[interactive]" in line:
|
||||
print(line)
|
||||
if result.returncode not in (0, 124):
|
||||
print("STDERR:", result.stderr[-2000:])
|
||||
|
||||
snap_sub = os.path.join(SNAP_DIR, "sprinter")
|
||||
if os.path.isdir(snap_sub):
|
||||
shutil.rmtree(snap_sub)
|
||||
|
||||
cmd = ["timeout", str(int(timeout) + 8), "./mame.arm", "sprinter"] + COMMON_ARGS + [
|
||||
"-snapshot_directory", SNAP_DIR,
|
||||
"-autoboot_script", LUA_SCRIPT,
|
||||
]
|
||||
print("Ввод по шагам:", [(round(t, 2), repr(txt)) for t, txt in steps])
|
||||
print("Скриншоты (сек):", snap_times, " таймаут:", timeout)
|
||||
result = subprocess.run(cmd, cwd=MAME_DIR, capture_output=True, text=True)
|
||||
for line in result.stdout.splitlines():
|
||||
if "[interactive]" in line:
|
||||
print(line)
|
||||
if result.returncode not in (0, 124):
|
||||
print("STDERR:", result.stderr[-2000:])
|
||||
|
||||
if os.path.isdir(snap_sub):
|
||||
snap_sub = snapshot_root/"sprinter"
|
||||
if snap_sub.is_dir():
|
||||
print("Скриншоты:")
|
||||
for s in sorted(os.listdir(snap_sub)):
|
||||
print(" ", os.path.join(snap_sub, s))
|
||||
for shot in sorted(snap_sub.iterdir()):
|
||||
print(" ", shot)
|
||||
else:
|
||||
print("Скриншотов не создано.")
|
||||
print("Скриншотов не создано. Каталог:", snapshot_root)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user