Files
rose-ash/artdag/core/scripts/compute_repo_hash.py
giles 1a74d811f7
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m33s
Incorporate art-dag-mono repo into artdag/ subfolder
Merges full history from art-dag/mono.git into the monorepo
under the artdag/ directory. Contains: core (DAG engine),
l1 (Celery rendering server), l2 (ActivityPub registry),
common (shared templates/middleware), client (CLI), test (e2e).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

git-subtree-dir: artdag
git-subtree-mainline: 1a179de547
git-subtree-split: 4c2e716558
2026-02-27 09:07:23 +00:00

68 lines
1.4 KiB
Python

#!/usr/bin/env python3
"""
Compute content hash of a git repository.
Hashes all tracked files (respects .gitignore) in sorted order.
"""
import hashlib
import subprocess
import sys
from pathlib import Path
def repo_hash(repo_path: Path) -> str:
"""
Compute SHA3-256 hash of all tracked files in a repo.
Uses git ls-files to respect .gitignore.
Files are hashed in sorted order for determinism.
Each file contributes: relative_path + file_contents
"""
# Get list of tracked files
result = subprocess.run(
["git", "ls-files"],
cwd=repo_path,
capture_output=True,
text=True,
check=True,
)
files = sorted(result.stdout.strip().split("\n"))
hasher = hashlib.sha3_256()
for rel_path in files:
if not rel_path:
continue
file_path = repo_path / rel_path
if not file_path.is_file():
continue
# Include path in hash
hasher.update(rel_path.encode())
# Include contents
with open(file_path, "rb") as f:
for chunk in iter(lambda: f.read(65536), b""):
hasher.update(chunk)
return hasher.hexdigest()
def main():
if len(sys.argv) > 1:
repo_path = Path(sys.argv[1])
else:
repo_path = Path.cwd()
h = repo_hash(repo_path)
print(f"Repository: {repo_path}")
print(f"Hash: {h}")
return h
if __name__ == "__main__":
main()