462 class BaseStoreEntry: |
462 class BaseStoreEntry: |
463 """An entry in the store |
463 """An entry in the store |
464 |
464 |
465 This is returned by `store.walk` and represent some data in the store.""" |
465 This is returned by `store.walk` and represent some data in the store.""" |
466 |
466 |
|
467 |
|
468 @attr.s(slots=True, init=False) |
|
469 class SimpleStoreEntry(BaseStoreEntry): |
|
470 """A generic entry in the store""" |
|
471 |
|
472 is_revlog = False |
|
473 |
467 _entry_path = attr.ib() |
474 _entry_path = attr.ib() |
468 _is_volatile = attr.ib(default=False) |
475 _is_volatile = attr.ib(default=False) |
469 _file_size = attr.ib(default=None) |
476 _file_size = attr.ib(default=None) |
470 |
477 |
471 def __init__( |
478 def __init__( |
472 self, |
479 self, |
473 entry_path, |
480 entry_path, |
474 is_volatile=False, |
481 is_volatile=False, |
475 file_size=None, |
482 file_size=None, |
476 ): |
483 ): |
|
484 super().__init__() |
477 self._entry_path = entry_path |
485 self._entry_path = entry_path |
478 self._is_volatile = is_volatile |
486 self._is_volatile = is_volatile |
479 self._file_size = file_size |
487 self._file_size = file_size |
480 |
488 |
481 def files(self): |
489 def files(self): |
487 ) |
495 ) |
488 ] |
496 ] |
489 |
497 |
490 |
498 |
491 @attr.s(slots=True, init=False) |
499 @attr.s(slots=True, init=False) |
492 class SimpleStoreEntry(BaseStoreEntry): |
|
493 """A generic entry in the store""" |
|
494 |
|
495 is_revlog = False |
|
496 |
|
497 |
|
498 @attr.s(slots=True, init=False) |
|
499 class RevlogStoreEntry(BaseStoreEntry): |
500 class RevlogStoreEntry(BaseStoreEntry): |
500 """A revlog entry in the store""" |
501 """A revlog entry in the store""" |
501 |
502 |
502 is_revlog = True |
503 is_revlog = True |
|
504 |
503 revlog_type = attr.ib(default=None) |
505 revlog_type = attr.ib(default=None) |
504 target_id = attr.ib(default=None) |
506 target_id = attr.ib(default=None) |
505 is_revlog_main = attr.ib(default=None) |
507 _path_prefix = attr.ib(default=None) |
|
508 _details = attr.ib(default=None) |
506 |
509 |
507 def __init__( |
510 def __init__( |
508 self, |
511 self, |
509 entry_path, |
|
510 revlog_type, |
512 revlog_type, |
|
513 path_prefix, |
511 target_id, |
514 target_id, |
512 is_revlog_main=False, |
515 details, |
513 is_volatile=False, |
|
514 file_size=None, |
|
515 ): |
516 ): |
516 super().__init__( |
517 super().__init__() |
517 entry_path=entry_path, |
|
518 is_volatile=is_volatile, |
|
519 file_size=file_size, |
|
520 ) |
|
521 self.revlog_type = revlog_type |
518 self.revlog_type = revlog_type |
522 self.target_id = target_id |
519 self.target_id = target_id |
523 self.is_revlog_main = is_revlog_main |
520 self._path_prefix = path_prefix |
|
521 assert b'.i' in details, (path_prefix, details) |
|
522 self._details = details |
524 |
523 |
525 def main_file_path(self): |
524 def main_file_path(self): |
526 """unencoded path of the main revlog file""" |
525 """unencoded path of the main revlog file""" |
527 return self._entry_path |
526 return self._path_prefix + b'.i' |
|
527 |
|
528 def files(self): |
|
529 files = [] |
|
530 for ext in sorted(self._details, key=_ext_key): |
|
531 path = self._path_prefix + ext |
|
532 data = self._details[ext] |
|
533 files.append(StoreFile(unencoded_path=path, **data)) |
|
534 return files |
528 |
535 |
529 |
536 |
530 @attr.s(slots=True) |
537 @attr.s(slots=True) |
531 class StoreFile: |
538 class StoreFile: |
532 """a file matching an entry""" |
539 """a file matching an entry""" |
533 |
540 |
534 unencoded_path = attr.ib() |
541 unencoded_path = attr.ib() |
535 _file_size = attr.ib(default=False) |
542 _file_size = attr.ib(default=None) |
536 is_volatile = attr.ib(default=False) |
543 is_volatile = attr.ib(default=False) |
537 |
544 |
538 def file_size(self, vfs): |
545 def file_size(self, vfs): |
539 if self._file_size is not None: |
546 if self._file_size is not None: |
540 return self._file_size |
547 return self._file_size |
650 ] |
657 ] |
651 for base_dir, rl_type in dirs: |
658 for base_dir, rl_type in dirs: |
652 files = self._walk(base_dir, True, undecodable=undecodable) |
659 files = self._walk(base_dir, True, undecodable=undecodable) |
653 files = (f for f in files if f[1][0] is not None) |
660 files = (f for f in files if f[1][0] is not None) |
654 for revlog, details in _gather_revlog(files): |
661 for revlog, details in _gather_revlog(files): |
|
662 file_details = {} |
|
663 revlog_target_id = revlog.split(b'/', 1)[1] |
655 for ext, (t, s) in sorted(details.items()): |
664 for ext, (t, s) in sorted(details.items()): |
656 u = revlog + ext |
665 file_details[ext] = { |
657 revlog_target_id = revlog.split(b'/', 1)[1] |
666 'is_volatile': bool(t & FILEFLAGS_VOLATILE), |
658 yield RevlogStoreEntry( |
667 'file_size': s, |
659 entry_path=u, |
668 } |
660 revlog_type=rl_type, |
669 yield RevlogStoreEntry( |
661 target_id=revlog_target_id, |
670 path_prefix=revlog, |
662 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN), |
671 revlog_type=rl_type, |
663 is_volatile=bool(t & FILEFLAGS_VOLATILE), |
672 target_id=revlog_target_id, |
664 file_size=s, |
673 details=file_details, |
665 ) |
674 ) |
666 |
675 |
667 def topfiles(self) -> Generator[BaseStoreEntry, None, None]: |
676 def topfiles(self) -> Generator[BaseStoreEntry, None, None]: |
668 files = reversed(self._walk(b'', False)) |
677 files = reversed(self._walk(b'', False)) |
669 |
678 |
670 changelogs = collections.defaultdict(dict) |
679 changelogs = collections.defaultdict(dict) |
690 ] |
699 ] |
691 assert len(manifestlogs) <= 1 |
700 assert len(manifestlogs) <= 1 |
692 assert len(changelogs) <= 1 |
701 assert len(changelogs) <= 1 |
693 for data, revlog_type in top_rl: |
702 for data, revlog_type in top_rl: |
694 for revlog, details in sorted(data.items()): |
703 for revlog, details in sorted(data.items()): |
695 # (keeping ordering so we get 00changelog.i last) |
704 file_details = {} |
696 key = lambda x: _ext_key(x[0]) |
705 for ext, (t, s) in details.items(): |
697 for ext, (t, s) in sorted(details.items(), key=key): |
706 file_details[ext] = { |
698 u = revlog + ext |
707 'is_volatile': bool(t & FILEFLAGS_VOLATILE), |
699 yield RevlogStoreEntry( |
708 'file_size': s, |
700 entry_path=u, |
709 } |
701 revlog_type=revlog_type, |
710 yield RevlogStoreEntry( |
702 target_id=b'', |
711 path_prefix=revlog, |
703 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN), |
712 revlog_type=revlog_type, |
704 is_volatile=bool(t & FILEFLAGS_VOLATILE), |
713 target_id=b'', |
705 file_size=s, |
714 details=file_details, |
706 ) |
715 ) |
707 |
716 |
708 def walk(self, matcher=None) -> Generator[BaseStoreEntry, None, None]: |
717 def walk(self, matcher=None) -> Generator[BaseStoreEntry, None, None]: |
709 """return files related to data storage (ie: revlogs) |
718 """return files related to data storage (ie: revlogs) |
710 |
719 |
711 yields (file_type, unencoded, size) |
720 yields (file_type, unencoded, size) |
979 # fncache might contains such file added by previous version of |
988 # fncache might contains such file added by previous version of |
980 # Mercurial. |
989 # Mercurial. |
981 files = (f for f in files if f[1] is not None) |
990 files = (f for f in files if f[1] is not None) |
982 by_revlog = _gather_revlog(files) |
991 by_revlog = _gather_revlog(files) |
983 for revlog, details in by_revlog: |
992 for revlog, details in by_revlog: |
|
993 file_details = {} |
984 if revlog.startswith(b'data/'): |
994 if revlog.startswith(b'data/'): |
985 rl_type = FILEFLAGS_FILELOG |
995 rl_type = FILEFLAGS_FILELOG |
986 revlog_target_id = revlog.split(b'/', 1)[1] |
996 revlog_target_id = revlog.split(b'/', 1)[1] |
987 elif revlog.startswith(b'meta/'): |
997 elif revlog.startswith(b'meta/'): |
988 rl_type = FILEFLAGS_MANIFESTLOG |
998 rl_type = FILEFLAGS_MANIFESTLOG |
990 tmp = revlog.split(b'/', 1)[1] |
1000 tmp = revlog.split(b'/', 1)[1] |
991 revlog_target_id = tmp.rsplit(b'/', 1)[0] + b'/' |
1001 revlog_target_id = tmp.rsplit(b'/', 1)[0] + b'/' |
992 else: |
1002 else: |
993 # unreachable |
1003 # unreachable |
994 assert False, revlog |
1004 assert False, revlog |
995 for ext, t in sorted(details.items()): |
1005 for ext, t in details.items(): |
996 f = revlog + ext |
1006 file_details[ext] = { |
997 entry = RevlogStoreEntry( |
1007 'is_volatile': bool(t & FILEFLAGS_VOLATILE), |
998 entry_path=f, |
1008 } |
999 revlog_type=rl_type, |
1009 entry = RevlogStoreEntry( |
1000 target_id=revlog_target_id, |
1010 path_prefix=revlog, |
1001 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN), |
1011 revlog_type=rl_type, |
1002 is_volatile=bool(t & FILEFLAGS_VOLATILE), |
1012 target_id=revlog_target_id, |
1003 ) |
1013 details=file_details, |
1004 if _match_tracked_entry(entry, matcher): |
1014 ) |
1005 yield entry |
1015 if _match_tracked_entry(entry, matcher): |
|
1016 yield entry |
1006 |
1017 |
1007 def copylist(self): |
1018 def copylist(self): |
1008 d = ( |
1019 d = ( |
1009 b'bookmarks', |
1020 b'bookmarks', |
1010 b'narrowspec', |
1021 b'narrowspec', |