#!/usr/bin/env python3 """Exercise core/GUI install and exact uninstall solely below a temporary DESTDIR.""" import argparse import os from pathlib import Path import shlex import shutil import subprocess import tempfile def run(args, **kwargs): return subprocess.run(args, check=True, **kwargs) def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--build-dir', type=Path, required=True) parser.add_argument('--gui', action='store_true') args = parser.parse_args() source = Path.cwd() with tempfile.TemporaryDirectory(prefix='xtc-install-') as directory: stage = Path(directory) prefix = '/opt/xtc test' root = stage / prefix.lstrip('/') sentinel = root / 'lib/keep-unrelated.txt' sentinel.parent.mkdir(parents=True) sentinel.write_text('keep\n') make = shlex.split(os.environ.get('MAKE', 'make')) # MAKEFLAGS jobserver descriptors do not cross Python subprocesses. env = dict(os.environ, MAKEFLAGS='', MFLAGS='') variables = [f'BUILD_DIR={args.build_dir}', f'PREFIX={prefix}', f'DESTDIR={stage}'] run(make + ['install'] + variables, env=env) assert not (root / 'bin/xtc').exists() assert (root / 'share/licenses/xtc/LICENSE').read_bytes() == (source / 'LICENSE').read_bytes() assert (root / 'share/doc/xtc/PROJECT_FORMAT.md').is_file() assert os.access(root / 'bin/xtc-check', os.X_OK) run([str(root / 'bin/xtc-check')]) version = subprocess.check_output([str(root / 'bin/xtc-check'), '--version'], text=True) assert version.startswith('xtc ') valid = stage / 'valid.xtc' valid.write_text('XTC_PROJECT 4\nAPP 0 1 0\nTEMPO 120000\nIDS 0 0\nGRAPH 1 0 0 0\nTRACKS 0\nCLIPS 0\nNOTES 0 0\nAUTOMATION 0\nEND\n') run([str(root / 'bin/xtc-check'), '--validate', str(valid)]) valid.write_text('damaged\n') assert subprocess.run([str(root / 'bin/xtc-check'), '--validate', str(valid)], stdout=subprocess.PIPE, stderr=subprocess.PIPE).returncode != 0 pkg_env = dict(env, PKG_CONFIG_PATH=str(root / 'lib/pkgconfig') + ':' + env.get('PKG_CONFIG_PATH', ''), PKG_CONFIG_SYSROOT_DIR=str(stage)) pkg = shlex.split(os.environ.get('PKG_CONFIG', 'pkg-config')) # A no-JACK test can be invoked with PKG_CONFIG=false; package consumer # discovery itself still uses the installed pkg-config tool. if pkg == ['false']: pkg = ['pkg-config'] flags = shlex.split(subprocess.check_output(pkg + ['--cflags', '--libs', '--static', 'xtc'], env=pkg_env, text=True)) includes = ''.join(f'#include "xtc/{p.name}"\n' for p in sorted((source / 'include/xtc').glob('*.h'))) consumer = stage / 'consumer.c' consumer.write_text(includes + '\nint main(void) { xtc_project *p = 0; xtc_result r = xtc_project_create(&p); xtc_project_destroy(p); return r != XTC_OK; }\n') for compiler, standard in [('CC', 'c99'), ('CXX', 'c++17')]: output = stage / ('consumer-' + compiler) command = shlex.split(env.get(compiler, 'cc' if compiler == 'CC' else 'c++')) run(command + [f'-std={standard}', '-Wall', '-Wextra', '-Werror', str(consumer)] + flags + ['-o', str(output)]) run([str(output)]) if args.gui: run(make + ['install-gui'] + variables, env=env) gui_env = dict(env, DISPLAY='', WAYLAND_DISPLAY='') assert subprocess.check_output([str(root / 'bin/xtc'), '--version'], env=gui_env, text=True) == version run([str(root / 'bin/xtc'), '--help'], env=gui_env) if shutil.which('desktop-file-validate'): run(['desktop-file-validate', str(root / 'share/applications/xtc.desktop')]) run(make + ['uninstall'] + variables, env=env) run(make + ['uninstall'] + variables, env=env) remaining = sorted(p.relative_to(root).as_posix() for p in root.rglob('*') if p.is_file() or p.is_symlink()) assert remaining == ['lib/keep-unrelated.txt'], remaining assert sentinel.read_text() == 'keep\n' print('Staged install/uninstall, C/C++ pkg-config consumers and headless CLI passed.') if __name__ == '__main__': main()