Files
docview/tests/cmyk_lut/export_pdfium_patch.py
2026-09-21 13:41:40 +09:00

93 lines
4.5 KiB
Python

#!/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()