1
0
Fork 0
forked from hanez/xtc
xtc/tests/integration/test_release.py

63 lines
2.7 KiB
Python

#!/usr/bin/env python3
"""Rebuild source exports in different paths and compare release artifacts."""
import argparse
import hashlib
import os
from pathlib import Path
import shlex
import subprocess
import tarfile
import tempfile
def digest(path):
return hashlib.sha256(path.read_bytes()).hexdigest()
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('archive', type=Path)
parser.add_argument('--gui', action='store_true')
args = parser.parse_args()
archive = args.archive.resolve()
with tempfile.TemporaryDirectory(prefix='xtc-release-') as directory:
root = Path(directory)
with tarfile.open(archive) as source:
names = [m.name for m in source.getmembers()]
assert len(set(names)) == len(names)
assert all(m.isfile() for m in source.getmembers())
top = names[0].split('/')[0]
epoch = source.getmembers()[0].mtime
assert all(n.startswith(top + '/') and '..' not in Path(n).parts for n in names)
assert all('__pycache__' not in Path(n).parts and '.git' not in Path(n).parts for n in names)
for name in ('first', 'different-path'):
source.extractall(root / name, filter='data')
env = dict(os.environ, SOURCE_DATE_EPOCH=str(epoch), MAKEFLAGS='', MFLAGS='')
builds = []
for name in ('first', 'different-path'):
project = root / name / top
log = root / (name + '.log')
make = shlex.split(env.get('MAKE', 'make'))
with log.open('w') as output:
try:
subprocess.run(make + ['BUILD_DIR=build', 'release'], cwd=project, env=env, stdout=output,
stderr=subprocess.STDOUT, check=True)
except subprocess.CalledProcessError:
print(log.read_text()[-12000:])
raise
# Exported source can package itself without a .git directory.
repacked = root / (name + '.tar.gz')
subprocess.run([env.get('PYTHON', 'python3'), 'tools/dist.py', '--output', str(repacked)],
cwd=project, env=env, check=True)
assert digest(repacked) == digest(archive), 'Source archive is not reproducible'
release = project / 'build/release'
files = ['libxtc.a', 'xtc-check'] + (['xtc'] if args.gui else [])
builds.append({file: digest(release / file) for file in files})
assert builds[0] == builds[1], (builds[0], builds[1])
for file, sha in builds[0].items():
print(f'Reproducible {file}: {sha}')
print('Two clean source-export release builds and archives are byte-identical.')
if __name__ == '__main__':
main()