2026-10-27 06:44:22 +01:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
"""Verify every packaged file, relocatable metadata and headless executables."""
|
|
|
|
|
import argparse
|
|
|
|
|
import hashlib
|
|
|
|
|
import json
|
|
|
|
|
import os
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
import subprocess
|
|
|
|
|
import tarfile
|
|
|
|
|
import sys
|
|
|
|
|
import tempfile
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
p = argparse.ArgumentParser(description=__doc__)
|
|
|
|
|
p.add_argument('archive', type=Path)
|
|
|
|
|
p.add_argument('--build-dir', type=Path)
|
|
|
|
|
a = p.parse_args()
|
|
|
|
|
expected = a.archive.with_name(a.archive.name + '.sha256').read_text().split()[0]
|
|
|
|
|
assert hashlib.sha256(a.archive.read_bytes()).hexdigest() == expected
|
|
|
|
|
with tempfile.TemporaryDirectory(prefix='xtc-package-test-') as temporary:
|
|
|
|
|
root = Path(temporary)
|
|
|
|
|
with tarfile.open(a.archive) as tar:
|
|
|
|
|
members = tar.getmembers()
|
|
|
|
|
assert members and all(m.isfile() for m in members)
|
|
|
|
|
assert len({m.name for m in members}) == len(members)
|
|
|
|
|
assert all(not Path(m.name).is_absolute() and '..' not in Path(m.name).parts for m in members)
|
|
|
|
|
tar.extractall(root, filter='data')
|
|
|
|
|
prefix = root / members[0].name.split('/')[0] / 'usr'
|
|
|
|
|
manifest_path = prefix / 'share/doc/xtc/BINARY_MANIFEST.json'
|
|
|
|
|
manifest = json.loads(manifest_path.read_text())
|
|
|
|
|
assert manifest['schema'] == 1 and manifest['needed']
|
|
|
|
|
expected_files = {f['path'] for f in manifest['files']} | {'usr/share/doc/xtc/BINARY_MANIFEST.json'}
|
|
|
|
|
assert expected_files == {str(p.relative_to(prefix.parent)) for p in prefix.rglob('*') if p.is_file()}
|
|
|
|
|
for f in manifest['files']:
|
|
|
|
|
content = (prefix.parent / f['path']).read_bytes()
|
|
|
|
|
assert len(content) == f['size'] and hashlib.sha256(content).hexdigest() == f['sha256']
|
|
|
|
|
env = dict(os.environ, DISPLAY='', WAYLAND_DISPLAY='', PKG_CONFIG_PATH=str(prefix / 'lib/pkgconfig'))
|
|
|
|
|
for name in ('xtc-check', 'xtc'):
|
|
|
|
|
binary = prefix / 'bin' / name
|
|
|
|
|
if binary.exists():
|
|
|
|
|
for option in ('--version', '--help', '--diagnose'):
|
|
|
|
|
subprocess.run([str(binary), option], env=env, check=True)
|
|
|
|
|
flags = subprocess.check_output(['pkg-config', '--cflags', '--libs', '--static', 'xtc'], env=env, text=True)
|
|
|
|
|
assert str(prefix / 'include') in flags or str(prefix / 'lib/pkgconfig/../../include') in flags
|
|
|
|
|
assert (prefix / 'share/doc/xtc/USER_MANUAL.md').exists()
|
2026-10-27 17:13:09 +01:00
|
|
|
assert (prefix / 'share/doc/xtc/RELEASE_NOTES.md').exists()
|
|
|
|
|
subprocess.run([str(prefix / 'bin/xtc-check'), '--inspect',
|
|
|
|
|
str(prefix / 'share/xtc/examples/midi-demo.xtc')], check=True)
|
|
|
|
|
for name in ('project-performance-baseline.json', 'graph-performance-phase29.json'):
|
|
|
|
|
assert (prefix / 'share/doc/xtc' / name).is_file()
|
2026-10-27 06:44:22 +01:00
|
|
|
if a.build_dir:
|
|
|
|
|
again = root / 'repacked.tar.gz'
|
|
|
|
|
command = [sys.executable, 'tools/package.py', '--build-dir', str(a.build_dir), '--output', str(again)]
|
|
|
|
|
if (prefix / 'bin/xtc').exists():
|
|
|
|
|
command.append('--gui')
|
|
|
|
|
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
|
|
|
|
assert result.returncode == 0, result.stdout
|
|
|
|
|
assert hashlib.sha256(again.read_bytes()).hexdigest() == expected, 'Binary repack differs'
|
|
|
|
|
print('Binary archive hashes, manifest, relocation, headless diagnostics and documentation passed.')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
main()
|