swayfx-mosaic/tooling/probes/step20c-scenefx-abi-package/seal.py

36 lines
2 KiB
Python

#!/usr/bin/env python3
"""Seal completed source/evidence inventories once, or verify existing bytes.
WHY: derived reports cannot silently overwrite the evidence they cite.
CONTRACT: fixtures finalized first; report/diff are captured outside inventory.
INVARIANT: no manifest replacement, no binaries/build trees in source inventory.
"""
import argparse
import hashlib
from pathlib import Path
p=argparse.ArgumentParser(description=__doc__);p.add_argument('lab',type=Path)
p.add_argument('--verify',action='store_true');a=p.parse_args();lab=a.lab.resolve()
fixture=Path(__file__).resolve().parent;repo=fixture.parents[2]
assert lab.is_relative_to(Path.home()) and lab!=Path.home() and not lab.is_relative_to(repo)
r=lab/'results'
def sha(path):return hashlib.sha256(path.read_bytes()).hexdigest()
if not a.verify:
assert not any((r/(name+'-sha256.txt')).exists() for name in ['source','evidence'])
source=set(p for p in fixture.iterdir() if p.is_file())
for tree in ['stock','scene-pristine','scene-private','wlroots-source','mosaic-private']:
source.update(p for p in (lab/tree).rglob('*') if p.is_file() and 'subprojects' not in p.relative_to(lab/tree).parts)
source.update(p for p in (lab/'patches').iterdir() if p.is_file())
source.update(p for p in lab.iterdir() if p.is_file() and p.suffix in ['.py','.c','.md'])
evidence=set(p for p in (lab/'raw').iterdir() if p.is_file())
evidence.update(p for p in r.iterdir() if p.is_file() and not p.name.endswith('-sha256.txt'))
for name,files in [('source',source),('evidence',evidence)]:
manifest=r/(name+'-sha256.txt')
# Exclusive creation, never truncate a prior result on interrupted runs.
with manifest.open('x') as out:
for path in sorted(files):out.write(f'{sha(path)} {path}\n')
for name in ['source','evidence']:
path=r/(name+'-sha256.txt');lines=path.read_text().splitlines()
for line in lines:
expected,filename=line.split(' ',1);assert sha(Path(filename))==expected,filename
print(name,len(lines),sha(path),'PASS')