aboutsummaryrefslogtreecommitdiffstats
path: root/prototypes/connections/check_source_package.py
blob: 5bc2f150304aaf8d3393cb3cb20747584a967f13 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/env python3
"""Verify a source snapshot after safe extraction and a clean native build."""
import argparse
import hashlib
import json
from pathlib import Path
import subprocess
import tarfile
import tempfile

PREFIX = 'pure-source-preview/'


def run(*args, timeout=120):
    result = subprocess.run([str(arg) for arg in args], capture_output=True, timeout=timeout)
    if result.returncode:
        raise AssertionError((result.args, result.returncode,
                              result.stdout[-2000:], result.stderr[-2000:]))
    return result


def check(archive, release, peer, copy_range, flat_export, mirror, hybrid_tui):
    archive = archive.resolve()
    checks = []
    with tempfile.TemporaryDirectory(prefix='pure-source-extracted-') as directory:
        root = Path(directory)
        package = root / PREFIX[:-1]
        with tarfile.open(archive, 'r:gz') as bundle:
            members = bundle.getmembers()
            names = [member.name for member in members]
            assert len(names) == len(set(names))
            assert all(member.isfile() and member.name.startswith(PREFIX) and
                       '..' not in Path(member.name).parts for member in members)
            for member in members:
                destination = root / member.name
                destination.parent.mkdir(parents=True, exist_ok=True)
                destination.write_bytes(bundle.extractfile(member).read())
        manifest = json.loads((package / 'manifest.json').read_text())
        assert manifest['format'] == 'pure-source-preview-1'
        assert set(names) == {PREFIX + name for name in manifest['files']} | {PREFIX + 'manifest.json'}
        for name, metadata in manifest['files'].items():
            content = (package / name).read_bytes()
            assert len(content) == metadata['bytes']
            assert hashlib.sha256(content).hexdigest() == metadata['sha256']
        checks.append('every extracted source file matches the manifest')

        connections = package / 'prototypes/connections'
        run('make', '-C', connections, timeout=120)
        default_outputs = {path.name for path in (connections / 'build').iterdir()}
        assert default_outputs == {'runtime.o', 'libpure-execution.a',
                                   'pure-compile', 'embedded-plan.h',
                                   'pure-edit-fixed'}, default_outputs
        checks.append('clean default build contains only the core, parser-free CLI and its build-time compiler')
        run('make', '-C', connections, 'check-native-checkpoint', timeout=300)
        checks.append('clean C17, both real terminal PTY scenarios and fixed/source CLI document RSS checks pass')
        run('make', '-C', connections, 'fixed-editor')
        editor = connections / 'build/pure-edit'
        fixed = connections / 'build/pure-edit-fixed'
        program = connections / 'examples/editor.pure'
        store = root / 'document-store'
        insert = root / 'insert.bin'
        insert.write_bytes(b'hello Pure')
        written = run(editor, '--program', program, '--store', store,
                      'edit', 'note', '0', '0', '0', insert)
        assert json.loads(written.stdout) == {'revision': '1', 'reply_bytes': 10}
        assert run(fixed, '--store', store, 'show', 'note').stdout == b'hello Pure'
        checks.append('source-loaded CLI and parser-free CLI share the real stored document')

        changed = root / 'changed.pure'
        source = program.read_text()
        assert 'reply(saved, edit.insert);' in source
        changed.write_text(source.replace('reply(saved, edit.insert);', 'reply(saved);'))
        changed_store = root / 'changed-store'
        changed_result = run(editor, '--program', changed, '--store', changed_store,
                             'edit', 'note', '0', '0', '0', insert)
        assert json.loads(changed_result.stdout) == {'revision': '1', 'reply_bytes': 0}
        checks.append('editing .pure changes the native source-loaded reply')

        if peer:
            run('make', '-C', connections, 'check-portable-peer', timeout=180)
            checks.append('clean native TLS client and both server profiles pass authenticated document work')

        if copy_range:
            run('make', '-C', connections, 'check-copy-range', timeout=240)
            checks.append('clean selected Linux copy path passes app, scale, size, RSS and traced one-MiB splice')

        if flat_export:
            run('make', '-C', connections, 'check-flat-export', timeout=180)
            checks.append('clean selected page store exports mixed revisions to the default flat store')

        if mirror:
            run('make', '-C', connections, 'check-mirror', timeout=180)
            checks.append('clean one-MiB document fans out to two same-process Pure domains with independent conflict and release')

        if hybrid_tui:
            run('make', '-C', connections, 'BUILD=build/hybrid', 'STORE=store-paged.c',
                'editor', 'source-tui', timeout=120)
            run('python3', connections / 'check_tui.py', '--build',
                connections / 'build/hybrid', '--source', timeout=120)
            selected = root / 'hybrid-tui.tar.gz'
            run('python3', connections / 'package_native.py', '--build',
                connections / 'build/hybrid', '--hybrid-storage', '--with-tui',
                '--output', selected, timeout=120)
            run('python3', connections / 'check_package.py', selected, timeout=120)
            checks.append('clean selected page store runs the source-loaded TUI and relocatable CLI+TUI package')

        if release:
            run('make', '-C', connections, 'check-release', timeout=180)
            checks.append('clean Linux release behavior, code, dependency and RSS gates pass')
            run('make', '-C', connections, 'check-source-tui', timeout=120)
            checks.append('clean source-loaded terminal editor PTY scenarios pass')
    return {'archive_sha256': hashlib.sha256(archive.read_bytes()).hexdigest(),
            'archive_bytes': archive.stat().st_size, 'source_files': len(manifest['files']),
            'checks': checks}


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('archive', type=Path)
    parser.add_argument('--release', action='store_true', help='also run Linux release gates')
    parser.add_argument('--peer', action='store_true',
                        help='also build and exercise the optional TLS client and servers')
    parser.add_argument('--copy-range', action='store_true',
                        help='also check the opt-in Linux file copy path with strace')
    parser.add_argument('--flat-export', action='store_true',
                        help='also check selected paged-to-default document store export')
    parser.add_argument('--mirror', action='store_true',
                        help='also check one-process document fan-out through two Pure domains')
    parser.add_argument('--hybrid-tui', action='store_true',
                        help='also build and relocate the selected 16 KiB-page native terminal app')
    parser.add_argument('--output', type=Path)
    args = parser.parse_args()
    if args.output and args.output.exists():
        parser.error('evidence file already exists')
    result = check(args.archive, args.release, args.peer, args.copy_range,
                   args.flat_export, args.mirror, args.hybrid_tui)
    text = json.dumps(result, indent=2) + '\n'
    if args.output:
        args.output.parent.mkdir(parents=True, exist_ok=True)
        args.output.write_text(text)
    print(text, end='')


if __name__ == '__main__':
    main()