| 1309 | return Meta(nfiles=len(new), isdir=True), new |
| 1310 | |
| 1311 | def apply( |
| 1312 | self, |
| 1313 | path: str, |
| 1314 | obj: Union["Tree", "HashFile"], |
| 1315 | meta: "Meta", |
| 1316 | ) -> tuple["Meta", "Tree"]: |
| 1317 | from pygtrie import Trie |
| 1318 | |
| 1319 | append_only = True |
| 1320 | rel_key = tuple(self.fs.parts(self.fs.relpath(path, self.fs_path))) |
| 1321 | |
| 1322 | if self.hash_info: |
| 1323 | tree = self.get_dir_cache() |
| 1324 | if tree is None: |
| 1325 | raise DvcException(f"could not read {self.hash_info.value!r}") |
| 1326 | else: |
| 1327 | tree = Tree() |
| 1328 | |
| 1329 | trie = tree.as_trie() |
| 1330 | assert isinstance(trie, Trie) |
| 1331 | |
| 1332 | try: |
| 1333 | del trie[rel_key:] # type: ignore[misc] |
| 1334 | except KeyError: |
| 1335 | pass |
| 1336 | else: |
| 1337 | append_only = False |
| 1338 | |
| 1339 | items = {} |
| 1340 | if isinstance(obj, Tree): |
| 1341 | items = {(*rel_key, *key): (m, o) for key, m, o in obj} |
| 1342 | else: |
| 1343 | items = {rel_key: (meta, obj.hash_info)} |
| 1344 | trie.update(items) |
| 1345 | |
| 1346 | new = Tree.from_trie(trie) |
| 1347 | new.digest() |
| 1348 | |
| 1349 | size = self.meta.size if self.meta and self.meta.size else None |
| 1350 | if append_only and size and meta.size is not None: |
| 1351 | # if files were only appended, we can sum to the existing size |
| 1352 | size += meta.size |
| 1353 | elif self.hash_info and self.hash_info == new.hash_info: |
| 1354 | # if hashes are same, sizes must have been the same |
| 1355 | size = self.meta.size |
| 1356 | else: |
| 1357 | size = None |
| 1358 | |
| 1359 | meta = Meta(nfiles=len(new), size=size, isdir=True) |
| 1360 | return meta, new |
| 1361 | |
| 1362 | def add( # noqa: C901 |
| 1363 | self, path: Optional[str] = None, no_commit: bool = False, relink: bool = True |