Record the annotated rebuild, bounded graphics matrices, private release-shape smoke, and remaining integration gates. Preserve STEP20C NEXT and production multi-output NOT YET SUPPORTED.
102 lines
7.3 KiB
Python
102 lines
7.3 KiB
Python
"""WHY: requalify annotated identity without inheriting historical graphics.
|
|
CONTRACT: pinned replay gate before reserved one-shot builds.
|
|
INVARIANT: historical LAB read only; no semantic source edit or build retry.
|
|
"""
|
|
import sys, json, hashlib, shutil, subprocess, tarfile, re, time, os, argparse
|
|
from pathlib import Path
|
|
parser=argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument('lab',type=Path)
|
|
parser.add_argument('--historical',type=Path,required=True)
|
|
args=parser.parse_args()
|
|
LAB=args.lab.resolve(); D=args.historical.resolve()
|
|
REPO=Path(__file__).resolve().parents[3]
|
|
assert LAB != D and not LAB.is_relative_to(REPO)
|
|
LAB.mkdir(exist_ok=True)
|
|
sys.path.insert(0,str(REPO/'tooling/probes/step20c-overnight'))
|
|
from ledger import initialize,reserve as debit
|
|
for name in ('scripts','raw','results','patches'): (LAB/name).mkdir(exist_ok=True)
|
|
initialize(LAB/'budget.json')
|
|
for name in ('support.py','audit-d.py','qualify-d.py','stage-d.py'):
|
|
shutil.copy2(D/'scripts'/name,LAB/'scripts'/name)
|
|
p=LAB/'scripts/support.py';txt=p.read_text();start=txt.index('def reserve(');end=txt.index('\ndef environment()',start)
|
|
txt=txt[:start]+"def reserve(lab, kind):\n import sys\n sys.path.insert(0, '"+str(REPO/'tooling/probes/step20c-overnight')+"')\n from ledger import reserve as debit\n return debit(Path(lab)/'budget.json', kind)\n"+txt[end:]
|
|
# Every command records wall time/date/return code, including failed diagnostics.
|
|
txt=txt.replace("lab=Path(lab); path=", "started=time.time(); lab=Path(lab); path=")
|
|
txt=txt.replace("'env':extra or {},'exit':proc.returncode", "'env':extra or {},'exit':proc.returncode,'started_unix':started,'duration_s':time.time()-started")
|
|
p.write_text(txt)
|
|
sys.path.insert(0,str(LAB/'scripts'))
|
|
from support import command,save,sha,reserve
|
|
|
|
def treehash(root):
|
|
entries=[{'path':str(p.relative_to(root)),'sha256':sha(p),'mode':oct(p.stat().st_mode&0o777)} for p in sorted(root.rglob('*')) if p.is_file()]
|
|
return hashlib.sha256(json.dumps(entries,sort_keys=True,separators=(',',':')).encode()).hexdigest()
|
|
|
|
def tokens(text):
|
|
# Strings/chars are consumed before comment syntax; comments inside literals survive.
|
|
expr=r'"(?:\\.|[^"\\])*"|\'(?:\\.|[^\'\\])*\'|/\*.*?\*/|//[^\n]*|[A-Za-z_]\w*|(?:\d[\w.]*)|[^\s]'
|
|
return [m.group(0) for m in re.finditer(expr,text,re.S) if not m.group(0).startswith(('/*','//'))]
|
|
|
|
state={'status':'RUNNING','source_gate':'NOT RUN','graphics':'NOT TESTED','historical':str(D)}
|
|
def checkpoint(): (LAB/'phase-a.json').write_text(json.dumps(state,indent=2)+'\n')
|
|
try:
|
|
versions=json.loads((D/'results/source-versions.json').read_text())
|
|
components=json.loads((D/'results/component-patches.json').read_text())
|
|
for name in ('mosaic-source','swayfx-source','scene-source','wlroots-source'):
|
|
arc=LAB/(name+'.tar');shutil.copy2(D/(name+'.tar'),arc)
|
|
assert sha(arc)==versions['archives'][arc.name]
|
|
if name in ('mosaic-source','swayfx-source'):
|
|
rev=versions['pins']['Mosaic' if name=='mosaic-source' else 'SwayFX']
|
|
with (LAB/(name+'-git-check.tar')).open('wb') as out:subprocess.run(['git','-C',str(REPO),'archive',rev],stdout=out,check=True)
|
|
assert sha(LAB/(name+'-git-check.tar'))==sha(arc)
|
|
(LAB/name).mkdir()
|
|
with tarfile.open(arc) as tf:tf.extractall(LAB/name,filter='data')
|
|
state['components']=[]
|
|
for item in components['ordered_patches']:
|
|
tree=LAB/item['tree'];src=Path(item['source']);patch=LAB/'patches'/src.name
|
|
assert sha(src)==sha(Path(item['candidate_path']))==item['sha256']
|
|
shutil.copy2(src,patch)
|
|
assert treehash(tree)==item['parent_tree_sha256']
|
|
command(LAB,'replay-'+src.stem+'-check',['git','apply','--check',patch],tree)
|
|
command(LAB,'replay-'+src.stem+'-apply',['git','apply',patch],tree)
|
|
assert treehash(tree)==item['result_tree_sha256']
|
|
state['components'].append({**item,'replayed_path':str(patch),'verified':True})
|
|
for name in ('mosaic-source','scene-source'):
|
|
assert treehash(LAB/name)==treehash(D/name)
|
|
manifest=json.loads((D/'comment-repair/repair-manifest.json').read_text())
|
|
before={row['path']:(LAB/row['path']).read_text() for row in manifest['files']}
|
|
for row in manifest['files']:assert sha(LAB/row['path'])==row['parent_sha256']
|
|
for name,digest in manifest['patches'].items():
|
|
patch=LAB/'patches'/name;shutil.copy2(D/'comment-repair'/name,patch);assert sha(patch)==digest
|
|
command(LAB,'comment-'+name+'-check',['git','apply','--check',patch],LAB)
|
|
command(LAB,'comment-'+name+'-apply',['git','apply',patch],LAB)
|
|
for row in manifest['files']:
|
|
assert sha(LAB/row['path'])==row['result_sha256']
|
|
assert tokens(before[row['path']])==tokens((LAB/row['path']).read_text())
|
|
state.update(source_gate='PASS',comments=manifest,source_trees={name:treehash(LAB/name) for name in ('scene-source','mosaic-source')})
|
|
assert sha(Path('/usr/lib/libwlroots-0.20.so').resolve())=='7edca9a7d65855addda68e29ba5db94d57c803eb5fa7d0f86db3136b90ca9837'
|
|
save(LAB,'source-versions',versions);checkpoint();print('SOURCE_GATE_PASS',flush=True)
|
|
command(LAB,'compiler',['cc','--version']);command(LAB,'meson-version',['meson','--version'])
|
|
command(LAB,'dependencies',['pkg-config','--modversion','wlroots-0.20','scenefx-0.5','wayland-server','wayland-client','wayland-protocols','libdrm','xkbcommon','pixman-1'])
|
|
reserve(LAB,'scene_build')
|
|
command(LAB,'scene-setup',['meson','setup',LAB/'scene-build',LAB/'scene-source','--prefix=/usr','-Ddefault_library=static','-Dexamples=false','-Dwerror=false'])
|
|
command(LAB,'scene-build',['meson','compile','-C',LAB/'scene-build','-j','8'])
|
|
reserve(LAB,'mosaic_build')
|
|
extra={'PKG_CONFIG_PATH':str(LAB/'scene-build/meson-uninstalled')}
|
|
flags=['--prefix=/usr','--bindir=bin','-Dwerror=false','-Dsd-bus-provider=libsystemd','-Dmosaic-package=true','-Dswaybar=false','-Dswaynag=false','-Dman-pages=disabled','-Ddefault-wallpaper=false']
|
|
command(LAB,'mosaic-setup',['meson','setup',LAB/'mosaic-build',LAB/'mosaic-source',*flags],extra=extra)
|
|
command(LAB,'mosaic-build',['meson','compile','-C',LAB/'mosaic-build','-j','8'],extra=extra)
|
|
state['builds']='PASS';checkpoint();print('BUILDS_PASS',flush=True)
|
|
command(LAB,'mosaic-model',['meson','test','-C',LAB/'mosaic-build','--no-rebuild','mosaic-model','--print-errorlogs'])
|
|
save(LAB,'static-build',{'status':'PASS','flags':flags,'options':json.loads((LAB/'mosaic-build/meson-info/intro-buildoptions.json').read_text()),'archive_sha256':sha(LAB/'scene-build/libscenefx-0.5.a'),'binary_sha256':sha(LAB/'mosaic-build/sway/swayfx-mosaic')})
|
|
reserve(LAB,'stage')
|
|
command(LAB,'meson-stage',['meson','install','-C',LAB/'mosaic-build','--no-rebuild','--destdir',LAB/'stage-static'])
|
|
for script,args in [('audit-d.py',[LAB]),('qualify-d.py',[]),('stage-d.py',[LAB])]:
|
|
command(LAB,script,['python',LAB/'scripts'/script,*args],timeout=600)
|
|
state['binary']=json.loads((LAB/'results/binary-elf.json').read_text())
|
|
state['stage']=json.loads((LAB/'results/static-stage-manifest.json').read_text())
|
|
state['ABI']='PASS local layout/headers/85-symbol characterization; semantic maintenance NOT ESTABLISHED'
|
|
state['status']='PASS'
|
|
except Exception as exc:
|
|
state['status']='FAIL';state['error']=repr(exc);raise
|
|
finally:
|
|
state['budget']=json.loads((LAB/'budget.json').read_text());checkpoint()
|