440 dir, subpath = f.split('/', 1) |
440 dir, subpath = f.split('/', 1) |
441 return dir + '/', subpath |
441 return dir + '/', subpath |
442 else: |
442 else: |
443 return '', f |
443 return '', f |
444 |
444 |
445 _noop = lambda: None |
445 _noop = lambda s: None |
446 |
446 |
447 class treemanifest(object): |
447 class treemanifest(object): |
448 def __init__(self, dir='', text=''): |
448 def __init__(self, dir='', text=''): |
449 self._dir = dir |
449 self._dir = dir |
450 self._node = revlog.nullid |
450 self._node = revlog.nullid |
451 self._load = _noop |
451 self._loadfunc = _noop |
|
452 self._copyfunc = _noop |
452 self._dirty = False |
453 self._dirty = False |
453 self._dirs = {} |
454 self._dirs = {} |
454 # Using _lazymanifest here is a little slower than plain old dicts |
455 # Using _lazymanifest here is a little slower than plain old dicts |
455 self._files = {} |
456 self._files = {} |
456 self._flags = {} |
457 self._flags = {} |
477 all(m._isempty() for m in self._dirs.values()))) |
478 all(m._isempty() for m in self._dirs.values()))) |
478 |
479 |
479 def __repr__(self): |
480 def __repr__(self): |
480 return ('<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s at 0x%x>' % |
481 return ('<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s at 0x%x>' % |
481 (self._dir, revlog.hex(self._node), |
482 (self._dir, revlog.hex(self._node), |
482 bool(self._load is _noop), |
483 bool(self._loadfunc is _noop), |
483 self._dirty, id(self))) |
484 self._dirty, id(self))) |
484 |
485 |
485 def dir(self): |
486 def dir(self): |
486 '''The directory that this tree manifest represents, including a |
487 '''The directory that this tree manifest represents, including a |
487 trailing '/'. Empty string for the repo root directory.''' |
488 trailing '/'. Empty string for the repo root directory.''' |
596 self._dirs[dir].__setitem__(subpath, n) |
597 self._dirs[dir].__setitem__(subpath, n) |
597 else: |
598 else: |
598 self._files[f] = n[:21] # to match manifestdict's behavior |
599 self._files[f] = n[:21] # to match manifestdict's behavior |
599 self._dirty = True |
600 self._dirty = True |
600 |
601 |
|
602 def _load(self): |
|
603 if self._loadfunc is not _noop: |
|
604 lf, self._loadfunc = self._loadfunc, _noop |
|
605 lf(self) |
|
606 elif self._copyfunc is not _noop: |
|
607 cf, self._copyfunc = self._copyfunc, _noop |
|
608 cf(self) |
|
609 |
601 def setflag(self, f, flags): |
610 def setflag(self, f, flags): |
602 """Set the flags (symlink, executable) for path f.""" |
611 """Set the flags (symlink, executable) for path f.""" |
603 assert 'd' not in flags |
612 assert 'd' not in flags |
604 self._load() |
613 self._load() |
605 dir, subpath = _splittopdir(f) |
614 dir, subpath = _splittopdir(f) |
613 |
622 |
614 def copy(self): |
623 def copy(self): |
615 copy = treemanifest(self._dir) |
624 copy = treemanifest(self._dir) |
616 copy._node = self._node |
625 copy._node = self._node |
617 copy._dirty = self._dirty |
626 copy._dirty = self._dirty |
618 def _load_for_copy(): |
627 if self._copyfunc is _noop: |
619 self._load() |
628 def _copyfunc(s): |
620 for d in self._dirs: |
629 self._load() |
621 copy._dirs[d] = self._dirs[d].copy() |
630 for d in self._dirs: |
622 copy._files = dict.copy(self._files) |
631 s._dirs[d] = self._dirs[d].copy() |
623 copy._flags = dict.copy(self._flags) |
632 s._files = dict.copy(self._files) |
624 copy._load = _noop |
633 s._flags = dict.copy(self._flags) |
625 copy._load = _load_for_copy |
634 if self._loadfunc is _noop: |
626 if self._load == _noop: |
635 _copyfunc(copy) |
627 # Chaining _load if it's _noop is functionally correct, but the |
636 else: |
628 # chain may end up excessively long (stack overflow), and |
637 copy._copyfunc = _copyfunc |
629 # will prevent garbage collection of 'self'. |
638 else: |
630 copy._load() |
639 copy._copyfunc = self._copyfunc |
631 return copy |
640 return copy |
632 |
641 |
633 def filesnotin(self, m2): |
642 def filesnotin(self, m2): |
634 '''Set of files in this manifest that are not in the other''' |
643 '''Set of files in this manifest that are not in the other''' |
635 files = set() |
644 files = set() |
832 dirs = [(d[:-1], self._dirs[d]._node, 'd') for d in self._dirs] |
841 dirs = [(d[:-1], self._dirs[d]._node, 'd') for d in self._dirs] |
833 files = [(f, self._files[f], flags(f)) for f in self._files] |
842 files = [(f, self._files[f], flags(f)) for f in self._files] |
834 return _text(sorted(dirs + files), usemanifestv2) |
843 return _text(sorted(dirs + files), usemanifestv2) |
835 |
844 |
836 def read(self, gettext, readsubtree): |
845 def read(self, gettext, readsubtree): |
837 def _load_for_read(): |
846 def _load_for_read(s): |
838 # Mark as loaded already here, so __setitem__ and setflag() don't |
847 s.parse(gettext(), readsubtree) |
839 # cause infinite loops when they try to load. |
848 s._dirty = False |
840 self._load = _noop |
849 self._loadfunc = _load_for_read |
841 self.parse(gettext(), readsubtree) |
|
842 self._dirty = False |
|
843 self._load = _load_for_read |
|
844 |
850 |
845 def writesubtrees(self, m1, m2, writesubtree): |
851 def writesubtrees(self, m1, m2, writesubtree): |
846 self._load() # for consistency; should never have any effect here |
852 self._load() # for consistency; should never have any effect here |
847 emptytree = treemanifest() |
853 emptytree = treemanifest() |
848 for d, subm in self._dirs.iteritems(): |
854 for d, subm in self._dirs.iteritems(): |