"""Bounded read-only UI capture of one exact private Workbench run; no input API.""" from pathlib import Path import hashlib,importlib.util,json,os,re,sys,time sys.path.insert(0,'/home/jakub/devel/escapistsrereintroduced/tools') from headless_display_probe import process,environment,ancestor,identity,owned_sockets,validate_display,executable_argument,X11 profile=Path('/home/jakub/devel/escapistsrereintroduced/.build/objective-map-profile-0832-final') out=Path('/home/jakub/devel/escapistsrereintroduced/.build/objective-map-final-ui-0832');out.mkdir(exist_ok=False) prefix='/tmp/erri-headless-compat/pfx' executable=Path('/home/jakub/.local/share/Steam/steamapps/common/Arma Reforger Tools/Workbench/ArmaReforgerWorkbenchSteamDiag.exe') spec=importlib.util.spec_from_file_location('capture','/tmp/erri-private-window-capture.py') capture=importlib.util.module_from_spec(spec);spec.loader.exec_module(capture) pending={'standard-long-warning','standard-rough','standard-exact','standard-reopened','shared-root','shared-long-warning','shared-reused-root'} records=[];deadline=time.monotonic()+240 while pending and time.monotonic()0 assert identity(process(p['pid']))==identity(p) and identity(process(scope['pid']))==identity(scope) assert owned_sockets(number,scope['pid'])==sockets for name in ready: path=out/(name+'.png');capture.capture(display,str(path),chosen['window']) latest=re.findall(r'ERR OBJECTIVE CAPTURE READY: ([a-z-]+)',logs[0].read_text(errors='replace')) assert latest and latest[-1]==name, 'Capture crossed native stage boundary' record={'stage':name,'sha256':hashlib.sha256(path.read_bytes()).hexdigest(),'workbench':identity(p),'gamescope':identity(scope),'display':display,'window':chosen,'sockets':sockets,'profile':str(profile),'read_only':True} records.append(record);pending.remove(name);print(name,flush=True) (out/'captures.json').write_text(json.dumps(records,indent=2)+'\n') finally:query.close() break except (FileNotFoundError,ProcessLookupError,PermissionError,ValueError):continue if 'ERR SMOKE FAIL:' in text or 'ERR SMOKE COMPLETE:' in text:break time.sleep(.1) if pending:raise RuntimeError('Missing bounded UI captures: '+str(sorted(pending)))