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