mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
This squashes all local history (768 commits) onto the scrubbed PR #90 baseline. Individual commits were lost during filter-repo corruption; the working tree content is preserved intact. Build: N/A (working tree state only)
83 lines
2.4 KiB
Python
83 lines
2.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Emit a machine-readable manifest of the build substrate."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import subprocess
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
|
|
|
|
def sha256_file(path: Path) -> str:
|
|
digest = hashlib.sha256()
|
|
with path.open("rb") as handle:
|
|
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
|
|
digest.update(chunk)
|
|
return digest.hexdigest()
|
|
|
|
|
|
def run(*args: str) -> str:
|
|
completed = subprocess.run(
|
|
list(args),
|
|
check=True,
|
|
text=True,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
)
|
|
return completed.stdout.strip()
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--root", required=True, help="Workspace root to inspect.")
|
|
parser.add_argument("--output", required=True, help="Path to the JSON manifest output.")
|
|
return parser.parse_args()
|
|
|
|
|
|
def main() -> int:
|
|
args = parse_args()
|
|
root = Path(args.root).resolve()
|
|
output = Path(args.output).resolve()
|
|
lock_path = root / "components.lock.json"
|
|
lock = json.loads(lock_path.read_text(encoding="utf-8"))
|
|
|
|
tracked = []
|
|
for component in lock["components"]:
|
|
rel_path = component["path"]
|
|
full_path = root / rel_path
|
|
tracked.append(
|
|
{
|
|
"path": rel_path,
|
|
"sha256": sha256_file(full_path),
|
|
}
|
|
)
|
|
|
|
os_release_path = Path("/etc/os-release")
|
|
|
|
manifest = {
|
|
"schema": "hutter_build_manifest_v1",
|
|
"generated_utc": datetime.now(timezone.utc).isoformat(),
|
|
"root": str(root),
|
|
"os_release": os_release_path.read_text(encoding="utf-8")
|
|
if os_release_path.is_file()
|
|
else "",
|
|
"tool_versions": {
|
|
"python3": run("python3", "--version"),
|
|
"xz": run("xz", "--version").splitlines()[0],
|
|
"tar": run("tar", "--version").splitlines()[0],
|
|
"gcc": run("gcc", "--version").splitlines()[0],
|
|
},
|
|
"apk_world": run("apk", "info", "-vv"),
|
|
"tracked_components": tracked,
|
|
}
|
|
|
|
output.write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
|
|
print(f"Wrote build manifest to {output}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|