#!/usr/bin/env python3 """Materialize previously verified fixed Git archives for an isolated PDFium build.""" import hashlib import json from pathlib import Path, PurePosixPath import tarfile ROOT = Path(__file__).resolve().parents[2] def sha(path): with path.open('rb') as stream: return hashlib.file_digest(stream,'sha256').hexdigest() def main(): reports=[ROOT/'tests/results/source-archives/pdfium-git/report.json', ROOT/'tests/results/source-archives/pdfium-gitlink/report.json'] repositories=[] for path in reports: report=json.loads(path.read_text()); assert report['success'] repositories.extend(report['repositories']) source=ROOT/'build-pdfium-intent/source' source.mkdir(parents=True,exist_ok=False) output=ROOT/'tests/results/pdfium-intent-build'; output.mkdir(parents=True,exist_ok=False) materialized=[]; links=[]; total=0; count=0 for repository in repositories: archive=ROOT/repository['archive']; inventory=ROOT/repository['inventory'] assert sha(archive)==repository['archiveSha256'] and sha(inventory)==repository['inventorySha256'] expected={r['path']:r for line in inventory.open() if (r:=json.loads(line))['archived']} prefix='pdfium/'+('' if repository['path']=='.' else repository['path']+'/') found=set() with tarfile.open(archive) as stream: for member in stream: assert member.name.startswith(prefix) relative=member.name.removeprefix(prefix) if member.isdir(): continue assert relative in expected and relative not in found found.add(relative); row=expected[relative] name=PurePosixPath(member.name.removeprefix('pdfium/')) assert not name.is_absolute() and '..' not in name.parts and '\\' not in str(name) path=source/name; assert path.resolve().is_relative_to(source) and not path.exists() path.parent.mkdir(parents=True,exist_ok=True) if member.issym(): assert row['mode']=='120000' and member.linkname==row['linkTarget'] target=PurePosixPath(member.linkname) assert not target.is_absolute() and (path.parent/target).resolve().is_relative_to(source) assert hashlib.sha256(member.linkname.encode()).hexdigest()==row['sha256'] links.append((path,member.linkname)) continue assert member.isfile() and row['mode'] in ('100644','100755') and member.size==row['bytes'] total+=member.size; count+=1 assert member.size<=256*1024**2 and total<=2*1024**3 and count<=100000 digest=hashlib.sha256() with stream.extractfile(member) as incoming, path.open('xb') as outgoing: for chunk in iter(lambda:incoming.read(1024*1024),b''): digest.update(chunk); outgoing.write(chunk) assert digest.hexdigest()==row['sha256'] path.chmod(0o755 if row['mode']=='100755' else 0o644) assert found==expected.keys() materialized.append({k:repository[k] for k in ('path','revision','archive','archiveSha256','inventory','inventorySha256')}) for path,target in links: assert (path.parent/target).resolve().is_file() path.symlink_to(target) record={'success':True,'preparerSha256':sha(Path(__file__)),'source':str(source.relative_to(ROOT)), 'repositories':materialized,'regularFiles':count,'regularBytes':total,'symlinks':len(links), 'sourceReports':{str(p.relative_to(ROOT)):sha(p) for p in reports}, 'scope':'Fixed sources materialized for a separate local build. No source hooks, downloads or build executed by this preparer. Production dependency remains unchanged.'} (output/'source-materialization.json').write_text(json.dumps(record,indent=2)+'\n') print(json.dumps({'repositories':len(materialized),'regularFiles':count,'regularBytes':total,'symlinks':len(links)})) if __name__=='__main__':main()