Files
maze32/scripts/verify_web_assets.py
T

69 lines
2.5 KiB
Python
Executable File

#!/usr/bin/env python3
"""Verify deterministic web generation and the checked-in generated assets."""
from __future__ import annotations
import gzip
import hashlib
import tempfile
from pathlib import Path
from generate_web_assets import generate_assets
PROJECT_DIRECTORY = Path(__file__).resolve().parent.parent
COMPRESSED_PAYLOAD_LIMIT = 1572864
def tree_digest(directory: Path) -> str:
digest = hashlib.sha256()
for path in sorted(item for item in directory.rglob("*") if item.is_file()):
digest.update(path.relative_to(directory).as_posix().encode("utf-8"))
digest.update(b"\0")
digest.update(path.read_bytes())
return digest.hexdigest()
def main() -> int:
source_directory = PROJECT_DIRECTORY / "web"
checked_in_directory = PROJECT_DIRECTORY / "data"
with tempfile.TemporaryDirectory(prefix="maze32-assets-") as temporary:
temporary_directory = Path(temporary)
first = temporary_directory / "first"
second = temporary_directory / "second"
generate_assets(source_directory, first)
generate_assets(source_directory, second)
first_digest = tree_digest(first)
second_digest = tree_digest(second)
checked_in_digest = tree_digest(checked_in_directory)
if first_digest != second_digest:
raise AssertionError("Repeated web-asset generation produced different output")
if first_digest != checked_in_digest:
raise AssertionError("Generated web assets are stale; regenerate the data directory")
for compressed_path in sorted(path for path in first.rglob("*.gz") if path.is_file()):
relative_path = compressed_path.relative_to(first)
source_relative = Path(str(relative_path)[:-3])
if gzip.decompress(compressed_path.read_bytes()) != (
source_directory / source_relative
).read_bytes():
raise AssertionError(f"Compressed asset does not reproduce {source_relative}")
compressed_size = sum(path.stat().st_size for path in first.rglob("*.gz"))
if compressed_size > COMPRESSED_PAYLOAD_LIMIT:
raise AssertionError(
f"Compressed web payload is {compressed_size} bytes and exceeds "
f"the {COMPRESSED_PAYLOAD_LIMIT}-byte limit"
)
print(
f"web asset reproducibility: PASS ({first_digest}, "
f"{compressed_size}/{COMPRESSED_PAYLOAD_LIMIT} bytes)"
)
return 0
if __name__ == "__main__":
raise SystemExit(main())