nps: bundle pkg2zip binary and run it via Wine

pkg2zip's prebuilt releases are Windows-only, so ship pkg2zip.exe in
data/bin/ (MIT, mmozeiko) and invoke it through Wine on Linux. find_pkg2zip
prefers the bundled binary, then a configured path, then a native pkg2zip on
PATH. Adds data/bin/ATTRIBUTION.md and README credit.
This commit is contained in:
2026-09-07 22:14:14 -04:00
parent 6837481f2b
commit d458a9859c
4 changed files with 67 additions and 9 deletions
+23 -3
View File
@@ -9,6 +9,7 @@ folder.
from __future__ import annotations
import logging
import os
import shutil
import subprocess
import urllib.parse
@@ -142,14 +143,30 @@ def fetch_items(content_type: str, url: str = "", timeout: int = 60) -> List[dic
def find_pkg2zip(configured_path: str = "") -> Optional[Path]:
"""Locate the pkg2zip binary (configured path, else PATH)."""
"""Locate pkg2zip: configured path, then the bundled binary, then PATH."""
if configured_path:
p = Path(configured_path)
return p if p.is_file() else None
bundled = config.DATA_DIR / "bin" / "pkg2zip.exe"
if bundled.is_file():
return bundled
found = shutil.which("pkg2zip")
return Path(found) if found else None
def _pkg2zip_cmd(pkg2zip: Path) -> List[str]:
"""Command prefix for pkg2zip, wrapping the bundled .exe in Wine on Linux."""
if pkg2zip.suffix.lower() == ".exe" and os.name != "nt":
wine = shutil.which("wine") or shutil.which("wine64")
if not wine:
raise RuntimeError(
"The bundled pkg2zip is a Windows binary and Wine is not installed — "
"install Wine (or point Settings → Store at a native pkg2zip)."
)
return [wine, str(pkg2zip)]
return [str(pkg2zip)]
def _safe_folder(value: str) -> str:
import re
cleaned = re.sub(r"[^A-Za-z0-9]", "", value or "").upper()
@@ -180,10 +197,13 @@ def extract_pkg(pkg_path, title_id: str, dest_dir, pkg2zip: Path,
if progress_cb is not None:
progress_cb("Extracting", 0.0, "")
try:
cmd = _pkg2zip_cmd(pkg2zip) + ["-x", str(pkg_path)]
env = dict(os.environ)
env["WINEDEBUG"] = "-all" # silence Wine's console chatter
proc = subprocess.Popen(
[str(pkg2zip), "-x", str(pkg_path)],
cmd,
cwd=str(tmp), stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
text=True, bufsize=1,
text=True, bufsize=1, env=env,
)
assert proc.stdout is not None
for _line in proc.stdout: