7 |
7 |
8 from i18n import _ |
8 from i18n import _ |
9 import mdiff, parsers, error, revlog, util |
9 import mdiff, parsers, error, revlog, util |
10 import array, struct |
10 import array, struct |
11 import os |
11 import os |
|
12 import heapq |
12 |
13 |
13 propertycache = util.propertycache |
14 propertycache = util.propertycache |
14 |
15 |
15 def _parsev1(data): |
16 def _parsev1(data): |
16 # This method does a little bit of excessive-looking |
17 # This method does a little bit of excessive-looking |
439 dir, subpath = f.split('/', 1) |
440 dir, subpath = f.split('/', 1) |
440 return dir + '/', subpath |
441 return dir + '/', subpath |
441 else: |
442 else: |
442 return '', f |
443 return '', f |
443 |
444 |
444 _noop = lambda: None |
445 _noop = lambda s: None |
445 |
446 |
446 class treemanifest(object): |
447 class treemanifest(object): |
447 def __init__(self, dir='', text=''): |
448 def __init__(self, dir='', text=''): |
448 self._dir = dir |
449 self._dir = dir |
449 self._node = revlog.nullid |
450 self._node = revlog.nullid |
450 self._load = _noop |
451 self._loadfunc = _noop |
|
452 self._copyfunc = _noop |
451 self._dirty = False |
453 self._dirty = False |
452 self._dirs = {} |
454 self._dirs = {} |
453 # Using _lazymanifest here is a little slower than plain old dicts |
455 # Using _lazymanifest here is a little slower than plain old dicts |
454 self._files = {} |
456 self._files = {} |
455 self._flags = {} |
457 self._flags = {} |
473 def _isempty(self): |
475 def _isempty(self): |
474 self._load() # for consistency; already loaded by all callers |
476 self._load() # for consistency; already loaded by all callers |
475 return (not self._files and (not self._dirs or |
477 return (not self._files and (not self._dirs or |
476 all(m._isempty() for m in self._dirs.values()))) |
478 all(m._isempty() for m in self._dirs.values()))) |
477 |
479 |
478 def __str__(self): |
480 def __repr__(self): |
479 return ('<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s>' % |
481 return ('<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s at 0x%x>' % |
480 (self._dir, revlog.hex(self._node), |
482 (self._dir, revlog.hex(self._node), |
481 bool(self._load is _noop), |
483 bool(self._loadfunc is _noop), |
482 self._dirty)) |
484 self._dirty, id(self))) |
483 |
485 |
484 def dir(self): |
486 def dir(self): |
485 '''The directory that this tree manifest represents, including a |
487 '''The directory that this tree manifest represents, including a |
486 trailing '/'. Empty string for the repo root directory.''' |
488 trailing '/'. Empty string for the repo root directory.''' |
487 return self._dir |
489 return self._dir |
595 self._dirs[dir].__setitem__(subpath, n) |
597 self._dirs[dir].__setitem__(subpath, n) |
596 else: |
598 else: |
597 self._files[f] = n[:21] # to match manifestdict's behavior |
599 self._files[f] = n[:21] # to match manifestdict's behavior |
598 self._dirty = True |
600 self._dirty = True |
599 |
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 |
600 def setflag(self, f, flags): |
610 def setflag(self, f, flags): |
601 """Set the flags (symlink, executable) for path f.""" |
611 """Set the flags (symlink, executable) for path f.""" |
602 assert 'd' not in flags |
612 assert 'd' not in flags |
603 self._load() |
613 self._load() |
604 dir, subpath = _splittopdir(f) |
614 dir, subpath = _splittopdir(f) |
612 |
622 |
613 def copy(self): |
623 def copy(self): |
614 copy = treemanifest(self._dir) |
624 copy = treemanifest(self._dir) |
615 copy._node = self._node |
625 copy._node = self._node |
616 copy._dirty = self._dirty |
626 copy._dirty = self._dirty |
617 def _load(): |
627 if self._copyfunc is _noop: |
618 self._load() |
628 def _copyfunc(s): |
619 for d in self._dirs: |
629 self._load() |
620 copy._dirs[d] = self._dirs[d].copy() |
630 for d in self._dirs: |
621 copy._files = dict.copy(self._files) |
631 s._dirs[d] = self._dirs[d].copy() |
622 copy._flags = dict.copy(self._flags) |
632 s._files = dict.copy(self._files) |
623 copy._load = _noop |
633 s._flags = dict.copy(self._flags) |
624 copy._load = _load |
634 if self._loadfunc is _noop: |
625 if self._load == _noop: |
635 _copyfunc(copy) |
626 # Chaining _load if it's _noop is functionally correct, but the |
636 else: |
627 # chain may end up excessively long (stack overflow), and |
637 copy._copyfunc = _copyfunc |
628 # will prevent garbage collection of 'self'. |
638 else: |
629 copy._load() |
639 copy._copyfunc = self._copyfunc |
630 return copy |
640 return copy |
631 |
641 |
632 def filesnotin(self, m2): |
642 def filesnotin(self, m2): |
633 '''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''' |
634 files = set() |
644 files = set() |
831 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] |
832 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] |
833 return _text(sorted(dirs + files), usemanifestv2) |
843 return _text(sorted(dirs + files), usemanifestv2) |
834 |
844 |
835 def read(self, gettext, readsubtree): |
845 def read(self, gettext, readsubtree): |
836 def _load(): |
846 def _load_for_read(s): |
837 # Mark as loaded already here, so __setitem__ and setflag() don't |
847 s.parse(gettext(), readsubtree) |
838 # cause infinite loops when they try to load. |
848 s._dirty = False |
839 self._load = _noop |
849 self._loadfunc = _load_for_read |
840 self.parse(gettext(), readsubtree) |
|
841 self._dirty = False |
|
842 self._load = _load |
|
843 |
850 |
844 def writesubtrees(self, m1, m2, writesubtree): |
851 def writesubtrees(self, m1, m2, writesubtree): |
845 self._load() # for consistency; should never have any effect here |
852 self._load() # for consistency; should never have any effect here |
846 emptytree = treemanifest() |
853 emptytree = treemanifest() |
847 for d, subm in self._dirs.iteritems(): |
854 for d, subm in self._dirs.iteritems(): |
968 # compute a delta here using properties we know about the |
975 # compute a delta here using properties we know about the |
969 # manifest up-front, which may save time later for the |
976 # manifest up-front, which may save time later for the |
970 # revlog layer. |
977 # revlog layer. |
971 |
978 |
972 _checkforbidden(added) |
979 _checkforbidden(added) |
973 # combine the changed lists into one list for sorting |
980 # combine the changed lists into one sorted iterator |
974 work = [(x, False) for x in added] |
981 work = heapq.merge([(x, False) for x in added], |
975 work.extend((x, True) for x in removed) |
982 [(x, True) for x in removed]) |
976 # this could use heapq.merge() (from Python 2.6+) or equivalent |
|
977 # since the lists are already sorted |
|
978 work.sort() |
|
979 |
983 |
980 arraytext, deltatext = m.fastdelta(self._mancache[p1][1], work) |
984 arraytext, deltatext = m.fastdelta(self._mancache[p1][1], work) |
981 cachedelta = self.rev(p1), deltatext |
985 cachedelta = self.rev(p1), deltatext |
982 text = util.buffer(arraytext) |
986 text = util.buffer(arraytext) |
983 n = self.addrevision(text, transaction, link, p1, p2, cachedelta) |
987 n = self.addrevision(text, transaction, link, p1, p2, cachedelta) |