#!/usr/bin/env python3 """Export the isolated PDFium core changes against the verified fixed archive.""" import difflib import hashlib import json from pathlib import Path import subprocess import tarfile import tempfile ROOT = Path(__file__).resolve().parents[2] def sha(path): with path.open('rb') as stream: return hashlib.file_digest(stream, 'sha256').hexdigest() def main(): results = ROOT / 'tests/results/pdfium-intent-build' materialization = json.loads((results / 'source-materialization.json').read_text()) repository = next(row for row in materialization['repositories'] if row['path'] == '.') archive = ROOT / repository['archive'] inventory = ROOT / repository['inventory'] assert sha(archive) == repository['archiveSha256'] assert sha(inventory) == repository['inventorySha256'] source = ROOT / materialization['source'] originals = {row['path']: row for line in inventory.open() if (row := json.loads(line))['archived'] and row['path'].startswith('core/')} changed = {} for name, row in originals.items(): assert row['mode'] == '100644' if sha(source / name) != row['sha256']: changed[name] = row added = {str(path.relative_to(source)) for path in (source / 'core').rglob('*') if path.is_file() and str(path.relative_to(source)) not in originals} assert all(Path(name).suffix in ('.h', '.cpp') for name in added) chunks = [] records = [] with tarfile.open(archive) as tar: for name in sorted(changed.keys() | added): before = b'' if name in added else tar.extractfile('pdfium/' + name).read() if name in changed: assert hashlib.sha256(before).hexdigest() == changed[name]['sha256'] after = (source / name).read_bytes() diff = ''.join(difflib.unified_diff( before.decode().splitlines(keepends=True), after.decode().splitlines(keepends=True), fromfile='/dev/null' if name in added else 'a/' + name, tofile='b/' + name)) assert diff chunks.append('diff --git a/' + name + ' b/' + name + '\n' + diff) records.append({'path': name, 'added': name in added, 'beforeSha256': None if name in added else hashlib.sha256(before).hexdigest(), 'afterSha256': hashlib.sha256(after).hexdigest()}) destination = ROOT / 'cmake/patches/pdfium-rendering-intent.patch' destination.parent.mkdir(parents=True, exist_ok=True) destination.write_text(''.join(chunks)) snapshot = results / 'patches' / (sha(destination) + '.patch') snapshot.parent.mkdir(exist_ok=True) if snapshot.exists(): assert snapshot.read_bytes() == destination.read_bytes() else: snapshot.write_bytes(destination.read_bytes()) # Check that this reviewable patch, rather than an unrecorded local change, # reproduces every modified core source without fuzzy matching. with tempfile.TemporaryDirectory(prefix='docview-pdfium-patch-') as folder: check_root = Path(folder) with tarfile.open(archive) as tar: for name in changed: target = check_root / name target.parent.mkdir(parents=True, exist_ok=True) target.write_bytes(tar.extractfile('pdfium/' + name).read()) result = subprocess.run(['patch', '-p1', '--batch', '--fuzz=0', '-i', str(destination)], cwd=check_root, capture_output=True, text=True) assert result.returncode == 0, result.stdout + result.stderr for row in records: assert sha(check_root / row['path']) == row['afterSha256'] record = {'success': True, 'exporterSha256': sha(Path(__file__)), 'baseRevision': repository['revision'], 'archiveSha256': sha(archive), 'patch': str(destination.relative_to(ROOT)), 'patchSha256': sha(destination), 'patchSnapshot': str(snapshot.relative_to(ROOT)), 'appliesWithoutFuzz': True, 'appliedSourcesByteIdentical': True, 'files': records, 'scope': 'Candidate core patch only. Provider shared-library/public-header patches are recorded separately. Production dependency is not replaced by this exporter.'} (results / 'candidate-patch.json').write_text(json.dumps(record, indent=2) + '\n') print(json.dumps({'files': len(records), 'patchBytes': destination.stat().st_size, 'patchSha256': record['patchSha256']})) if __name__ == '__main__': main()