Phase 9: Add native processors and reproducible Linux release tooling
This commit is contained in:
parent
7db5fb7738
commit
de403b37d7
43 changed files with 1656 additions and 19 deletions
63
tests/integration/test_release.py
Normal file
63
tests/integration/test_release.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#!/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 + ['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()
|
||||
Loading…
Add table
Add a link
Reference in a new issue