fix: a game build is recognised before the archive integrity test, so re-extract no longer stalls on it
CI and images / lint (push) Successful in 2s
CI and images / extension-version (push) Successful in 2s
CI and images / frontend-build (push) Successful in 24s
CI and images / extension-test (push) Successful in 18s
CI and images / backend-lint-and-test (push) Successful in 47s
CI and images / integration (push) Successful in 2m44s
CI and images / sign-extension (push) Successful in 3s
CI and images / build-agent (push) Successful in 5s
CI and images / build-web (push) Successful in 2m1s
CI and images / smoke-web (push) Successful in 49s
CI and images / promote (push) Successful in 1s
CI and images / refresh-dev (push) Skipped
CI and images / unattended-failure (push) Skipped
CI and images / lint (push) Successful in 2s
CI and images / extension-version (push) Successful in 2s
CI and images / frontend-build (push) Successful in 24s
CI and images / extension-test (push) Successful in 18s
CI and images / backend-lint-and-test (push) Successful in 47s
CI and images / integration (push) Successful in 2m44s
CI and images / sign-extension (push) Successful in 3s
CI and images / build-agent (push) Successful in 5s
CI and images / build-web (push) Successful in 2m1s
CI and images / smoke-web (push) Successful in 49s
CI and images / promote (push) Successful in 1s
CI and images / refresh-dev (push) Skipped
CI and images / unattended-failure (push) Skipped
The archive probe read and checksummed every member before the importer looked at what the archive held. For a multi-gigabyte game build that is minutes of work on a file that is kept whole and never extracted, and it held a re-extract chunk far past its time budget. - The importer checks the archive's directory for a software build first, for the outer archive and for one nested inside an art pack, and only probes archives it may extract. - The probe rejects an archive over the size cap from its directory totals, before the integrity test decompresses anything. - Re-extract logs each archive as it starts and finishes, with its size and how long it took, so an archive that stalls a chunk is named in the log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -175,12 +175,20 @@ def _run_probe(path_str: str) -> tuple[str, str | None]:
|
||||
return ("ok", None)
|
||||
|
||||
|
||||
def _over_cap(total) -> bool:
|
||||
return total is not None and total > MAX_ARCHIVE_UNCOMPRESSED_BYTES
|
||||
|
||||
|
||||
def _inspect_archive(path: Path):
|
||||
"""Return (total_uncompressed_bytes | None, first_bad_member | None)
|
||||
for the archive. Format detected by extension OR magic bytes (so a
|
||||
mis-named archive is still bomb-guarded + integrity-tested, matching the
|
||||
extractor's gate); raises on a structurally-broken container (caught by the
|
||||
child as a clean rejection)."""
|
||||
child as a clean rejection).
|
||||
|
||||
The size total comes from the archive's directory, so an archive over the
|
||||
cap is rejected before the integrity test decompresses anything: on a
|
||||
multi-gigabyte archive that test alone outlasts the probe's timeout."""
|
||||
from ..services.archive_extractor import detect_archive_format
|
||||
|
||||
fmt = detect_archive_format(path)
|
||||
@@ -189,12 +197,16 @@ def _inspect_archive(path: Path):
|
||||
|
||||
with zipfile.ZipFile(path) as zf:
|
||||
total = sum(zi.file_size for zi in zf.infolist())
|
||||
if _over_cap(total):
|
||||
return total, None
|
||||
return total, zf.testzip()
|
||||
if fmt == "rar":
|
||||
import rarfile
|
||||
|
||||
with rarfile.RarFile(path) as rf:
|
||||
total = sum(getattr(ri, "file_size", 0) for ri in rf.infolist())
|
||||
if _over_cap(total):
|
||||
return total, None
|
||||
rf.testrar()
|
||||
return total, None
|
||||
if fmt == "7z":
|
||||
@@ -203,6 +215,8 @@ def _inspect_archive(path: Path):
|
||||
with py7zr.SevenZipFile(path, "r") as zf:
|
||||
info = zf.archiveinfo()
|
||||
total = getattr(info, "uncompressed", None)
|
||||
if _over_cap(total):
|
||||
return total, None
|
||||
ok = zf.test() # True / None when all members pass
|
||||
return total, (None if ok in (True, None) else "7z test reported corruption")
|
||||
# Not a recognised archive — nothing to test; treat as clean.
|
||||
|
||||
Reference in New Issue
Block a user