bundle_dag.py (3594B)
1 """Exact constructor/child-ID interning of verified portable DAGs; no expansion.""" 2 import struct,sys 3 from pathlib import Path 4 from stable_bundle import assembled,sections 5 6 def read(path): 7 m,n=sections(Path(path));off=12 8 def word(): 9 nonlocal off 10 v=struct.unpack_from('>I',m,off)[0];off+=4;return v 11 def string(): 12 nonlocal off 13 size=word();v=m[off:off+size];off+=size;return v 14 for _ in range(9):string() 15 for _ in range(word()):string() 16 off+=1 17 locations={} 18 for _ in range(word()): 19 pos=off;word();name=string().decode();locations.setdefault(name,[]).append(pos) 20 exports={} 21 for _ in range(word()): 22 name=string().decode();locations.setdefault(name,[]).append(off);exports[name]=word();string();string() 23 for _ in range(word()): 24 off+=2;string() 25 assert word()==0 26 assert off==len(m) 27 nodes=[];at=8 28 for i in range(struct.unpack_from('>Q',n,0)[0]): 29 size=struct.unpack_from('>I',n,at)[0];at+=4;p=n[at:at+size];at+=size 30 tag=p[0];assert tag in (0,1,2) 31 children=() if tag==0 else struct.unpack('>I' if tag==1 else '>II',p[1:]) 32 assert all(c<i for c in children) 33 nodes.append((tag,*children)) 34 assert at==len(n) 35 return m,n,nodes,exports,locations 36 37 class Intern: 38 def __init__(self):self.nodes=[];self.table={} 39 def node(self,key): 40 if key not in self.table:self.table[key]=len(self.nodes);self.nodes.append(key) 41 return self.table[key] 42 def graph(self,nodes): 43 ids=[] 44 for tag,*children in nodes:ids.append(self.node((tag,*[ids[c] for c in children]))) 45 return ids 46 def encoded(self): 47 rows=[] 48 for tag,*children in self.nodes: 49 p=bytes([tag])+b''.join(struct.pack('>I',c) for c in children);rows.append(struct.pack('>I',len(p))+p) 50 return struct.pack('>Q',len(rows))+b''.join(rows) 51 52 def contains(nodes,root,target): 53 seen=set();todo=[root] 54 while todo: 55 cur=todo.pop() 56 if cur in seen:continue 57 if cur==target:return True 58 seen.add(cur);todo.extend(nodes[cur][1:]) 59 return False 60 61 def merge_bundles(destination, selections, *, prune_unreachable=False): 62 """Intern selected complete public roots; retain order, validate exact structure. 63 Each selection is (bundle_path, [(old_export_name, new_export_name), ...]). 64 """ 65 intern=Intern();named=[];seen=set();first=read(selections[0][0])[0] 66 at=12 67 def word(): 68 nonlocal at 69 v=struct.unpack_from('>I',first,at)[0];at+=4;return v 70 def string(): 71 nonlocal at 72 n=word();at+=n 73 for _ in range(9):string() 74 for _ in range(word()):string() 75 at+=1;prefix=first[:at] 76 for _ in range(word()):word();string() 77 for _ in range(word()):string();word();string();string() 78 suffix=first[at:] 79 def text(v): 80 b=v.encode();return struct.pack('>I',len(b))+b 81 for path,names in selections: 82 bundle=read(path) 83 if prune_unreachable: 84 reachable=set();todo=[bundle[3][old] for old,_ in names] 85 while todo: 86 root=todo.pop() 87 if root in reachable:continue 88 reachable.add(root);todo.extend(bundle[2][root][1:]) 89 ids={} 90 for index in sorted(reachable): 91 tag,*children=bundle[2][index] 92 ids[index]=intern.node((tag,*[ids[c] for c in children])) 93 else: 94 ids=intern.graph(bundle[2]) 95 for old,new in names: 96 assert new not in seen;seen.add(new);named.append((new,ids[bundle[3][old]])) 97 roots=struct.pack('>I',len(named))+b''.join(struct.pack('>I',v)+text(k) for k,v in named) 98 exports=struct.pack('>I',len(named))+b''.join(text(k)+struct.pack('>I',v)+text('term')+text('arboricx.abi.tree.v1') for k,v in named) 99 Path(destination).write_bytes(assembled(prefix+roots+exports+suffix,intern.encoded())) 100 check=read(destination);ids=intern.graph(check[2]);assert {k:ids[v] for k,v in check[3].items()}==dict(named)