1#!/usr/bin/env python3
2"""Generate a reproducible TOC edit history that crosses log and counter boundaries."""
3import argparse
4from document_model import EXPORTER, view
5import hashlib
6import json
7from pathlib import Path
8import shutil
9import subprocess
10import tempfile
11
12ROOT = Path(__file__).resolve().parent.parent
13
14if __name__ == '__main__':
15 parser = argparse.ArgumentParser(description=__doc__)
16 parser.add_argument('source', type=Path)
17 parser.add_argument('destination', type=Path)
18 args = parser.parse_args()
19 if args.destination.resolve().is_relative_to(args.source.resolve()):
20 raise ValueError('Choose a destination outside the source notebook.')
21 args.destination.mkdir(parents=True, exist_ok=False)
22 notebook = args.destination / 'notebook'
23 shutil.copytree(args.source, notebook)
24 toc = notebook / 'Open Notebook.onetoc2'
25 original = toc.read_bytes()
26 doc = json.loads(subprocess.check_output([EXPORTER, toc]))
27 _, space = view(doc, doc['root']); oid = space['roots']['1']
28 color = space['nodes'][oid]['kind']['color']
29 history = []
30 with tempfile.TemporaryDirectory() as temporary:
31 source = Path(temporary) / 'current'
32 source.write_bytes(original)
33 for value in range(260):
34 destination = Path(temporary) / 'next'
35 subprocess.run([ROOT / 'target/debug/examples/edit_property', source, destination,
36 '20001', '14001cbe', color.to_bytes(4, 'little').hex(),
37 value.to_bytes(4, 'little').hex(), doc['root'], oid], check=True)
38 destination.replace(source)
39 history.append({'before': color, 'after': value})
40 color = value
41 toc.write_bytes(source.read_bytes())
42 (args.destination / 'history.json').write_text(json.dumps({
43 'source_sha256': hashlib.sha256(original).hexdigest(), 'space': doc['root'], 'object': oid,
44 'property': '14001cbe', 'operations': history, 'result_sha256': hashlib.sha256(toc.read_bytes()).hexdigest(),
45 }, indent=2))