93 lines
4.5 KiB
Python
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()
|