Files
m2pack-secure/scripts/runtime_smoke_wine.py
2026-04-14 17:25:17 +02:00

154 lines
4.9 KiB
Python
Executable File

#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import os
import subprocess
import sys
from pathlib import Path
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Temporarily switch selected legacy client packs to .m2p and run the Wine login smoke test."
)
parser.add_argument(
"--runtime-root",
type=Path,
required=True,
help="Client runtime root containing pack/ and config/.",
)
parser.add_argument(
"--client-repo",
type=Path,
required=True,
help="Path to m2dev-client-src checkout.",
)
parser.add_argument(
"--master-key",
type=Path,
required=True,
help="Path to m2pack runtime master key file.",
)
parser.add_argument(
"--key-id",
type=str,
default="1",
help="Runtime key_id to inject into the client.",
)
parser.add_argument(
"--timeout",
type=int,
default=20,
help="Wine run timeout in seconds.",
)
parser.add_argument(
"--pack",
dest="packs",
action="append",
required=True,
help="Pack basename to test as .m2p. Repeat for multiple packs.",
)
parser.add_argument(
"--json",
action="store_true",
help="Emit machine-readable JSON result.",
)
return parser.parse_args()
def activate_pack(pack_dir: Path, pack_name: str, moved: list[tuple[Path, Path]]) -> None:
offsingle = pack_dir / f"{pack_name}.m2p.offsingle"
m2p = pack_dir / f"{pack_name}.m2p"
legacy = pack_dir / f"{pack_name}.pck"
legacy_backup = pack_dir / f"{pack_name}.pck.testbak"
if offsingle.exists():
offsingle.rename(m2p)
moved.append((m2p, offsingle))
if legacy.exists():
legacy.rename(legacy_backup)
moved.append((legacy_backup, legacy))
def restore_moves(moved: list[tuple[Path, Path]]) -> None:
for src, dst in reversed(moved):
if src.exists():
src.rename(dst)
def main() -> int:
args = parse_args()
runtime_root = args.runtime_root.resolve()
client_repo = args.client_repo.resolve()
pack_dir = runtime_root / "pack"
run_script = client_repo / "scripts" / "run-wine-headless.sh"
build_bin = client_repo / "build-mingw64-lld" / "bin"
log_dir = build_bin / "log"
if not pack_dir.is_dir():
raise SystemExit(f"runtime pack dir not found: {pack_dir}")
if not run_script.is_file():
raise SystemExit(f"wine runner not found: {run_script}")
if not (build_bin / "Metin2_RelWithDebInfo.exe").is_file():
raise SystemExit(f"client binary not found: {build_bin / 'Metin2_RelWithDebInfo.exe'}")
moved: list[tuple[Path, Path]] = []
try:
for pack_name in args.packs:
activate_pack(pack_dir, pack_name, moved)
log_dir.mkdir(parents=True, exist_ok=True)
for file_path in log_dir.glob("*.txt"):
file_path.unlink(missing_ok=True)
for file_path in [build_bin / "syserr.txt", build_bin / "ErrorLog.txt"]:
file_path.unlink(missing_ok=True)
env = os.environ.copy()
env["M2PACK_MASTER_KEY_HEX"] = args.master_key.read_text(encoding="utf-8").strip()
env["M2PACK_KEY_ID"] = args.key_id
env["M2_TIMEOUT"] = str(args.timeout)
env.setdefault("WINEDEBUG", "-all")
completed = subprocess.run(
[str(run_script), str(build_bin)],
cwd=client_repo,
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
prototype_trace = (log_dir / "prototype_trace.txt").read_text(encoding="utf-8", errors="ignore") if (log_dir / "prototype_trace.txt").exists() else ""
system_trace = (log_dir / "system_py_trace.txt").read_text(encoding="utf-8", errors="ignore") if (log_dir / "system_py_trace.txt").exists() else ""
syserr = (build_bin / "syserr.txt").read_text(encoding="utf-8", errors="ignore") if (build_bin / "syserr.txt").exists() else ""
result = {
"ok": "SetLoginPhase ok" in prototype_trace,
"returncode": completed.returncode,
"packs": args.packs,
"prototype_tail": prototype_trace.strip().splitlines()[-10:],
"system_tail": system_trace.strip().splitlines()[-10:],
"syserr_tail": syserr.strip().splitlines()[-10:],
}
if args.json:
print(json.dumps(result, indent=2))
else:
print(f"packs={','.join(args.packs)} ok={result['ok']} returncode={completed.returncode}")
if result["prototype_tail"]:
print("prototype tail:")
for line in result["prototype_tail"]:
print(f" {line}")
return 0 if result["ok"] else 1
finally:
restore_moves(moved)
if __name__ == "__main__":
sys.exit(main())