Files
docview/tests/portal/record_build.py
T
2026-09-21 13:41:40 +09:00

58 lines
2.9 KiB
Python

#!/usr/bin/env python3
"""Freeze a complete passing build; keep earlier version evidence separate."""
import argparse
from datetime import datetime, timezone
import hashlib
import json
from pathlib import Path
import platform
import re
import subprocess
import xml.etree.ElementTree as ET
def sha(path):
with path.open('rb') as stream:
return hashlib.file_digest(stream, 'sha256').hexdigest()
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--source', type=Path, default=Path(__file__).resolve().parents[2])
parser.add_argument('--build', type=Path, required=True)
parser.add_argument('--ctest', type=Path, required=True)
parser.add_argument('--installed', type=Path)
parser.add_argument('--output', type=Path, required=True)
args = parser.parse_args()
cases = ET.parse(args.ctest / 'tests.xml').findall('.//testcase')
assert len(cases) == 22 and all(c.find('failure') is None and c.find('skipped') is None for c in cases)
files = [args.source / name for name in ('CMakeLists.txt', 'resources.qrc')]
for folder in ('src', 'qml', 'cmake', 'resources', 'tools', 'tests'):
files += [path for path in (args.source / folder).rglob('*')
if path.is_file() and not path.is_symlink() and '__pycache__' not in path.parts
and 'results' not in path.parts and 'fixtures' not in path.parts]
names = ['docview', 'docview-pdf-worker', 'docview-archive-worker', 'test_app',
'test_core', 'test_pdf', 'test_pdf_canvas', 'test_web_qml', 'test_translations']
value = {
'recordedAtUtc': datetime.now(timezone.utc).isoformat(),
'scope': 'Full CTest after URL representation fix; Xvfb/xcb, software rendering, internal sandboxes enabled',
'os': platform.freedesktop_os_release(), 'kernel': platform.release(),
'compiler': subprocess.check_output(['c++', '--version'], text=True).splitlines()[0],
'binaries': {name: sha(args.build / name) for name in names},
'sourceSha256': {str(path.relative_to(args.source)): sha(path) for path in sorted(set(files))},
'ctest': {'groups': len(cases), 'failures': 0, 'junitSha256': sha(args.ctest / 'tests.xml'),
'logSha256': sha(args.ctest / 'LastTest.log'),
'cases': [case.attrib for case in cases]},
'qtTestTotalsIncludingSetupAndCleanup': re.findall(r'Totals: .*', (args.ctest / 'LastTest.log').read_text()),
'runnerSha256': sha(Path(__file__)),
}
if args.installed:
value['installedBinaries'] = {name: sha(args.installed / 'bin' / name) for name in names[:3]}
with args.output.open('x') as stream:
stream.write(json.dumps(value, ensure_ascii=False, indent=2) + '\n')
print(json.dumps({'ctestGroups': len(cases), 'docviewSha256': value['binaries']['docview']}))
if __name__ == '__main__':
main()