"""Restore archived historical ZIPs and exact distribution bytes to a fresh folder.""" import argparse,hashlib,json,os,shutil,zipfile from pathlib import Path def sha(p): with p.open('rb')as f:return hashlib.file_digest(f,'sha256').hexdigest() p=argparse.ArgumentParser();p.add_argument('manifest');p.add_argument('destination');p.add_argument('archives',nargs='+');a=p.parse_args();m=json.loads(Path(a.manifest).read_text());root=Path(a.destination).resolve();archives={} for name in a.archives: path=Path(name);h=sha(path);assert h not in archives;archives[h]=path assert set(archives)=={x['zip']['sha256']for x in m['items']} for item in m['items']: dest=root/item['name'];assert dest.resolve().is_relative_to(root)and not dest.exists()and not dest.is_symlink();source=archives[item['zip']['sha256']];assert source.stat().st_size==item['zip']['bytes'];dest.mkdir(parents=True) target=dest/Path(item['zip']['path']).name with source.open('rb')as inp,target.open('xb')as out:shutil.copyfileobj(inp,out,1024**2) assert sha(target)==item['zip']['sha256'];os.chmod(target,item['zip']['mode']);os.utime(target,ns=(item['zip']['mtime_ns'],item['zip']['mtime_ns'])) files={x['relative_path']:x for x in item['files']} with zipfile.ZipFile(source)as archive: assert set(archive.namelist())==set(files)and len(archive.infolist())==len(files) for name,x in files.items(): relative=Path(name);assert not relative.is_absolute()and '..'not in relative.parts;path=dest/'distribution'/relative;assert path.resolve().is_relative_to(dest)and not path.exists();path.parent.mkdir(parents=True,exist_ok=True);h=hashlib.sha256() with archive.open(name)as inp,path.open('xb')as out: for chunk in iter(lambda:inp.read(1024**2),b''):h.update(chunk);out.write(chunk) assert h.hexdigest()==x['sha256']and path.stat().st_size==x['bytes'];os.chmod(path,x['mode']);os.utime(path,ns=(x['mtime_ns'],x['mtime_ns'])) for d in reversed(item['directories']): path=dest/'distribution'/d['path'];os.chmod(path,d['mode']);os.utime(path,ns=(d['mtime_ns'],d['mtime_ns'])) print('Verified and restored',len(m['items']),'historical packages')