Phase 9: Add native processors and reproducible Linux release tooling

This commit is contained in:
Johannes Findeisen 2026-10-27 01:21:04 +01:00
commit de403b37d7
43 changed files with 1656 additions and 19 deletions

View 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()