Phase 30: complete configurable installation and release qualification
This commit is contained in:
parent
afc049e2c8
commit
90eac33a71
18 changed files with 399 additions and 59 deletions
|
|
@ -17,6 +17,7 @@ def main():
|
|||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--build-dir', type=Path, required=True)
|
||||
parser.add_argument('--gui', action='store_true')
|
||||
parser.add_argument('--custom-layout', action='store_true')
|
||||
args = parser.parse_args()
|
||||
source = Path.cwd()
|
||||
with tempfile.TemporaryDirectory(prefix='xtc-install-') as directory:
|
||||
|
|
@ -30,28 +31,48 @@ def main():
|
|||
# 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}']
|
||||
if args.custom_layout:
|
||||
variables += [f'exec_prefix={prefix}/runtime', f'libdir={prefix}/lib64',
|
||||
f'includedir={prefix}/headers', f'datarootdir={prefix}/resources',
|
||||
f'docdir={prefix}/manual', f'pkgconfigdir={prefix}/metadata']
|
||||
binaries = root / ('runtime/bin' if args.custom_layout else 'bin')
|
||||
headers = root / ('headers' if args.custom_layout else 'include')
|
||||
resources = root / ('resources' if args.custom_layout else 'share')
|
||||
docs = root / ('manual' if args.custom_layout else 'share/doc/xtc')
|
||||
metadata = root / ('metadata' if args.custom_layout else 'lib/pkgconfig')
|
||||
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')])
|
||||
diagnose = subprocess.check_output([str(root / 'bin/xtc-check'), '--diagnose'], text=True)
|
||||
assert not (binaries / 'xtc').exists()
|
||||
assert (resources / 'licenses/xtc/LICENSE').read_bytes() == (source / 'LICENSE').read_bytes()
|
||||
assert (docs / 'PROJECT_FORMAT.md').is_file()
|
||||
assert os.access(binaries / 'xtc-check', os.X_OK)
|
||||
run([str(binaries / 'xtc-check')])
|
||||
for filename in ('performance-baseline.json', 'project-performance-baseline.json', 'graph-performance-phase29.json'):
|
||||
assert (docs / filename).read_bytes() == (source / 'docs' / filename).read_bytes()
|
||||
example = resources / 'xtc/examples/midi-demo.xtc'
|
||||
run([str(binaries / 'xtc-check'), '--inspect', str(example)])
|
||||
assert (resources / 'xtc/examples/README.md').is_file()
|
||||
diagnose = subprocess.check_output([str(binaries / 'xtc-check'), '--diagnose'], text=True)
|
||||
assert 'Project formats: 1..10' in diagnose and 'JACK compiled:' in diagnose
|
||||
# Replacing a file symlink must not overwrite an unrelated target.
|
||||
protected = stage / 'unrelated-target'
|
||||
protected.write_text('keep unrelated target\n')
|
||||
(binaries / 'xtc-check').unlink()
|
||||
(binaries / 'xtc-check').symlink_to(protected)
|
||||
# Upgrade/repair repeats the same owned-file install and keeps unrelated data.
|
||||
(root / 'include/xtc/xtc.h').write_text('old installation marker\n')
|
||||
(headers / '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 (headers / '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 protected.read_text() == 'keep unrelated target\n'
|
||||
version = subprocess.check_output([str(binaries / '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)])
|
||||
run([str(binaries / 'xtc-check'), '--validate', str(valid)])
|
||||
valid.write_text('damaged\n')
|
||||
assert subprocess.run([str(root / 'bin/xtc-check'), '--validate', str(valid)],
|
||||
assert subprocess.run([str(binaries / '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_env = dict(env, PKG_CONFIG_PATH=str(metadata) + ':' + 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
|
||||
|
|
@ -87,10 +108,30 @@ int main(int argc, char **argv) {
|
|||
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)
|
||||
assert subprocess.check_output([str(binaries / 'xtc'), '--version'], env=gui_env, text=True) == version
|
||||
run([str(binaries / 'xtc'), '--help'], env=gui_env)
|
||||
if shutil.which('desktop-file-validate'):
|
||||
run(['desktop-file-validate', str(root / 'share/applications/xtc.desktop')])
|
||||
run(['desktop-file-validate', str(resources / 'applications/xtc.desktop')])
|
||||
# Both operations must reject staging paths redirected outside DESTDIR.
|
||||
with tempfile.TemporaryDirectory(prefix='xtc-install-outside-') as outside:
|
||||
escape = root / 'escape'
|
||||
escape.symlink_to(outside, target_is_directory=True)
|
||||
redirected = variables + [f'docdir={prefix}/escape/docs']
|
||||
for operation in ('install', 'uninstall'):
|
||||
refusal = subprocess.run(make + [operation] + redirected, env=env,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
assert refusal.returncode != 0 and not list(Path(outside).iterdir())
|
||||
assert (headers / 'xtc/xtc.h').is_file()
|
||||
escape.unlink()
|
||||
# A directory at an owned file path must fail the whole removal preflight.
|
||||
saved_binary = stage / 'saved-check'
|
||||
(binaries / 'xtc-check').rename(saved_binary)
|
||||
(binaries / 'xtc-check').mkdir()
|
||||
refusal = subprocess.run(make + ['uninstall'] + variables, env=env,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
assert refusal.returncode != 0 and (headers / 'xtc/xtc.h').is_file()
|
||||
(binaries / 'xtc-check').rmdir()
|
||||
saved_binary.rename(binaries / 'xtc-check')
|
||||
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())
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@ def main():
|
|||
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()
|
||||
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()
|
||||
if a.build_dir:
|
||||
again = root / 'repacked.tar.gz'
|
||||
command = [sys.executable, 'tools/package.py', '--build-dir', str(a.build_dir), '--output', str(again)]
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ def main():
|
|||
parser.add_argument('--gui', action='store_true')
|
||||
args = parser.parse_args()
|
||||
archive = args.archive.resolve()
|
||||
assert archive.with_name(archive.name + '.sha256').read_text().split()[0] == digest(archive)
|
||||
with tempfile.TemporaryDirectory(prefix='xtc-release-') as directory:
|
||||
root = Path(directory)
|
||||
with tarfile.open(archive) as source:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue