Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a09c77-b1a9-7eb3-b501-6cb24b458c97
53 lines
1.7 KiB
Python
53 lines
1.7 KiB
Python
"""Atomic content-addressed JSON and source artifact storage."""
|
|
import hashlib
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import tempfile
|
|
|
|
|
|
def canonical(value):
|
|
return json.dumps(value, sort_keys=True, separators=(',', ':'), ensure_ascii=False,
|
|
allow_nan=False).encode('utf-8')
|
|
|
|
|
|
def atomic(path, data, immutable=False):
|
|
path = Path(path)
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
fd, name = tempfile.mkstemp(dir=path.parent, prefix='.write-')
|
|
try:
|
|
with os.fdopen(fd, 'wb') as stream:
|
|
stream.write(data)
|
|
stream.flush()
|
|
os.fsync(stream.fileno())
|
|
if immutable:
|
|
try:
|
|
os.link(name, path)
|
|
except FileExistsError:
|
|
if path.read_bytes() != data:
|
|
raise ValueError(f'immutable content mismatch: {path}') from None
|
|
else:
|
|
os.replace(name, path)
|
|
finally:
|
|
Path(name).unlink(missing_ok=True)
|
|
|
|
|
|
def put(root, kind, value):
|
|
content = canonical(value)
|
|
ident = hashlib.sha256(content).hexdigest()
|
|
atomic(Path(root) / 'data' / kind / f'{ident}.json', content + b'\n', immutable=True)
|
|
return ident
|
|
|
|
|
|
def get(root, kind, ident):
|
|
if len(ident) != 64 or any(c not in '0123456789abcdef' for c in ident):
|
|
raise ValueError('invalid content ID')
|
|
value = json.loads((Path(root) / 'data' / kind / f'{ident}.json').read_text())
|
|
if hashlib.sha256(canonical(value)).hexdigest() != ident:
|
|
raise ValueError(f'integrity mismatch: {kind}/{ident}')
|
|
return value
|
|
|
|
|
|
def all_records(root, kind):
|
|
return [(p.stem, get(root, kind, p.stem))
|
|
for p in sorted((Path(root) / 'data' / kind).glob('*.json'))]
|