Package Apple Silicon VM exports and cached runtime switching with local cabinet controls and conagent provisioning. Preserve experimental SPIKE 2 emulation. Improve preparation concurrency, Ghidra checkpoints, signature importing, sound indexing and client-side spectrograms. Include regression tests and validation notes.
97 lines
3.9 KiB
Python
97 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Read-only inventory for the supplied SPIKE 3 process emulator.
|
|
|
|
Does not execute donor code, prepare images, install tools, or read credentials.
|
|
Passing this inventory does not establish that a game can boot.
|
|
"""
|
|
import argparse
|
|
import json
|
|
import platform
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
|
|
SOURCE_FILES = (
|
|
"emulation/spike3-emu",
|
|
"emulation/process/spike3_emu.py",
|
|
"emulation/process/config.default.json",
|
|
"emulation/machine/service.py",
|
|
"emulation/machine/profiles/pokemon-pro.json",
|
|
"emulation/dashboard/server.py",
|
|
"emulation/vpx/layout.json",
|
|
)
|
|
RUNTIME_FILES = (
|
|
"games/pokemon_pro/game",
|
|
"games/pokemon_pro/image.bin",
|
|
"games/pokemon_pro/assets/godot/main.pck",
|
|
"games/pokemon_pro/spike3/spike_menu/game",
|
|
"games/pokemon_pro/spike3/spike_menu/image.bin",
|
|
"games/pokemon_pro/spike3/bin/boot_display",
|
|
"lib/ld-linux-aarch64.so.1",
|
|
)
|
|
|
|
|
|
def inventory(source: Path, runtime: Path) -> dict:
|
|
machine = platform.machine().lower()
|
|
native = machine in ("aarch64", "arm64")
|
|
checks = []
|
|
for category, root, paths in (
|
|
("source", source, SOURCE_FILES), ("runtime", runtime, RUNTIME_FILES)
|
|
):
|
|
for relative in paths:
|
|
path = root / relative
|
|
checks.append({"category": category, "name": relative,
|
|
"present": path.is_file(), "path": str(path)})
|
|
commands = [(name,) for name in (
|
|
"python3", "bwrap", "ffmpeg", "ffplay", "Xvfb", "x11vnc", "websockify"
|
|
)]
|
|
commands += [("readelf", "objdump")]
|
|
commands += [("cc", "gcc")] if native else [
|
|
("aarch64-linux-gnu-gcc",), ("qemu-aarch64-static", "qemu-aarch64")
|
|
]
|
|
for alternatives in commands:
|
|
found = next((path for command in alternatives
|
|
if (path := shutil.which(command))), None)
|
|
checks.append({"category": "tool", "name": " or ".join(alternatives),
|
|
"present": found is not None, "path": found})
|
|
return {
|
|
"schema": 1,
|
|
"platform": platform.system(),
|
|
"architecture": machine,
|
|
"suggested_engine": "native" if native else "qemu-user",
|
|
"inventory_complete": platform.system() == "Linux" and all(
|
|
check["present"] for check in checks
|
|
),
|
|
"boot_verified": False,
|
|
"checks": checks,
|
|
"limitations": [
|
|
"Inventory targets the donor's default Linux process/display path.",
|
|
"Library closure, ELF architecture, Mesa, noVNC assets, namespace permissions, and boot still require launcher validation.",
|
|
"The current launcher expects source and runtime in one workspace; a separate runtime root here is inventory only.",
|
|
"This inventories the standalone donor, not the Verstack Docker worker. Use emulator/README.md to test the integrated screen/audio and session controls.",
|
|
],
|
|
}
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--source", type=Path, default=Path.home() / "pokemon_emulator")
|
|
parser.add_argument("--runtime", type=Path, help="Extracted runtime root; defaults to source")
|
|
parser.add_argument("--json", action="store_true", help="Print structured inventory")
|
|
args = parser.parse_args()
|
|
source = args.source.expanduser().resolve()
|
|
result = inventory(source, (args.runtime or source).expanduser().resolve())
|
|
if args.json:
|
|
print(json.dumps(result, indent=2))
|
|
else:
|
|
print(f"SPIKE 3 inventory: {result['platform']} {result['architecture']} ({result['suggested_engine']})")
|
|
for check in result["checks"]:
|
|
print(f"{'FOUND' if check['present'] else 'MISSING'} {check['category']}: {check['name']}")
|
|
for limitation in result["limitations"]:
|
|
print(limitation)
|
|
return 0 if result["inventory_complete"] else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|