1#!/usr/bin/env python3
2"""Cold-open a batch of disposable section candidates in isolated OneNote caches."""
3import argparse
4import hashlib
5import json
6from pathlib import Path
7import signal
8import zipfile
9from native_runner import ROOT, clone, command, windows, collect_artifacts
10
11
12def run(inputs, output, scripts=None):
13 output.mkdir(parents=True, exist_ok=False)
14 files = sorted(inputs.glob('*.one'))
15 assert files, 'No section candidates'
16 if scripts is None:
17 (output / 'scripts').mkdir()
18 scripts = [output / 'scripts' / name for name in ('cold.ps1', 'probe.ps1')]
19 for path in scripts: path.write_bytes((ROOT / 'tools/native' / path.name).read_bytes())
20 (output / 'run.json').write_text(json.dumps({'inputs': {p.name: hashlib.sha256(p.read_bytes()).hexdigest() for p in files},
21 'scripts': {p.name: hashlib.sha256(p.read_bytes()).hexdigest() for p in scripts}}, indent=2))
22 archive = output / 'inputs.zip'
23 try:
24 with zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED) as packed:
25 for path in files:
26 packed.writestr(path.name, path.read_bytes())
27 with clone(output) as name:
28 for local, remote in [(archive, r'C:\one-tests\inputs.zip'), (scripts[0], r'C:\one-tests\cold-current.ps1'),
29 (scripts[1], r'C:\one-tests\probe.ps1')]:
30 result = windows.do_put(local, remote, name)
31 if result.get('error'): raise RuntimeError(result['error'])
32 command(name, r'powershell -NoProfile -Command "Expand-Archive C:\one-tests\inputs.zip C:\one-tests\runs\capture\inputs"', output)
33 command(name, r'powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File C:\one-tests\probe.ps1 -Root C:\one-tests\runs\capture -CloneHost ONE-' + name.upper(), output, (len(files) * 60 + 120) * 1000)
34 collect_artifacts(name, output, r'results, C:\one-tests\runs\capture\results.json, C:\one-tests\runs\capture\progress.jsonl')
35 finally:
36 archive.unlink(missing_ok=True)
37
38
39if __name__ == '__main__':
40 parser = argparse.ArgumentParser(description=__doc__)
41 parser.add_argument('inputs', type=Path)
42 parser.add_argument('output', type=Path)
43 args = parser.parse_args()
44 def interrupted(_signum, _frame):
45 raise KeyboardInterrupt
46 signal.signal(signal.SIGTERM, interrupted)
47 run(args.inputs.resolve(), args.output.resolve())