File size: 1,815 Bytes
ecad52f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/env python3
"""Rebuild the exact source ZIP from a verified extracted release, offline."""
import hashlib
import json
import sys
import zipfile
from pathlib import Path
from safe_json import strict_loads
from verify_release import verify_release


def build_archive(root, target):
    root, target = Path(root).resolve(), Path(target).resolve()
    if target.is_relative_to(root):
        raise ValueError("Write the ZIP outside the extracted release directory")
    checked = verify_release(root)
    if not checked["verified"]:
        raise ValueError("Source integrity check failed")
    manifest = strict_loads((root / "RELEASE_MANIFEST.json").read_text(encoding="utf-8"))
    names = sorted([*manifest["files"], "RELEASE_MANIFEST.json"])
    with target.open("xb") as handle:
        with zipfile.ZipFile(handle, "w", compression=zipfile.ZIP_STORED) as archive:
            for name in names:
                entry = zipfile.ZipInfo(name, date_time=(1980, 1, 1, 0, 0, 0))
                entry.create_system = 3
                entry.external_attr = 0o100644 << 16
                entry.compress_type = zipfile.ZIP_STORED
                archive.writestr(entry, (root / name).read_bytes())
    data = target.read_bytes()
    return {"built": True, "bytes": len(data), "files": len(names), "sha256": hashlib.sha256(data).hexdigest(), "sha512": hashlib.sha512(data).hexdigest()}


if __name__ == "__main__":
    try:
        if len(sys.argv) != 2:
            raise ValueError("Usage: python -B build_archive.py ../rebuilt.zip")
        result = build_archive(Path(__file__).resolve().parent, sys.argv[1])
        print(json.dumps(result, sort_keys=True))
    except (ValueError, OSError, zipfile.BadZipFile) as exc:
        print(json.dumps({"built": False, "error": str(exc)}))
        sys.exit(2)