dcs_liberation/game/zipfileext.py
Dan Albert 0f34946127 Restructure save games into a zipped bundle.
This is the first step toward bundling all assets related to a save game
into a single item. That makes it easier to avoid clobbering "temporary"
assets from other games like the state.json, but also makes it easier
for players to file bug reports, since there's only a single asset to
upload.

This is only the first step because so far it only includes the various
save files: start of turn, end of last turn before results processing,
and "latest" (the game saved explicitly by the player).
2023-01-16 13:59:16 -08:00

35 lines
1.4 KiB
Python

import shutil
from pathlib import Path
from tempfile import TemporaryDirectory
from zipfile import ZipFile
class ZipFileExt:
@staticmethod
def remove_member(path: Path, name: str, missing_ok: bool = False) -> None:
"""Replaces the archive with a copy that excludes one member.
This is needed to workaround Python's lack of a ZipFile.remove() or a way to
overwrite existing members. Attempting to update a member in a zipfile will
write a duplicate entry: https://github.com/python/cpython/issues/51067.
"""
with ZipFile(path, "r") as zip_file:
if name not in zip_file.namelist():
if missing_ok:
return
raise ValueError(f"Cannot override {name} as it does not exist")
# Doing this by extracting all the files to a temporary directory is faster than
# reading and writing a file at a time (1-5 seconds vs 0.5 seconds for a save
# bundle).
with TemporaryDirectory() as temp_dir_str:
temp_dir = Path(temp_dir_str)
shutil.unpack_archive(path, temp_dir)
(temp_dir / name).unlink()
shutil.make_archive(
# shutil.make_archive automatically adds the extension
str(path.with_suffix("")),
"zip",
root_dir=temp_dir_str,
)