HMCLIP / restore_backup.py
SteveZeyuZhang's picture
Add source files and streaming backup restore instructions
b91f38a
Raw History Blame Contribute Delete
1.32 kB
#!/usr/bin/env python3
"""Verify downloaded volumes, then extract without concatenating a large archive."""
import hashlib,json,subprocess,sys
from pathlib import Path
root=Path(__file__).resolve().parent
m=json.loads((root/'backup-manifest.json').read_text())
if not m['complete']: raise SystemExit('This backup is still uploading.')
for part in m['parts']:
p=root/part['path']; h=hashlib.sha256()
with p.open('rb') as f:
for block in iter(lambda:f.read(4*1024*1024),b''):h.update(block)
if p.stat().st_size!=part['size'] or h.hexdigest()!=part['sha256']:
raise SystemExit('Missing/corrupt volume or unmaterialized LFS pointer: '+str(p))
print('All volume checksums verified.',flush=True)
out=Path(sys.argv[1]).resolve() if len(sys.argv)>1 else root
out.mkdir(parents=True,exist_ok=True)
z=subprocess.Popen(['zstd','-d','-c'],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
t=subprocess.Popen(['tar','-xf','-','-C',str(out)],stdin=z.stdout)
z.stdout.close()
try:
for part in m['parts']:
with (root/part['path']).open('rb') as f:
for block in iter(lambda:f.read(4*1024*1024),b''):z.stdin.write(block)
z.stdin.close()
if z.wait()!=0 or t.wait()!=0:raise SystemExit('Extraction failed.')
finally:
for proc in [z,t]:
if proc.poll() is None:proc.terminate()
print('Restored the archived directories to',out)