FDS/OS 1.0
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
"""The complete versioned image/package set used by comparison and release assembly."""
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def digest(path):
|
||||
with Path(path).open('rb') as stream:
|
||||
return hashlib.file_digest(stream, 'sha256').hexdigest()
|
||||
|
||||
|
||||
def artifacts(project):
|
||||
project = Path(project).resolve(strict=True)
|
||||
out = project / 'out'
|
||||
result = {}
|
||||
for name in ('fds-system-cli.img', 'fds-system-development.img', 'fds-recovery.img',
|
||||
'fds-boot.img', 'fds-internal.img'):
|
||||
result[name] = (out / name).resolve(strict=True)
|
||||
for profile in ('cli', 'development', 'recovery'):
|
||||
result[f'rootfs-{profile}.tar'] = (out / f'rootfs-{profile}.tar').resolve(strict=True)
|
||||
for suffix in ('', '.gz', '.lz4', '.zst'):
|
||||
name = 'initramfs.cpio' + suffix
|
||||
result[name] = (out / 'initramfs' / name).resolve(strict=True)
|
||||
for name in ('kernel_2712.img', 'bcm2712-rpi-5-b.dtb'):
|
||||
result[name] = (out / 'kernel/boot' / name).resolve(strict=True)
|
||||
for name in ('configured.bin', 'rollback.bin', 'configured.conf', 'original.conf'):
|
||||
result['eeprom-production-' + name] = (out / 'eeprom-production-latest' / name).resolve(strict=True)
|
||||
packages = sorted((out / 'packages').glob('fds-*.aarch64.xbps'))
|
||||
required = {'fds-base', 'fds-base-files', 'fds-init', 'fds-cli', 'fds-cartridged',
|
||||
'fds-dasungd', 'fds-kernel', 'fds-dhcpcd', 'fds-eink'}
|
||||
names = {p.name.rsplit('-', 1)[0] for p in packages}
|
||||
if names != required or len(packages) != len(required):
|
||||
raise ValueError('The release requires exactly one version of every FDS base package')
|
||||
for path in packages:
|
||||
result[path.name] = path.resolve(strict=True)
|
||||
for name, path in result.items():
|
||||
if not path.is_file() or path.stat().st_size == 0:
|
||||
raise ValueError(f'Missing or empty release artifact: {name}')
|
||||
return result
|
||||
|
||||
|
||||
def read_lock(project):
|
||||
path = Path(project) / '.host/frozen/lock.json'
|
||||
lock = json.loads(path.read_text())
|
||||
if lock.get('format') != 1 or lock.get('version') != '0.1.0':
|
||||
raise ValueError('Build does not identify a supported frozen input snapshot')
|
||||
return lock, digest(path)
|
||||
|
||||
|
||||
def compare(first, second):
|
||||
left_lock, left_hash = read_lock(first)
|
||||
right_lock, right_hash = read_lock(second)
|
||||
if left_hash != right_hash:
|
||||
raise ValueError('Builds did not use the same frozen input lock')
|
||||
left, right = artifacts(first), artifacts(second)
|
||||
if left.keys() != right.keys():
|
||||
raise ValueError('Builds produced different artifact names')
|
||||
records = []
|
||||
for name in sorted(left):
|
||||
one, two = digest(left[name]), digest(right[name])
|
||||
records.append({'name': name, 'first_sha256': one, 'second_sha256': two,
|
||||
'first_bytes': left[name].stat().st_size, 'second_bytes': right[name].stat().st_size,
|
||||
'identical': one == two and left[name].stat().st_size == right[name].stat().st_size})
|
||||
return {'format': 1, 'status': 'passed' if all(x['identical'] for x in records) else 'failed',
|
||||
'version': left_lock['version'], 'source_sha256': left_lock['source_sha256'],
|
||||
'input_lock_sha256': left_hash, 'hardware_validation': 'deferred', 'artifacts': records}
|
||||
Reference in New Issue
Block a user