feat: add mod editing, revision merges and secure game storage
Add immutable revisions, PGVN editor, asset replacement, merge and rebase workflows, authenticated media delivery and reachability GC. Harden the script interpreter, pin unrpyc and remove tracked build metadata. Include current compatibility checks, Naninovel import and regression tests.
This commit is contained in:
1 parent
06ff19ac4a
commit
c8d83b3fe7
65 files changed
+3825
-68
No files matched your search
@@ -16,15 +16,16 @@ def _safe_target(root: Path, name: str) -> Path | None:
|
||||
return target if target.is_relative_to(root.resolve()) else None
|
||||
|
||||
|
||||
def extract(archive: Path, filename: str, dest: Path) -> None:
|
||||
def extract(archive: Path, filename: str, dest: Path, *, only_scripts: bool = False) -> None:
|
||||
dest.mkdir(parents=True, exist_ok=True)
|
||||
if filename.lower().endswith(".zip") and zipfile.is_zipfile(archive):
|
||||
_extract_zip(archive, dest)
|
||||
_extract_zip(archive, dest, only_scripts=only_scripts)
|
||||
return
|
||||
seven = shutil.which("7zz") or shutil.which("7z")
|
||||
if not seven:
|
||||
raise ArchiveError("Для этого формата нужен 7-Zip (7zz), он не установлен")
|
||||
proc = subprocess.run([seven, "x", "-y", "-snl-", f"-o{dest}", str(archive)],
|
||||
filters = [f"-ir!*{suffix}" for suffix in SCRIPT_EXTS | {".tar"}] if only_scripts else []
|
||||
proc = subprocess.run([seven, "x", "-y", "-snl-", *filters, f"-o{dest}", str(archive)],
|
||||
capture_output=True, text=True)
|
||||
if proc.returncode not in (0, 1): # 1 = warnings
|
||||
raise ArchiveError(f"7-Zip: {proc.stderr.strip() or proc.stdout.strip()[-500:]}")
|
||||
@@ -33,14 +34,19 @@ def extract(archive: Path, filename: str, dest: Path) -> None:
|
||||
inner = list(dest.iterdir())
|
||||
if len(inner) == 1 and inner[0].suffix == ".tar":
|
||||
tar = inner[0]
|
||||
extract(tar, tar.name, dest / "_tar")
|
||||
extract(tar, tar.name, dest / "_tar", only_scripts=only_scripts)
|
||||
tar.unlink()
|
||||
|
||||
|
||||
def _extract_zip(archive: Path, dest: Path) -> None:
|
||||
SCRIPT_EXTS = {".rpy", ".rpyc", ".rpa", ".rpym", ".rpymc"}
|
||||
|
||||
|
||||
def _extract_zip(archive: Path, dest: Path, *, only_scripts: bool = False) -> None:
|
||||
with zipfile.ZipFile(archive) as zf:
|
||||
for info in zf.infolist():
|
||||
name = info.filename
|
||||
if only_scripts and Path(name).suffix.lower() not in SCRIPT_EXTS:
|
||||
continue
|
||||
if info.flag_bits & 0x800 == 0:
|
||||
# legacy zips store names in cp437; many were really written as cp866/utf-8
|
||||
try:
|
||||
|
||||
Reference in new issue
Block a user