Show More
@@ -441,10 +441,13 b' def _splittopdir(f):' | |||||
441 | else: |
|
441 | else: | |
442 | return '', f |
|
442 | return '', f | |
443 |
|
443 | |||
|
444 | _noop = lambda: None | |||
|
445 | ||||
444 | class treemanifest(object): |
|
446 | class treemanifest(object): | |
445 | def __init__(self, dir='', text=''): |
|
447 | def __init__(self, dir='', text=''): | |
446 | self._dir = dir |
|
448 | self._dir = dir | |
447 | self._node = revlog.nullid |
|
449 | self._node = revlog.nullid | |
|
450 | self._load = _noop | |||
448 | self._dirty = False |
|
451 | self._dirty = False | |
449 | self._dirs = {} |
|
452 | self._dirs = {} | |
450 | # Using _lazymanifest here is a little slower than plain old dicts |
|
453 | # Using _lazymanifest here is a little slower than plain old dicts | |
@@ -461,18 +464,22 b' class treemanifest(object):' | |||||
461 | return self._dir + path |
|
464 | return self._dir + path | |
462 |
|
465 | |||
463 | def __len__(self): |
|
466 | def __len__(self): | |
|
467 | self._load() | |||
464 | size = len(self._files) |
|
468 | size = len(self._files) | |
465 | for m in self._dirs.values(): |
|
469 | for m in self._dirs.values(): | |
466 | size += m.__len__() |
|
470 | size += m.__len__() | |
467 | return size |
|
471 | return size | |
468 |
|
472 | |||
469 | def _isempty(self): |
|
473 | def _isempty(self): | |
|
474 | self._load() # for consistency; already loaded by all callers | |||
470 | return (not self._files and (not self._dirs or |
|
475 | return (not self._files and (not self._dirs or | |
471 | all(m._isempty() for m in self._dirs.values()))) |
|
476 | all(m._isempty() for m in self._dirs.values()))) | |
472 |
|
477 | |||
473 | def __str__(self): |
|
478 | def __str__(self): | |
474 | return ('<treemanifest dir=%s, node=%s, dirty=%s>' % |
|
479 | return ('<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s>' % | |
475 |
(self._dir, revlog.hex(self._node), |
|
480 | (self._dir, revlog.hex(self._node), | |
|
481 | bool(self._load is _noop), | |||
|
482 | self._dirty)) | |||
476 |
|
483 | |||
477 | def dir(self): |
|
484 | def dir(self): | |
478 | '''The directory that this tree manifest represents, including a |
|
485 | '''The directory that this tree manifest represents, including a | |
@@ -491,6 +498,7 b' class treemanifest(object):' | |||||
491 | self._dirty = False |
|
498 | self._dirty = False | |
492 |
|
499 | |||
493 | def iteritems(self): |
|
500 | def iteritems(self): | |
|
501 | self._load() | |||
494 | for p, n in sorted(self._dirs.items() + self._files.items()): |
|
502 | for p, n in sorted(self._dirs.items() + self._files.items()): | |
495 | if p in self._files: |
|
503 | if p in self._files: | |
496 | yield self._subpath(p), n |
|
504 | yield self._subpath(p), n | |
@@ -499,6 +507,7 b' class treemanifest(object):' | |||||
499 | yield f, sn |
|
507 | yield f, sn | |
500 |
|
508 | |||
501 | def iterkeys(self): |
|
509 | def iterkeys(self): | |
|
510 | self._load() | |||
502 | for p in sorted(self._dirs.keys() + self._files.keys()): |
|
511 | for p in sorted(self._dirs.keys() + self._files.keys()): | |
503 | if p in self._files: |
|
512 | if p in self._files: | |
504 | yield self._subpath(p) |
|
513 | yield self._subpath(p) | |
@@ -515,6 +524,7 b' class treemanifest(object):' | |||||
515 | def __contains__(self, f): |
|
524 | def __contains__(self, f): | |
516 | if f is None: |
|
525 | if f is None: | |
517 | return False |
|
526 | return False | |
|
527 | self._load() | |||
518 | dir, subpath = _splittopdir(f) |
|
528 | dir, subpath = _splittopdir(f) | |
519 | if dir: |
|
529 | if dir: | |
520 | if dir not in self._dirs: |
|
530 | if dir not in self._dirs: | |
@@ -524,6 +534,7 b' class treemanifest(object):' | |||||
524 | return f in self._files |
|
534 | return f in self._files | |
525 |
|
535 | |||
526 | def get(self, f, default=None): |
|
536 | def get(self, f, default=None): | |
|
537 | self._load() | |||
527 | dir, subpath = _splittopdir(f) |
|
538 | dir, subpath = _splittopdir(f) | |
528 | if dir: |
|
539 | if dir: | |
529 | if dir not in self._dirs: |
|
540 | if dir not in self._dirs: | |
@@ -533,6 +544,7 b' class treemanifest(object):' | |||||
533 | return self._files.get(f, default) |
|
544 | return self._files.get(f, default) | |
534 |
|
545 | |||
535 | def __getitem__(self, f): |
|
546 | def __getitem__(self, f): | |
|
547 | self._load() | |||
536 | dir, subpath = _splittopdir(f) |
|
548 | dir, subpath = _splittopdir(f) | |
537 | if dir: |
|
549 | if dir: | |
538 | return self._dirs[dir].__getitem__(subpath) |
|
550 | return self._dirs[dir].__getitem__(subpath) | |
@@ -540,6 +552,7 b' class treemanifest(object):' | |||||
540 | return self._files[f] |
|
552 | return self._files[f] | |
541 |
|
553 | |||
542 | def flags(self, f): |
|
554 | def flags(self, f): | |
|
555 | self._load() | |||
543 | dir, subpath = _splittopdir(f) |
|
556 | dir, subpath = _splittopdir(f) | |
544 | if dir: |
|
557 | if dir: | |
545 | if dir not in self._dirs: |
|
558 | if dir not in self._dirs: | |
@@ -551,6 +564,7 b' class treemanifest(object):' | |||||
551 | return self._flags.get(f, '') |
|
564 | return self._flags.get(f, '') | |
552 |
|
565 | |||
553 | def find(self, f): |
|
566 | def find(self, f): | |
|
567 | self._load() | |||
554 | dir, subpath = _splittopdir(f) |
|
568 | dir, subpath = _splittopdir(f) | |
555 | if dir: |
|
569 | if dir: | |
556 | return self._dirs[dir].find(subpath) |
|
570 | return self._dirs[dir].find(subpath) | |
@@ -558,6 +572,7 b' class treemanifest(object):' | |||||
558 | return self._files[f], self._flags.get(f, '') |
|
572 | return self._files[f], self._flags.get(f, '') | |
559 |
|
573 | |||
560 | def __delitem__(self, f): |
|
574 | def __delitem__(self, f): | |
|
575 | self._load() | |||
561 | dir, subpath = _splittopdir(f) |
|
576 | dir, subpath = _splittopdir(f) | |
562 | if dir: |
|
577 | if dir: | |
563 | self._dirs[dir].__delitem__(subpath) |
|
578 | self._dirs[dir].__delitem__(subpath) | |
@@ -572,6 +587,7 b' class treemanifest(object):' | |||||
572 |
|
587 | |||
573 | def __setitem__(self, f, n): |
|
588 | def __setitem__(self, f, n): | |
574 | assert n is not None |
|
589 | assert n is not None | |
|
590 | self._load() | |||
575 | dir, subpath = _splittopdir(f) |
|
591 | dir, subpath = _splittopdir(f) | |
576 | if dir: |
|
592 | if dir: | |
577 | if dir not in self._dirs: |
|
593 | if dir not in self._dirs: | |
@@ -584,6 +600,7 b' class treemanifest(object):' | |||||
584 | def setflag(self, f, flags): |
|
600 | def setflag(self, f, flags): | |
585 | """Set the flags (symlink, executable) for path f.""" |
|
601 | """Set the flags (symlink, executable) for path f.""" | |
586 | assert 'd' not in flags |
|
602 | assert 'd' not in flags | |
|
603 | self._load() | |||
587 | dir, subpath = _splittopdir(f) |
|
604 | dir, subpath = _splittopdir(f) | |
588 | if dir: |
|
605 | if dir: | |
589 | if dir not in self._dirs: |
|
606 | if dir not in self._dirs: | |
@@ -597,10 +614,19 b' class treemanifest(object):' | |||||
597 | copy = treemanifest(self._dir) |
|
614 | copy = treemanifest(self._dir) | |
598 | copy._node = self._node |
|
615 | copy._node = self._node | |
599 | copy._dirty = self._dirty |
|
616 | copy._dirty = self._dirty | |
600 | for d in self._dirs: |
|
617 | def _load(): | |
601 | copy._dirs[d] = self._dirs[d].copy() |
|
618 | self._load() | |
602 | copy._files = dict.copy(self._files) |
|
619 | for d in self._dirs: | |
603 | copy._flags = dict.copy(self._flags) |
|
620 | copy._dirs[d] = self._dirs[d].copy() | |
|
621 | copy._files = dict.copy(self._files) | |||
|
622 | copy._flags = dict.copy(self._flags) | |||
|
623 | copy._load = _noop | |||
|
624 | copy._load = _load | |||
|
625 | if self._load == _noop: | |||
|
626 | # Chaining _load if it's _noop is functionally correct, but the | |||
|
627 | # chain may end up excessively long (stack overflow), and | |||
|
628 | # will prevent garbage collection of 'self'. | |||
|
629 | copy._load() | |||
604 | return copy |
|
630 | return copy | |
605 |
|
631 | |||
606 | def filesnotin(self, m2): |
|
632 | def filesnotin(self, m2): | |
@@ -609,6 +635,8 b' class treemanifest(object):' | |||||
609 | def _filesnotin(t1, t2): |
|
635 | def _filesnotin(t1, t2): | |
610 | if t1._node == t2._node and not t1._dirty and not t2._dirty: |
|
636 | if t1._node == t2._node and not t1._dirty and not t2._dirty: | |
611 | return |
|
637 | return | |
|
638 | t1._load() | |||
|
639 | t2._load() | |||
612 | for d, m1 in t1._dirs.iteritems(): |
|
640 | for d, m1 in t1._dirs.iteritems(): | |
613 | if d in t2._dirs: |
|
641 | if d in t2._dirs: | |
614 | m2 = t2._dirs[d] |
|
642 | m2 = t2._dirs[d] | |
@@ -631,6 +659,7 b' class treemanifest(object):' | |||||
631 | return self._alldirs |
|
659 | return self._alldirs | |
632 |
|
660 | |||
633 | def hasdir(self, dir): |
|
661 | def hasdir(self, dir): | |
|
662 | self._load() | |||
634 | topdir, subdir = _splittopdir(dir) |
|
663 | topdir, subdir = _splittopdir(dir) | |
635 | if topdir: |
|
664 | if topdir: | |
636 | if topdir in self._dirs: |
|
665 | if topdir in self._dirs: | |
@@ -673,6 +702,7 b' class treemanifest(object):' | |||||
673 | return |
|
702 | return | |
674 |
|
703 | |||
675 | # yield this dir's files and walk its submanifests |
|
704 | # yield this dir's files and walk its submanifests | |
|
705 | self._load() | |||
676 | for p in sorted(self._dirs.keys() + self._files.keys()): |
|
706 | for p in sorted(self._dirs.keys() + self._files.keys()): | |
677 | if p in self._files: |
|
707 | if p in self._files: | |
678 | fullp = self._subpath(p) |
|
708 | fullp = self._subpath(p) | |
@@ -697,6 +727,7 b' class treemanifest(object):' | |||||
697 | if not match.visitdir(self._dir[:-1] or '.'): |
|
727 | if not match.visitdir(self._dir[:-1] or '.'): | |
698 | return ret |
|
728 | return ret | |
699 |
|
729 | |||
|
730 | self._load() | |||
700 | for fn in self._files: |
|
731 | for fn in self._files: | |
701 | fullp = self._subpath(fn) |
|
732 | fullp = self._subpath(fn) | |
702 | if not match(fullp): |
|
733 | if not match(fullp): | |
@@ -734,6 +765,8 b' class treemanifest(object):' | |||||
734 | def _diff(t1, t2): |
|
765 | def _diff(t1, t2): | |
735 | if t1._node == t2._node and not t1._dirty and not t2._dirty: |
|
766 | if t1._node == t2._node and not t1._dirty and not t2._dirty: | |
736 | return |
|
767 | return | |
|
768 | t1._load() | |||
|
769 | t2._load() | |||
737 | for d, m1 in t1._dirs.iteritems(): |
|
770 | for d, m1 in t1._dirs.iteritems(): | |
738 | m2 = t2._dirs.get(d, emptytree) |
|
771 | m2 = t2._dirs.get(d, emptytree) | |
739 | _diff(m1, m2) |
|
772 | _diff(m1, m2) | |
@@ -784,6 +817,7 b' class treemanifest(object):' | |||||
784 |
|
817 | |||
785 | def text(self, usemanifestv2=False): |
|
818 | def text(self, usemanifestv2=False): | |
786 | """Get the full data of this manifest as a bytestring.""" |
|
819 | """Get the full data of this manifest as a bytestring.""" | |
|
820 | self._load() | |||
787 | flags = self.flags |
|
821 | flags = self.flags | |
788 | return _text(((f, self[f], flags(f)) for f in self.keys()), |
|
822 | return _text(((f, self[f], flags(f)) for f in self.keys()), | |
789 | usemanifestv2) |
|
823 | usemanifestv2) | |
@@ -792,12 +826,23 b' class treemanifest(object):' | |||||
792 | """Get the full data of this directory as a bytestring. Make sure that |
|
826 | """Get the full data of this directory as a bytestring. Make sure that | |
793 | any submanifests have been written first, so their nodeids are correct. |
|
827 | any submanifests have been written first, so their nodeids are correct. | |
794 | """ |
|
828 | """ | |
|
829 | self._load() | |||
795 | flags = self.flags |
|
830 | flags = self.flags | |
796 | dirs = [(d[:-1], self._dirs[d]._node, 'd') for d in self._dirs] |
|
831 | dirs = [(d[:-1], self._dirs[d]._node, 'd') for d in self._dirs] | |
797 | files = [(f, self._files[f], flags(f)) for f in self._files] |
|
832 | files = [(f, self._files[f], flags(f)) for f in self._files] | |
798 | return _text(sorted(dirs + files), usemanifestv2) |
|
833 | return _text(sorted(dirs + files), usemanifestv2) | |
799 |
|
834 | |||
|
835 | def read(self, gettext, readsubtree): | |||
|
836 | def _load(): | |||
|
837 | # Mark as loaded already here, so __setitem__ and setflag() don't | |||
|
838 | # cause infinite loops when they try to load. | |||
|
839 | self._load = _noop | |||
|
840 | self.parse(gettext(), readsubtree) | |||
|
841 | self._dirty = False | |||
|
842 | self._load = _load | |||
|
843 | ||||
800 | def writesubtrees(self, m1, m2, writesubtree): |
|
844 | def writesubtrees(self, m1, m2, writesubtree): | |
|
845 | self._load() # for consistency; should never have any effect here | |||
801 | emptytree = treemanifest() |
|
846 | emptytree = treemanifest() | |
802 | for d, subm in self._dirs.iteritems(): |
|
847 | for d, subm in self._dirs.iteritems(): | |
803 | subp1 = m1._dirs.get(d, emptytree)._node |
|
848 | subp1 = m1._dirs.get(d, emptytree)._node | |
@@ -891,15 +936,17 b' class manifest(revlog.revlog):' | |||||
891 | return self._newmanifest() # don't upset local cache |
|
936 | return self._newmanifest() # don't upset local cache | |
892 | if node in self._mancache: |
|
937 | if node in self._mancache: | |
893 | return self._mancache[node][0] |
|
938 | return self._mancache[node][0] | |
894 | text = self.revision(node) |
|
|||
895 | if self._treeondisk: |
|
939 | if self._treeondisk: | |
|
940 | def gettext(): | |||
|
941 | return self.revision(node) | |||
896 | def readsubtree(dir, subm): |
|
942 | def readsubtree(dir, subm): | |
897 | return self.dirlog(dir).read(subm) |
|
943 | return self.dirlog(dir).read(subm) | |
898 | m = self._newmanifest() |
|
944 | m = self._newmanifest() | |
899 |
m. |
|
945 | m.read(gettext, readsubtree) | |
900 | m.setnode(node) |
|
946 | m.setnode(node) | |
901 | arraytext = None |
|
947 | arraytext = None | |
902 | else: |
|
948 | else: | |
|
949 | text = self.revision(node) | |||
903 | m = self._newmanifest(text) |
|
950 | m = self._newmanifest(text) | |
904 | arraytext = array.array('c', text) |
|
951 | arraytext = array.array('c', text) | |
905 | self._mancache[node] = (m, arraytext) |
|
952 | self._mancache[node] = (m, arraytext) |
@@ -78,9 +78,11 b' Removing directory does not create an re' | |||||
78 | $ rm before after |
|
78 | $ rm before after | |
79 |
|
79 | |||
80 | Check that hg files (calls treemanifest.walk()) works |
|
80 | Check that hg files (calls treemanifest.walk()) works | |
|
81 | without loading all directory revlogs | |||
81 |
|
82 | |||
82 | $ hg co 'desc("add dir2")' |
|
83 | $ hg co 'desc("add dir2")' | |
83 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
84 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
85 | $ mv .hg/store/meta/dir2 .hg/store/meta/dir2-backup | |||
84 | $ hg files -r . dir1 |
|
86 | $ hg files -r . dir1 | |
85 | dir1/a (glob) |
|
87 | dir1/a (glob) | |
86 | dir1/b (glob) |
|
88 | dir1/b (glob) | |
@@ -90,12 +92,14 b' Check that hg files (calls treemanifest.' | |||||
90 | dir1/dir2/b (glob) |
|
92 | dir1/dir2/b (glob) | |
91 |
|
93 | |||
92 | Check that status between revisions works (calls treemanifest.matches()) |
|
94 | Check that status between revisions works (calls treemanifest.matches()) | |
|
95 | without loading all directory revlogs | |||
93 |
|
96 | |||
94 |
$ |
|
97 | $ hg status --rev 'desc("add dir1")' --rev . dir1 | |
95 | A dir1/dir1/a |
|
98 | A dir1/dir1/a | |
96 | A dir1/dir1/b |
|
99 | A dir1/dir1/b | |
97 | A dir1/dir2/a |
|
100 | A dir1/dir2/a | |
98 | A dir1/dir2/b |
|
101 | A dir1/dir2/b | |
|
102 | $ mv .hg/store/meta/dir2-backup .hg/store/meta/dir2 | |||
99 |
|
103 | |||
100 | Merge creates 2-parent revision of directory revlog |
|
104 | Merge creates 2-parent revision of directory revlog | |
101 |
|
105 |
General Comments 0
You need to be logged in to leave comments.
Login now