fix: build only recipes whose members match

This commit is contained in:
Abdessamad Derraz committed 2026-10-17 15:00:35 +02:00
1 parent b3783e0780
commit 1ca37e429e
2 files changed
+55 -1

No files matched your search

+24 -1
View File
@@ -165,15 +165,38 @@ class AtomPool:
def identify_archive(
path: Path, recipes: dict[str, Recipe], pool: AtomPool
) -> str | None:
"""Return the recipe label that reproduces *path* byte for byte."""
"""Return the recipe label that reproduces *path* byte for byte.
Equal bytes need equal (name, crc32) members, which the archive's
central directory gives without inflating anything: building every
recipe at DEFLATE level 9 first took 94 s and 1 GB at pipeline step 1c.
"""
held = _member_list(path)
if held is None:
return None
original = path.read_bytes()
for label, recipe in sorted(recipes.items()):
if sorted((name, crc.lower()) for name, crc in recipe) != held:
continue
blob = pool.build(recipe)
if blob is not None and blob == original:
return label
return None
def _member_list(path: Path) -> list[tuple[str, str]] | None:
"""Sorted (name, crc32) of an archive's members, from its directory."""
try:
with zipfile.ZipFile(path) as archive:
return sorted(
(info.filename, format(info.CRC, "08x"))
for info in archive.infolist() if not info.is_dir()
)
except (zipfile.BadZipFile, OSError) as exc:
print(f" UNREADABLE: {path}: {exc}", file=sys.stderr)
return None
def reconstruct(
target_md5: str, recipes: dict[str, Recipe], pool: AtomPool
) -> tuple[str, bytes] | None: