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

127 lines
7.9 KiB
Python

#!/usr/bin/env python3
"""Build/package the pinned v2 candidate only in the dedicated Ubuntu guest.
Input transfer is recorded separately. Existing source/build/install/provider
prefixes and earlier evidence are preserved. This does not stop the VM.
"""
import argparse
import hashlib
import json
import os
from pathlib import Path
import re
import shutil
import subprocess
import sys
import time
ROOT = Path(__file__).resolve().parents[2]
HOME = Path('/home/docview')
PREFIX = HOME / 'validation/pdfium-context-prefix'
BUILD = HOME / 'docview-context-build'
INSTALL = HOME / 'docview-context-install'
RESULTS = HOME / 'validation/pdfium-context-package'
VERSION = '0.1.0~validation4'
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('--phase', choices=('build', 'package', 'smoke'), required=True)
parser.add_argument('--run-name', required=True)
args = parser.parse_args()
assert os.getuid() != 0 and Path.home() == HOME and ROOT == HOME / 'docview-context-source'
assert re.fullmatch('[a-z0-9-]{1,64}', args.run_name)
output = RESULTS / args.run_name; output.mkdir(parents=True, exist_ok=False)
env = {**os.environ, 'PATH': '/opt/docview-deps/bin:/opt/docview-qt/6.11.2/gcc_64/bin:' + os.environ['PATH'],
'PKG_CONFIG_PATH': '/opt/docview-deps/lib/pkgconfig',
'LD_LIBRARY_PATH': '/opt/docview-deps/lib:/opt/docview-qt/6.11.2/gcc_64/lib',
'QT_QPA_PLATFORM': 'xcb', 'QT_QUICK_BACKEND': 'software',
'QTWEBENGINE_CHROMIUM_FLAGS': '--disable-gpu', 'QT_SCALE_FACTOR': '1',
'QT_AUTO_SCREEN_SCALE_FACTOR': '0', 'XDG_SESSION_TYPE': 'x11'}
for key in ('LD_PRELOAD', 'LD_AUDIT', 'QTWEBENGINE_DISABLE_SANDBOX', 'WAYLAND_DISPLAY'):
assert not env.get(key), key
preserved = [HOME / 'docview-source/.deps/pdfium/lib/libpdfium.so', HOME / 'docview-build/docview',
HOME / 'docview-build/docview-pdf-worker', HOME / 'docview-install/bin/docview']
before = {str(path): sha(path) for path in preserved}
report = {'success': False, 'phase': args.phase, 'commands': [], 'runnerSha256': sha(Path(__file__)),
'providerAndOriginalBuildBefore': before, 'scope': 'Local Ubuntu candidate integration only; no public release or complete Chromium notice claim'}
def run(label, command, timeout=1800, environment=env):
start = time.monotonic(); log = output / (label + '.log')
print('Starting', label, flush=True)
with log.open('w') as stream:
result = subprocess.run(command, cwd=ROOT, env=environment, stdout=stream, stderr=subprocess.STDOUT, timeout=timeout)
report['commands'].append({'name': label, 'command': list(map(str, command)), 'exitCode': result.returncode,
'seconds': time.monotonic() - start, 'logSha256': sha(log)})
print('Finished', label, result.returncode, flush=True)
assert result.returncode == 0, label + ' failed; inspect ' + str(log)
try:
sys.path.insert(0, str(ROOT / 'tools'))
from verify_pdfium_candidate import verify_prefix, verify_installed
report['candidatePrefix'], _ = verify_prefix(PREFIX, PREFIX / 'lib/libpdfium.so', PREFIX / 'include')
if args.phase == 'build':
run('configure', ['cmake', '-S', str(ROOT), '-B', str(BUILD), '-G', 'Ninja', '-DCMAKE_BUILD_TYPE=Release',
'-DCMAKE_PREFIX_PATH=/opt/docview-qt/6.11.2/gcc_64;/opt/docview-deps',
'-DDOCVIEW_PDFIUM_ROOT=' + str(PREFIX)])
run('build', ['cmake', '--build', str(BUILD), '--parallel', '4'])
run('candidate-integration-tests', [sys.executable, str(ROOT / 'tests/test_pdfium_candidate_integration.py'), '-v'])
run('ctest', ['dbus-run-session', '--', 'xvfb-run', '-a', '-s', '-screen 0 1920x1080x24',
'ctest', '--test-dir', str(BUILD), '--output-on-failure', '--output-junit', str(output / 'tests.xml')])
shutil.copyfile(BUILD / 'Testing/Temporary/LastTest.log', output / 'LastTest.log')
run('install', ['cmake', '--install', str(BUILD), '--prefix', str(INSTALL)])
report['installedCandidate'] = verify_installed(INSTALL)
report['binaries'] = {name: sha(BUILD / name) for name in ('docview', 'docview-pdf-worker', 'docview-archive-worker')}
elif args.phase == 'package':
package_command = [sys.executable, str(ROOT / 'tools/package_ubuntu.py'), '--prefix', str(INSTALL),
'--qtpaths', '/opt/docview-qt/6.11.2/gcc_64/bin/qtpaths', '--dependency-prefix', '/opt/docview-deps',
'--source-root', str(HOME / 'dependency-sources/qpdf-12.4.1'),
'--source-root', str(HOME / 'dependency-sources/libzip-1.11.4'),
'--input-manifest', str(HOME / 'incoming/sdk-downloads.json'),
'--sdk-notices', str(ROOT / 'tests/results/source-archives/qt-sdk-notices-final'),
'--sdk-supplement', str(ROOT / 'tests/results/qt-notice-supplement/collection'),
'--qt-licenses', str(ROOT / 'tests/results/ubuntu-package/inputs/qt-licenses'), '--version', VERSION]
for name in ('package', 'repeat'):
destination = output / name
run(name, [*package_command, '--output', str(destination)])
run(name + '-verify', [sys.executable, str(ROOT / 'tools/verify_ubuntu_package.py'), '--archive',
str(destination / ('docview_' + VERSION + '_amd64.deb')), '--output', str(destination / 'verification.json')])
archive = 'docview_' + VERSION + '_amd64.deb'
report['archiveSha256'] = sha(output / 'package' / archive)
report['repeatSha256'] = sha(output / 'repeat' / archive)
assert report['archiveSha256'] == report['repeatSha256']
report['archive'] = str(output / 'package' / archive)
else:
package = json.loads((RESULTS / 'package/report.json').read_text())
assert package['success'] and sha(Path(package['archive'])) == package['archiveSha256']
run('apt-install', ['sudo', 'env', 'DEBIAN_FRONTEND=noninteractive', 'apt-get', '-y',
'--no-install-recommends', 'install', package['archive']])
report['installedCandidate'] = verify_installed(Path('/opt/docview'))
run('installed-smoke', [sys.executable, str(ROOT / 'tests/ubuntu_vm/package_smoke.py'),
'--output', str(output / 'installed-smoke'), '--hide-prefix', str(BUILD), '--hide-prefix', str(INSTALL),
'--hide-prefix', str(PREFIX), '--hide-prefix', str(HOME / 'validation/pdfium-intent-context')],
environment={key: value for key, value in os.environ.items() if key not in (
'LD_LIBRARY_PATH', 'QT_PLUGIN_PATH', 'QT_QPA_PLATFORM_PLUGIN_PATH', 'QML_IMPORT_PATH',
'QML2_IMPORT_PATH', 'QTWEBENGINEPROCESS_PATH', 'QTWEBENGINE_DISABLE_SANDBOX')})
run('lifecycle', [sys.executable, str(ROOT / 'tests/ubuntu_vm/package_lifecycle.py'), '--smoke',
str(output / 'installed-smoke'), '--output', str(output / 'lifecycle')])
report['packagePurged'] = not Path('/opt/docview').exists() and not Path('/etc/apparmor.d/docview').exists()
assert report['packagePurged']
after = {str(path): sha(path) for path in preserved}
report['providerAndOriginalBuildAfter'] = after
assert before == after
report['originalsUnchanged'] = report['success'] = True
finally:
report['evidenceSha256'] = {str(path.relative_to(output)): sha(path)
for path in sorted(output.rglob('*')) if path.is_file() and path.suffix != '.deb'}
(output / 'report.json').write_text(json.dumps(report, indent=2) + '\n')
print(json.dumps({'phase': args.phase, 'success': report['success']}))
if __name__ == '__main__':
main()