Files
2026-09-21 13:41:40 +09:00

49 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""Create a bounded source/PDFium snapshot, excluding results, builds and VM keys."""
import argparse
import hashlib
import json
import os
from pathlib import Path
import re
import tarfile
ROOT = Path(__file__).resolve().parents[2]
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--name', required=True)
args = parser.parse_args()
if not re.fullmatch(r'[a-z0-9][a-z0-9-]{0,63}', args.name):
parser.error('Use a short lowercase snapshot name')
work = Path(os.environ.get('DOCVIEW_VM_WORK', ROOT / 'build-ubuntu-vm')).resolve()
archive = work / (args.name + '.tar.gz')
manifest = work / 'metadata' / (args.name + '.json')
if archive.exists() or manifest.exists():
parser.error('Choose a new name to preserve previous source evidence')
files = [ROOT / name for name in ('CMakeLists.txt', 'resources.qrc', 'README.md')]
for name in ('src', 'qml', 'cmake', 'resources', 'tools', 'tests', 'docs', '.deps/pdfium'):
directory = ROOT / name
for base, directories, leaves in os.walk(directory, followlinks=False):
directories[:] = [d for d in directories if d not in ('results', '__pycache__', '.git')
and not (Path(base) / d).is_symlink()]
files.extend(Path(base) / leaf for leaf in leaves if leaf != 'validation-record.json')
rows, total = [], 0
for path in sorted(set(files)):
if path.is_symlink() or not path.is_file() or not path.resolve().is_relative_to(ROOT):
raise SystemExit('Unexpected non-regular source input')
size = path.stat().st_size
total += size
if len(rows) >= 10000 or size > 256 * 1024 * 1024 or total > 512 * 1024 * 1024:
raise SystemExit('Source snapshot exceeds finite limits')
with path.open('rb') as stream:
digest = hashlib.file_digest(stream, 'sha256').hexdigest()
rows.append({'path': str(path.relative_to(ROOT)), 'size': size, 'sha256': digest})
work.mkdir(parents=True, exist_ok=True)
manifest.parent.mkdir(parents=True, exist_ok=True)
with tarfile.open(archive, 'x:gz') as stream:
for row in rows:
stream.add(ROOT / row['path'], arcname=row['path'], recursive=False)
with archive.open('rb') as stream:
digest = hashlib.file_digest(stream, 'sha256').hexdigest()
manifest.write_text(json.dumps({'archiveSha256': digest, 'files': rows}, indent=2) + '\n')
print(json.dumps({'files': len(rows), 'sourceBytes': total, 'archiveSha256': digest}))