| 
					
				 | 
			
			
				@@ -5,13 +5,14 @@ from datetime import datetime, timedelta, timezone 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from operator import attrgetter 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from collections.abc import Sequence 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from .logger import create_logger 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from borgstore.store import ObjectNotFound, ItemInfo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from .logger import create_logger 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 logger = create_logger() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .constants import *  # NOQA 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .helpers.datastruct import StableDict 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-from .helpers.parseformat import bin_to_hex 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from .helpers.parseformat import bin_to_hex, hex_to_bin 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .helpers.time import parse_timestamp, calculate_relative_offset, archive_ts_now 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .helpers.errors import Error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .patterns import get_regex_from_pattern 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -246,12 +247,10 @@ class Manifest: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def load(cls, repository, operations, key=None, *, ro_cls=RepoObj): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         from .item import ManifestItem 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         from .crypto.key import key_factory 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        from .remote3 import RemoteRepository3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         from .repository3 import Repository3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            cdata = repository.get(cls.MANIFEST_ID) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        except Repository3.ObjectNotFound: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            raise NoManifestError 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        cdata = repository.get_manifest() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if not key: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             key = key_factory(repository, cdata, ro_cls=ro_cls) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         manifest = cls(key, repository, ro_cls=ro_cls) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -261,7 +260,24 @@ class Manifest: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         manifest.id = manifest.repo_objs.id_hash(data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if m.get("version") not in (1, 2): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             raise ValueError("Invalid manifest version") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        manifest.archives.set_raw_dict(m.archives) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if isinstance(repository, (Repository3, RemoteRepository3)): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            from .helpers import msgpack 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            archives = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                infos = list(repository.store_list("archives")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            except ObjectNotFound: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                infos = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for info in infos: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                info = ItemInfo(*info)  # RPC does not give us a NamedTuple 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                value = repository.store_load(f"archives/{info.name}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _, value = manifest.repo_objs.parse(hex_to_bin(info.name), value, ro_type=ROBJ_MANIFEST) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                archive = msgpack.unpackb(value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                archives[archive["name"]] = dict(id=archive["id"], time=archive["time"]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            manifest.archives.set_raw_dict(archives) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            manifest.archives.set_raw_dict(m.archives) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         manifest.timestamp = m.get("timestamp") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         manifest.config = m.config 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # valid item keys are whatever is known in the repo or every key we know 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -298,6 +314,8 @@ class Manifest: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def write(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         from .item import ManifestItem 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        from .remote3 import RemoteRepository3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        from .repository3 import Repository3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # self.timestamp needs to be strictly monotonically increasing. Clocks often are not set correctly 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if self.timestamp is None: 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -312,12 +330,39 @@ class Manifest: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert all(len(name) <= 255 for name in self.archives) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert len(self.item_keys) <= 100 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.config["item_keys"] = tuple(sorted(self.item_keys)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if isinstance(self.repository, (Repository3, RemoteRepository3)): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            valid_keys = set() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for name, info in self.archives.get_raw_dict().items(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                archive = dict(name=name, id=info["id"], time=info["time"]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                value = self.key.pack_metadata(archive) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                id = self.repo_objs.id_hash(value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                key = bin_to_hex(id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                value = self.repo_objs.format(id, {}, value, ro_type=ROBJ_MANIFEST) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                self.repository.store_store(f"archives/{key}", value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                valid_keys.add(key) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # now, delete all other keys in archives/ which are not in valid keys / in the manifest anymore. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            # TODO: this is a dirty hack to simulate the old manifest behaviour closely, but also means 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            #       keeping its problems, like read-modify-write behaviour requiring an exclusive lock. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                infos = list(self.repository.store_list("archives")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            except ObjectNotFound: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                infos = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for info in infos: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                info = ItemInfo(*info)  # RPC does not give us a NamedTuple 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if info.name not in valid_keys: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    self.repository.store_delete(f"archives/{info.name}") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            manifest_archives = {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            manifest_archives = StableDict(self.archives.get_raw_dict()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         manifest = ManifestItem( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             version=2, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            archives=StableDict(self.archives.get_raw_dict()), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            archives=manifest_archives, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             timestamp=self.timestamp, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             config=StableDict(self.config), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         data = self.key.pack_metadata(manifest.as_dict()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.id = self.repo_objs.id_hash(data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        self.repository.put(self.MANIFEST_ID, self.repo_objs.format(self.MANIFEST_ID, {}, data, ro_type=ROBJ_MANIFEST)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        robj = self.repo_objs.format(self.MANIFEST_ID, {}, data, ro_type=ROBJ_MANIFEST) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.repository.put_manifest(robj) 
			 |