52 lines
3.6 KiB
Python
52 lines
3.6 KiB
Python
from pathlib import Path
|
|
import json,hashlib,os,shutil,time
|
|
R=Path('/Users/korizatou114/Projects/とりにく工房ゲーム制作部')
|
|
D=R/'docs/plans/original-completion-2026-10-02/execution/drive-offload-p08-cold-pairs-20261015'
|
|
M=json.loads((D/'MANIFEST.json').read_bytes()); B=Path(M['base'])
|
|
def sha(p):
|
|
h=hashlib.sha256()
|
|
with p.open('rb') as f:
|
|
for b in iter(lambda:f.read(1024*1024),b''):h.update(b)
|
|
return h.hexdigest()
|
|
def read(n):return json.loads((D/n).read_bytes())
|
|
P=read('PREPARED.json'); V=read('CLOUD_ARCHIVE_VERIFIED.json'); parts=read('CLOUD_PARTS.json')
|
|
assert P['source_unchanged'] and P['actual_downloaded_tar_members_verified'] and V['all_cloud_archive_members_verified']
|
|
assert V['cloud_archive_sha256']==P['archive_sha256'] and V['cloud_archive_bytes']==P['archive_bytes']
|
|
assert len(parts)==24 and sum(x['bytes'] for x in parts)==P['archive_bytes']
|
|
for i,x in enumerate(parts):
|
|
assert x['order']==i and x['verified'] and x['actual_readback_sha256']==x['sha256'] and x['actual_readback_bytes']==x['bytes']
|
|
for name in ['MANIFEST.json','CLOUD_PARTS.json','RESTORE.md']:
|
|
v=read('READBACK-'+name+'.json');assert v['actual_cloud_readback_verified'] and v['sha256']==sha(D/name)
|
|
for entry in read('CLOUD_PART_METADATA.json')+read('CLOUD_METADATA.json'):
|
|
result=entry.get('result') or entry['metadata']; assert not result.get('isError')
|
|
s=result['structuredContent']; assert s['permissions'] and all(x['type']=='user' and x['role']=='owner' for x in s['permissions'])
|
|
assert s['parent_ids']==['1Xa2b6rQmwBFq4jWIDFcJgiCbcNYfWXsK']
|
|
roots=[B/x for x in M['roots']]
|
|
assert all(p.is_dir() and not p.is_symlink() for p in roots)
|
|
expected={x['path']:x for x in M['members']}
|
|
actual={p.relative_to(B).as_posix() for root in roots for p in [root,*root.rglob('*')]}
|
|
assert actual==set(expected)
|
|
protected={str(p):sha(p) for root in roots for p in root.parent.iterdir() if p.is_file()}
|
|
allocated=logical=files=0
|
|
for rel,x in expected.items():
|
|
p=B/rel; s=p.lstat(); assert not p.is_symlink()
|
|
assert s.st_mtime_ns==x['mtime_ns'] and s.st_mode&0o7777==x['mode'],rel
|
|
if x['type']=='file':
|
|
assert p.is_file() and s.st_size==x['bytes'] and sha(p)==x['sha256'],rel
|
|
allocated+=s.st_blocks*512;logical+=s.st_size;files+=1
|
|
else:assert p.is_dir()
|
|
assert files==M['files']==5554 and logical==M['logical_bytes']
|
|
free_before=shutil.disk_usage(B).free
|
|
for rel,x in expected.items():
|
|
if x['type']=='file':(B/rel).unlink()
|
|
for rel,x in sorted(expected.items(),key=lambda a:len(Path(a[0]).parts),reverse=True):
|
|
if x['type']=='directory':(B/rel).rmdir()
|
|
assert all(not p.exists() for p in roots)
|
|
assert protected=={p:sha(Path(p)) for p in protected}
|
|
pointer={'manifest':str(D/'MANIFEST.json'),'cloud_parts':str(D/'CLOUD_PARTS.json'),'restore':str(D/'RESTORE.md'),'folder_url':'https://drive.google.com/drive/folders/1Xa2b6rQmwBFq4jWIDFcJgiCbcNYfWXsK','archive_sha256':P['archive_sha256'],'roots':M['roots'],'local_originals_retired':True,'formal_credit':0}
|
|
for root in roots:(root.parent/'CLOUD_COLD_PAIR_HISTORY.json').write_text(json.dumps(pointer,ensure_ascii=False,indent=2)+'\n')
|
|
report=dict(files=files,logical_bytes=logical,allocated_bytes_before=allocated,free_before=free_before,free_after=shutil.disk_usage(B).free,all_original_files_reverified_before_removal=True,cloud_downloaded_archive_all_members_verified=True,protected_parent_files_unchanged=protected,deleted_only_manifest_members=True,formal_credit=0,completed_unix=time.time())
|
|
(D/'RETIREMENT.json').write_text(json.dumps(report,ensure_ascii=False,indent=2)+'\n')
|
|
shutil.copy2(__file__,D/'retire_verified.py')
|
|
print(json.dumps({k:v for k,v in report.items() if k!='protected_parent_files_unchanged'}))
|