Fiw-Gentoo-Dots/tools/ci/check.py
Fi3w0 fd3d79f61f
All checks were successful
Check and mirror to GitHub / checks (push) Successful in 21s
Check and mirror to GitHub / github-mirror (push) Successful in 8s
Trim maintenance clutter and add desktop screenshots
2026-10-03 23:57:58 +02:00

69 lines
3 KiB
Python

#!/usr/bin/env python3
"""Check portable code and the shipped assets without applying the installer."""
import gzip
import hashlib
import importlib.util
import io
import json
import os
import subprocess
from pathlib import Path
REPO = Path(__file__).resolve().parents[2]
def sha(data):
return hashlib.sha256(data).hexdigest()
def check_assets():
spec = importlib.util.spec_from_file_location('launcher', REPO / 'lib/launcher.py')
launcher = importlib.util.module_from_spec(spec)
spec.loader.exec_module(launcher)
root = REPO / 'assets/bin'
metadata = json.loads((root / 'tui.json').read_text())
if metadata['version'] != (REPO / 'VERSION').read_text().strip():
raise RuntimeError('TUI version does not match VERSION; rebuild the release bundle.')
if metadata['source_sha256'] != launcher.source_hash(REPO):
raise RuntimeError('TUI source changed; rebuild the release bundle.')
for binary in metadata['binaries'].values():
path = root / binary['file']
if path.parent.resolve() != root.resolve():
raise RuntimeError('Invalid TUI archive path.')
compressed = path.read_bytes()
if sha(compressed) != binary['gzip_sha256']:
raise RuntimeError('TUI archive checksum mismatch.')
size = binary['size']
if not isinstance(size, int) or not 0 < size <= 64 * 1024 * 1024:
raise RuntimeError('Invalid TUI size.')
with gzip.GzipFile(fileobj=io.BytesIO(compressed)) as stream:
executable = stream.read(size + 1)
if len(executable) != size or sha(executable) != binary['sha256']:
raise RuntimeError('TUI executable checksum mismatch.')
line = binary['gzip_sha256'] + ' ' + binary['file']
if line not in (root / 'SHA256SUMS').read_text().splitlines():
raise RuntimeError('SHA256SUMS does not match the TUI archive.')
for name, entry in json.loads((REPO / 'assets/editor-themes.json').read_text()).items():
directory = REPO / entry['root']
if not directory.resolve().is_relative_to(REPO):
raise RuntimeError('Invalid editor asset directory.')
actual = {path.relative_to(directory).as_posix(): sha(path.read_bytes())
for path in sorted(directory.rglob('*')) if path.is_file()}
if actual != entry['sha256']:
raise RuntimeError('Editor asset fingerprints changed: ' + name)
print('Prebuilt TUI and editor asset fingerprints match.', flush=True)
def main():
subprocess.run(['python3', 'tools/check-private.py'], cwd=REPO, check=True)
check_assets()
for directory in ('lib', 'tools'):
for path in (REPO / directory).rglob('*.py'):
compile(path.read_bytes(), path.relative_to(REPO).as_posix(), 'exec')
print('Python sources parse.', flush=True)
subprocess.run(['go', 'build', '-o', os.devnull, './cmd/dots'], cwd=REPO, check=True)
print('Portable CI checks passed; no installer actions were applied.', flush=True)
if __name__ == '__main__':
main()