69 lines
4.4 KiB
Python
69 lines
4.4 KiB
Python
"""Prepare a new disposable canvas trial; retain the real GUI process exit code."""
|
|
from pathlib import Path
|
|
from datetime import datetime, timezone
|
|
import hashlib
|
|
import json
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
|
|
root = Path(__file__).resolve().parent.parent
|
|
trial = root / '.local/native-qa/canvas-paint-d61f1f3-20260912-01'
|
|
mode = sys.argv[1]
|
|
if mode == 'prepare':
|
|
assert not trial.exists(), 'Never overwrite a native trial'
|
|
sources = {
|
|
'compact-baseline': root / '.local/native-qa/delete-20260912/compact-baseline-v2',
|
|
'compact-work': root / '.local/native-qa/delete-20260912/compact-baseline-v2',
|
|
'bound-baseline': root / 'harness/experiments/canvas-editing-followup-20260912/bound-nested-fixture-r1-20260912',
|
|
'bound-work': root / 'harness/experiments/canvas-editing-followup-20260912/bound-nested-fixture-r1-20260912',
|
|
'draft-work': root / 'harness/experiments/canvas-editing-followup-20260912/nested-call-fixture-20260912',
|
|
'process-work': root / 'harness/fixtures/source7-native/base',
|
|
}
|
|
assert all(path.is_dir() for path in sources.values())
|
|
trial.mkdir()
|
|
rows = []
|
|
for label, source in sources.items():
|
|
shutil.copytree(source, trial / label)
|
|
for path in sorted(source.rglob('*')):
|
|
if path.is_file():
|
|
relative = path.relative_to(source)
|
|
raw = path.read_bytes()
|
|
assert (trial / label / relative).read_bytes() == raw
|
|
rows.append({'path': f'{label}/{relative.as_posix()}', 'source': str(path.relative_to(root)), 'bytes': len(raw), 'sha256': hashlib.sha256(raw).hexdigest()})
|
|
for label in ['profile/Desktop', 'profile/Documents', 'profile/AppData/Local', 'profile/AppData/Roaming', 'temp', 'evidence']:
|
|
(trial / label).mkdir(parents=True, exist_ok=True)
|
|
(trial / 'preparation.json').write_text(json.dumps({'utc': datetime.now(timezone.utc).isoformat(), 'files': rows}, indent=2) + '\n', encoding='utf-8', newline='\n')
|
|
print(json.dumps({'trial': str(trial), 'identical_fixture_files': len(rows)}))
|
|
elif mode == 'launch':
|
|
assert (trial / 'preparation.json').is_file()
|
|
assert not (trial / 'launch.json').exists()
|
|
stage = Path(sys.argv[2]).resolve()
|
|
assert stage.is_relative_to(root / '.local/native-qa')
|
|
record = json.loads((stage / 'manifest.json').read_bytes())
|
|
for gate in ['full', 'clippy', 'gui']:
|
|
result = record['results'][gate]
|
|
assert result['exit'] == 0 and not result['changed_inputs']
|
|
assert result['source'] == record['source'], 'Require same-source gates for this production correction'
|
|
for name in ['arcadia-studio.exe', 'libunwind.dll']:
|
|
raw = (stage / name).read_bytes()
|
|
assert len(raw) == record['artifacts'][name]['bytes']
|
|
assert hashlib.sha256(raw).hexdigest() == record['artifacts'][name]['sha256']
|
|
env = {key: os.environ[key] for key in ['SystemRoot', 'WINDIR', 'SystemDrive', 'ProgramData', 'ALLUSERSPROFILE', 'PUBLIC', 'COMSPEC', 'PATHEXT', 'NUMBER_OF_PROCESSORS', 'PROCESSOR_ARCHITECTURE', 'OS'] if key in os.environ}
|
|
profile = trial / 'profile'
|
|
windows = Path(env['SystemRoot'])
|
|
env.update({'PATH': os.pathsep.join(map(str, [stage, windows / 'System32', windows])), 'USERPROFILE': str(profile), 'LOCALAPPDATA': str(profile / 'AppData/Local'), 'APPDATA': str(profile / 'AppData/Roaming'), 'TEMP': str(trial / 'temp'), 'TMP': str(trial / 'temp')})
|
|
with (trial / 'stdout.log').open('xb') as out, (trial / 'stderr.log').open('xb') as err:
|
|
process = subprocess.Popen([str(stage / 'arcadia-studio.exe')], cwd=trial, env=env, stdin=subprocess.DEVNULL, stdout=out, stderr=err, creationflags=subprocess.CREATE_NO_WINDOW)
|
|
launch = {'utc': datetime.now(timezone.utc).isoformat(), 'pid': process.pid, 'source': record['source'], 'binary': str(stage / 'arcadia-studio.exe'), 'sha256': record['artifacts']['arcadia-studio.exe']['sha256'], 'private_profile': str(profile)}
|
|
(trial / 'launch.json').write_text(json.dumps(launch, indent=2) + '\n', encoding='utf-8', newline='\n')
|
|
print(json.dumps(launch), flush=True)
|
|
code = process.wait()
|
|
closure = {'utc': datetime.now(timezone.utc).isoformat(), 'pid': process.pid, 'exit': code}
|
|
(trial / 'closure.json').write_text(json.dumps(closure, indent=2) + '\n', encoding='utf-8', newline='\n')
|
|
print(json.dumps(closure), flush=True)
|
|
sys.exit(code)
|
|
else:
|
|
raise SystemExit('Expected prepare or launch STAGED_DIRECTORY')
|