Phase 20: package Linux builds and document release and maintenance workflows
This commit is contained in:
parent
6b85f28add
commit
830b6e1914
22 changed files with 490 additions and 17 deletions
|
|
@ -36,6 +36,13 @@ def main():
|
|||
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')])
|
||||
diagnose = subprocess.check_output([str(root / 'bin/xtc-check'), '--diagnose'], text=True)
|
||||
assert 'Project formats: 1..7' in diagnose and 'JACK compiled:' in diagnose
|
||||
# Upgrade/repair repeats the same owned-file install and keeps unrelated data.
|
||||
(root / 'include/xtc/xtc.h').write_text('old installation marker\n')
|
||||
run(make + ['install'] + variables, env=env)
|
||||
assert (root / 'include/xtc/xtc.h').read_bytes() == (source / 'include/xtc/xtc.h').read_bytes()
|
||||
assert sentinel.read_text() == 'keep\n'
|
||||
version = subprocess.check_output([str(root / 'bin/xtc-check'), '--version'], text=True)
|
||||
assert version.startswith('xtc ')
|
||||
valid = stage / 'valid.xtc'
|
||||
|
|
@ -54,12 +61,29 @@ def main():
|
|||
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')
|
||||
consumer.write_text(includes + r'''
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
int main(int argc, char **argv) {
|
||||
xtc_project *p = 0, *q = 0; xtc_midi_plan *a = 0, *b = 0;
|
||||
uint64_t track, clip, note; float before[127], after[127]; int i, nonzero = 0;
|
||||
if (argc != 2 || xtc_project_create(&p) != XTC_OK || xtc_project_create(&q) != XTC_OK) return 1;
|
||||
if (xtc_project_add_track(p,"Installed",&track) != XTC_OK ||
|
||||
xtc_project_add_midi_clip(p,track,0,960,&clip) != XTC_OK ||
|
||||
xtc_project_add_note(p,clip,0,960,69,127,0,¬e) != XTC_OK ||
|
||||
xtc_project_save(p,argv[1]) != XTC_OK || xtc_project_load(q,argv[1]) != XTC_OK ||
|
||||
xtc_midi_plan_create(p,48000,&a) != XTC_OK || xtc_midi_plan_create(q,48000,&b) != XTC_OK ||
|
||||
xtc_midi_plan_render(a,0,0,0,before,127) != XTC_OK || xtc_midi_plan_render(b,0,0,0,after,127) != XTC_OK) return 2;
|
||||
for (i = 0; i < 127; ++i) { if (before[i] != after[i]) return 3; if (before[i] != 0) nonzero = 1; }
|
||||
xtc_midi_plan_destroy(a); xtc_midi_plan_destroy(b); xtc_project_destroy(p); xtc_project_destroy(q);
|
||||
remove(argv[1]); return !nonzero;
|
||||
}
|
||||
''')
|
||||
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)])
|
||||
run([str(output), str(stage / ("installed-" + compiler + ".xtc"))])
|
||||
if args.gui:
|
||||
run(make + ['install-gui'] + variables, env=env)
|
||||
gui_env = dict(env, DISPLAY='', WAYLAND_DISPLAY='')
|
||||
|
|
|
|||
59
tests/integration/test_package.py
Normal file
59
tests/integration/test_package.py
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#!/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()
|
||||
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()
|
||||
|
|
@ -58,6 +58,14 @@ int main(void)
|
|||
assert(xtc_project_find_clip(p,clip,&c) == XTC_OK && !strcmp(c.asset_path,media));
|
||||
unlink(copy); rmdir(sub);
|
||||
}
|
||||
{
|
||||
char alias_dir[512], alias[512]; xtc_clip_info c;
|
||||
snprintf(alias_dir,sizeof(alias_dir),"%s/aliases",root); assert(mkdir(alias_dir,0700) == 0);
|
||||
snprintf(alias,sizeof(alias),"%s/aliases/link.xtc",root); assert(symlink(file,alias) == 0);
|
||||
assert(xtc_project_load(p,alias) == XTC_OK);
|
||||
assert(xtc_project_find_clip(p,clip,&c) == XTC_OK && !strcmp(c.asset_path,media));
|
||||
unlink(alias); rmdir(alias_dir);
|
||||
}
|
||||
snprintf(moved,sizeof(moved),"%s-moved",root); assert(rename(root,moved) == 0);
|
||||
snprintf(file,sizeof(file),"%s-moved/migration.xtc",root);
|
||||
assert(xtc_project_load(p,file) == XTC_OK);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue