Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions tools/artifact_manifest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env python3
"""Build a reproducible artifact manifest with file sizes and hashes."""

from __future__ import annotations

import argparse
import hashlib
import json
from pathlib import Path
from tempfile import TemporaryDirectory

PATTERNS = ["build/**/*.so", "benchmark/**/*.log", "logs/**/*", "*.txt"]


def sha256(path: Path) -> str:
h = hashlib.sha256()
with path.open("rb") as f:
for chunk in iter(lambda: f.read(1024 * 1024), b""):
h.update(chunk)
return h.hexdigest()


def collect(root: Path) -> dict[str, object]:
if not root.is_dir():
raise NotADirectoryError(f"artifact root is not a directory: {root}")

seen: set[str] = set()
artifacts: list[dict[str, object]] = []
for pattern in PATTERNS:
for path in sorted(root.glob(pattern)):
if not path.is_file():
continue
rel = path.relative_to(root).as_posix()
if rel in seen:
continue
seen.add(rel)
artifacts.append(
{"path": rel, "bytes": path.stat().st_size, "sha256": sha256(path)}
)
return {"root": str(root), "count": len(artifacts), "artifacts": artifacts}


def self_test() -> None:
with TemporaryDirectory() as tmp_dir:
root = Path(tmp_dir)
sample = root / "artifact_manifest_sample.txt"
sample.write_text("maca artifact\n", encoding="utf-8")
data = collect(root)
if not any(item["path"] == sample.name for item in data["artifacts"]):
raise RuntimeError(f"self-test failed: {data}")
print(json.dumps({"ok": True, "count": data["count"]}, ensure_ascii=False))


def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--root", default=".")
parser.add_argument("--self-test", action="store_true")
args = parser.parse_args()
if args.self_test:
self_test()
return 0
root = Path(args.root)
if not root.is_dir():
parser.error(f"--root is not a directory: {root}")
print(json.dumps(collect(root), ensure_ascii=False, indent=2))
return 0
Comment on lines +58 to +66

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the directory specified by --root does not exist or is not a directory, collect will silently return an empty list of artifacts with a success exit code (0). This can be highly misleading to users who might have misspelled the path.

Validating that the path exists and is a directory using parser.error() provides immediate, clear feedback and prevents silent failures.

Suggested change
args = parser.parse_args()
if args.self_test:
self_test()
return 0
print(json.dumps(collect(Path(args.root)), ensure_ascii=False, indent=2))
return 0
args = parser.parse_args()
if args.self_test:
self_test()
return 0
root_path = Path(args.root)
if not root_path.is_dir():
parser.error(f"Root path '{root_path}' is not a directory or does not exist.")
print(json.dumps(collect(root_path), ensure_ascii=False, indent=2))
return 0



if __name__ == "__main__":
raise SystemExit(main())