comparison mercurial/manifest.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents 2c4f656c8e9f
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
36 propertycache = util.propertycache 36 propertycache = util.propertycache
37 37
38 # Allow tests to more easily test the alternate path in manifestdict.fastdelta() 38 # Allow tests to more easily test the alternate path in manifestdict.fastdelta()
39 FASTDELTA_TEXTDIFF_THRESHOLD = 1000 39 FASTDELTA_TEXTDIFF_THRESHOLD = 1000
40 40
41
41 def _parse(data): 42 def _parse(data):
42 # This method does a little bit of excessive-looking 43 # This method does a little bit of excessive-looking
43 # precondition checking. This is so that the behavior of this 44 # precondition checking. This is so that the behavior of this
44 # class exactly matches its C counterpart to try and help 45 # class exactly matches its C counterpart to try and help
45 # prevent surprise breakage for anyone that develops against 46 # prevent surprise breakage for anyone that develops against
55 if len(n) > 40: 56 if len(n) > 40:
56 yield f, bin(n[:40]), n[40:] 57 yield f, bin(n[:40]), n[40:]
57 else: 58 else:
58 yield f, bin(n), '' 59 yield f, bin(n), ''
59 60
61
60 def _text(it): 62 def _text(it):
61 files = [] 63 files = []
62 lines = [] 64 lines = []
63 for f, n, fl in it: 65 for f, n, fl in it:
64 files.append(f) 66 files.append(f)
66 # be sure to check the templates/ dir again (especially *-raw.tmpl) 68 # be sure to check the templates/ dir again (especially *-raw.tmpl)
67 lines.append("%s\0%s%s\n" % (f, hex(n), fl)) 69 lines.append("%s\0%s%s\n" % (f, hex(n), fl))
68 70
69 _checkforbidden(files) 71 _checkforbidden(files)
70 return ''.join(lines) 72 return ''.join(lines)
73
71 74
72 class lazymanifestiter(object): 75 class lazymanifestiter(object):
73 def __init__(self, lm): 76 def __init__(self, lm):
74 self.pos = 0 77 self.pos = 0
75 self.lm = lm 78 self.lm = lm
89 zeropos = data.find('\x00', pos) 92 zeropos = data.find('\x00', pos)
90 return data[pos:zeropos] 93 return data[pos:zeropos]
91 94
92 __next__ = next 95 __next__ = next
93 96
97
94 class lazymanifestiterentries(object): 98 class lazymanifestiterentries(object):
95 def __init__(self, lm): 99 def __init__(self, lm):
96 self.lm = lm 100 self.lm = lm
97 self.pos = 0 101 self.pos = 0
98 102
106 raise StopIteration 110 raise StopIteration
107 if pos == -1: 111 if pos == -1:
108 self.pos += 1 112 self.pos += 1
109 return data 113 return data
110 zeropos = data.find('\x00', pos) 114 zeropos = data.find('\x00', pos)
111 hashval = unhexlify(data, self.lm.extrainfo[self.pos], 115 hashval = unhexlify(data, self.lm.extrainfo[self.pos], zeropos + 1, 40)
112 zeropos + 1, 40)
113 flags = self.lm._getflags(data, self.pos, zeropos) 116 flags = self.lm._getflags(data, self.pos, zeropos)
114 self.pos += 1 117 self.pos += 1
115 return (data[pos:zeropos], hashval, flags) 118 return (data[pos:zeropos], hashval, flags)
116 119
117 __next__ = next 120 __next__ = next
118 121
122
119 def unhexlify(data, extra, pos, length): 123 def unhexlify(data, extra, pos, length):
120 s = bin(data[pos:pos + length]) 124 s = bin(data[pos : pos + length])
121 if extra: 125 if extra:
122 s += chr(extra & 0xff) 126 s += chr(extra & 0xFF)
123 return s 127 return s
128
124 129
125 def _cmp(a, b): 130 def _cmp(a, b):
126 return (a > b) - (a < b) 131 return (a > b) - (a < b)
132
127 133
128 class _lazymanifest(object): 134 class _lazymanifest(object):
129 """A pure python manifest backed by a byte string. It is supplimented with 135 """A pure python manifest backed by a byte string. It is supplimented with
130 internal lists as it is modified, until it is compacted back to a pure byte 136 internal lists as it is modified, until it is compacted back to a pure byte
131 string. 137 string.
140 sorted by filename. 146 sorted by filename.
141 147
142 ``extradata`` is a list of (key, hash, flags) for entries that were added or 148 ``extradata`` is a list of (key, hash, flags) for entries that were added or
143 modified since the manifest was created or compacted. 149 modified since the manifest was created or compacted.
144 """ 150 """
145 def __init__(self, data, positions=None, extrainfo=None, extradata=None, 151
146 hasremovals=False): 152 def __init__(
153 self,
154 data,
155 positions=None,
156 extrainfo=None,
157 extradata=None,
158 hasremovals=False,
159 ):
147 if positions is None: 160 if positions is None:
148 self.positions = self.findlines(data) 161 self.positions = self.findlines(data)
149 self.extrainfo = [0] * len(self.positions) 162 self.extrainfo = [0] * len(self.positions)
150 self.data = data 163 self.data = data
151 self.extradata = [] 164 self.extradata = []
162 return [] 175 return []
163 pos = data.find("\n") 176 pos = data.find("\n")
164 if pos == -1 or data[-1:] != '\n': 177 if pos == -1 or data[-1:] != '\n':
165 raise ValueError("Manifest did not end in a newline.") 178 raise ValueError("Manifest did not end in a newline.")
166 positions = [0] 179 positions = [0]
167 prev = data[:data.find('\x00')] 180 prev = data[: data.find('\x00')]
168 while pos < len(data) - 1 and pos != -1: 181 while pos < len(data) - 1 and pos != -1:
169 positions.append(pos + 1) 182 positions.append(pos + 1)
170 nexts = data[pos + 1:data.find('\x00', pos + 1)] 183 nexts = data[pos + 1 : data.find('\x00', pos + 1)]
171 if nexts < prev: 184 if nexts < prev:
172 raise ValueError("Manifest lines not in sorted order.") 185 raise ValueError("Manifest lines not in sorted order.")
173 prev = nexts 186 prev = nexts
174 pos = data.find("\n", pos + 1) 187 pos = data.find("\n", pos + 1)
175 return positions 188 return positions
183 return self.data, pos 196 return self.data, pos
184 return self.extradata[-pos - 1], -1 197 return self.extradata[-pos - 1], -1
185 198
186 def _getkey(self, pos): 199 def _getkey(self, pos):
187 if pos >= 0: 200 if pos >= 0:
188 return self.data[pos:self.data.find('\x00', pos + 1)] 201 return self.data[pos : self.data.find('\x00', pos + 1)]
189 return self.extradata[-pos - 1][0] 202 return self.extradata[-pos - 1][0]
190 203
191 def bsearch(self, key): 204 def bsearch(self, key):
192 first = 0 205 first = 0
193 last = len(self.positions) - 1 206 last = len(self.positions) - 1
194 207
195 while first <= last: 208 while first <= last:
196 midpoint = (first + last)//2 209 midpoint = (first + last) // 2
197 nextpos = self.positions[midpoint] 210 nextpos = self.positions[midpoint]
198 candidate = self._getkey(nextpos) 211 candidate = self._getkey(nextpos)
199 r = _cmp(key, candidate) 212 r = _cmp(key, candidate)
200 if r == 0: 213 if r == 0:
201 return midpoint 214 return midpoint
211 # done for performance reasons 224 # done for performance reasons
212 first = 0 225 first = 0
213 last = len(self.positions) - 1 226 last = len(self.positions) - 1
214 227
215 while first <= last: 228 while first <= last:
216 midpoint = (first + last)//2 229 midpoint = (first + last) // 2
217 nextpos = self.positions[midpoint] 230 nextpos = self.positions[midpoint]
218 candidate = self._getkey(nextpos) 231 candidate = self._getkey(nextpos)
219 r = _cmp(key, candidate) 232 r = _cmp(key, candidate)
220 if r == 0: 233 if r == 0:
221 return (midpoint, True) 234 return (midpoint, True)
257 def __delitem__(self, key): 270 def __delitem__(self, key):
258 needle, found = self.bsearch2(key) 271 needle, found = self.bsearch2(key)
259 if not found: 272 if not found:
260 raise KeyError 273 raise KeyError
261 cur = self.positions[needle] 274 cur = self.positions[needle]
262 self.positions = self.positions[:needle] + self.positions[needle + 1:] 275 self.positions = self.positions[:needle] + self.positions[needle + 1 :]
263 self.extrainfo = self.extrainfo[:needle] + self.extrainfo[needle + 1:] 276 self.extrainfo = self.extrainfo[:needle] + self.extrainfo[needle + 1 :]
264 if cur >= 0: 277 if cur >= 0:
265 # This does NOT unsort the list as far as the search functions are 278 # This does NOT unsort the list as far as the search functions are
266 # concerned, as they only examine lines mapped by self.positions. 279 # concerned, as they only examine lines mapped by self.positions.
267 self.data = self.data[:cur] + '\x00' + self.data[cur + 1:] 280 self.data = self.data[:cur] + '\x00' + self.data[cur + 1 :]
268 self.hasremovals = True 281 self.hasremovals = True
269 282
270 def __setitem__(self, key, value): 283 def __setitem__(self, key, value):
271 if not isinstance(key, bytes): 284 if not isinstance(key, bytes):
272 raise TypeError("setitem: manifest keys must be a byte string.") 285 raise TypeError("setitem: manifest keys must be a byte string.")
291 self.extradata.append((key, hashval, value[1])) 304 self.extradata.append((key, hashval, value[1]))
292 self.positions[needle] = -len(self.extradata) 305 self.positions[needle] = -len(self.extradata)
293 else: 306 else:
294 # not found, put it in with extra positions 307 # not found, put it in with extra positions
295 self.extradata.append((key, hashval, value[1])) 308 self.extradata.append((key, hashval, value[1]))
296 self.positions = (self.positions[:needle] + [-len(self.extradata)] 309 self.positions = (
297 + self.positions[needle:]) 310 self.positions[:needle]
298 self.extrainfo = (self.extrainfo[:needle] + [0] + 311 + [-len(self.extradata)]
299 self.extrainfo[needle:]) 312 + self.positions[needle:]
313 )
314 self.extrainfo = (
315 self.extrainfo[:needle] + [0] + self.extrainfo[needle:]
316 )
300 317
301 def copy(self): 318 def copy(self):
302 # XXX call _compact like in C? 319 # XXX call _compact like in C?
303 return _lazymanifest(self.data, self.positions, self.extrainfo, 320 return _lazymanifest(
304 self.extradata, self.hasremovals) 321 self.data,
322 self.positions,
323 self.extrainfo,
324 self.extradata,
325 self.hasremovals,
326 )
305 327
306 def _compact(self): 328 def _compact(self):
307 # hopefully not called TOO often 329 # hopefully not called TOO often
308 if len(self.extradata) == 0 and not self.hasremovals: 330 if len(self.extradata) == 0 and not self.hasremovals:
309 return 331 return
327 349
328 # A removed file has no positions[] entry, but does have an 350 # A removed file has no positions[] entry, but does have an
329 # overwritten first byte. Break out and find the end of the 351 # overwritten first byte. Break out and find the end of the
330 # current good entry/entries if there is a removed file 352 # current good entry/entries if there is a removed file
331 # before the next position. 353 # before the next position.
332 if (self.hasremovals 354 if (
333 and self.data.find('\n\x00', cur, 355 self.hasremovals
334 self.positions[i]) != -1): 356 and self.data.find('\n\x00', cur, self.positions[i])
357 != -1
358 ):
335 break 359 break
336 360
337 offset += self.positions[i] - cur 361 offset += self.positions[i] - cur
338 cur = self.positions[i] 362 cur = self.positions[i]
339 end_cut = self.data.find('\n', cur) 363 end_cut = self.data.find('\n', cur)
401 for f, n, fl in self.iterentries(): 425 for f, n, fl in self.iterentries():
402 if filterfn(f): 426 if filterfn(f):
403 c[f] = n, fl 427 c[f] = n, fl
404 return c 428 return c
405 429
430
406 try: 431 try:
407 _lazymanifest = parsers.lazymanifest 432 _lazymanifest = parsers.lazymanifest
408 except AttributeError: 433 except AttributeError:
409 pass 434 pass
435
410 436
411 @interfaceutil.implementer(repository.imanifestdict) 437 @interfaceutil.implementer(repository.imanifestdict)
412 class manifestdict(object): 438 class manifestdict(object):
413 def __init__(self, data=''): 439 def __init__(self, data=''):
414 self._lm = _lazymanifest(data) 440 self._lm = _lazymanifest(data)
454 if match: 480 if match:
455 m1 = self.matches(match) 481 m1 = self.matches(match)
456 m2 = m2.matches(match) 482 m2 = m2.matches(match)
457 return m1.filesnotin(m2) 483 return m1.filesnotin(m2)
458 diff = self.diff(m2) 484 diff = self.diff(m2)
459 files = set(filepath 485 files = set(
460 for filepath, hashflags in diff.iteritems() 486 filepath
461 if hashflags[1][0] is None) 487 for filepath, hashflags in diff.iteritems()
488 if hashflags[1][0] is None
489 )
462 return files 490 return files
463 491
464 @propertycache 492 @propertycache
465 def _dirs(self): 493 def _dirs(self):
466 return util.dirs(self) 494 return util.dirs(self)
473 501
474 def _filesfastpath(self, match): 502 def _filesfastpath(self, match):
475 '''Checks whether we can correctly and quickly iterate over matcher 503 '''Checks whether we can correctly and quickly iterate over matcher
476 files instead of over manifest files.''' 504 files instead of over manifest files.'''
477 files = match.files() 505 files = match.files()
478 return (len(files) < 100 and (match.isexact() or 506 return len(files) < 100 and (
479 (match.prefix() and all(fn in self for fn in files)))) 507 match.isexact()
508 or (match.prefix() and all(fn in self for fn in files))
509 )
480 510
481 def walk(self, match): 511 def walk(self, match):
482 '''Generates matching file names. 512 '''Generates matching file names.
483 513
484 Equivalent to manifest.matches(match).iterkeys(), but without creating 514 Equivalent to manifest.matches(match).iterkeys(), but without creating
609 l = "%s\0%s%s\n" % (f, hex(h), fl) 639 l = "%s\0%s%s\n" % (f, hex(h), fl)
610 else: 640 else:
611 if start == end: 641 if start == end:
612 # item we want to delete was not found, error out 642 # item we want to delete was not found, error out
613 raise AssertionError( 643 raise AssertionError(
614 _("failed to remove %s from manifest") % f) 644 _("failed to remove %s from manifest") % f
645 )
615 l = "" 646 l = ""
616 if dstart is not None and dstart <= start and dend >= start: 647 if dstart is not None and dstart <= start and dend >= start:
617 if dend < end: 648 if dend < end:
618 dend = end 649 dend = end
619 if l: 650 if l:
632 else: 663 else:
633 # For large changes, it's much cheaper to just build the text and 664 # For large changes, it's much cheaper to just build the text and
634 # diff it. 665 # diff it.
635 arraytext = bytearray(self.text()) 666 arraytext = bytearray(self.text())
636 deltatext = mdiff.textdiff( 667 deltatext = mdiff.textdiff(
637 util.buffer(base), util.buffer(arraytext)) 668 util.buffer(base), util.buffer(arraytext)
669 )
638 670
639 return arraytext, deltatext 671 return arraytext, deltatext
672
640 673
641 def _msearch(m, s, lo=0, hi=None): 674 def _msearch(m, s, lo=0, hi=None):
642 '''return a tuple (start, end) that says where to find s within m. 675 '''return a tuple (start, end) that says where to find s within m.
643 676
644 If the string is found m[start:end] are the line containing 677 If the string is found m[start:end] are the line containing
645 that string. If start == end the string was not found and 678 that string. If start == end the string was not found and
646 they indicate the proper sorted insertion point. 679 they indicate the proper sorted insertion point.
647 680
648 m should be a buffer, a memoryview or a byte string. 681 m should be a buffer, a memoryview or a byte string.
649 s is a byte string''' 682 s is a byte string'''
683
650 def advance(i, c): 684 def advance(i, c):
651 while i < lenm and m[i:i + 1] != c: 685 while i < lenm and m[i : i + 1] != c:
652 i += 1 686 i += 1
653 return i 687 return i
688
654 if not s: 689 if not s:
655 return (lo, lo) 690 return (lo, lo)
656 lenm = len(m) 691 lenm = len(m)
657 if not hi: 692 if not hi:
658 hi = lenm 693 hi = lenm
659 while lo < hi: 694 while lo < hi:
660 mid = (lo + hi) // 2 695 mid = (lo + hi) // 2
661 start = mid 696 start = mid
662 while start > 0 and m[start - 1:start] != '\n': 697 while start > 0 and m[start - 1 : start] != '\n':
663 start -= 1 698 start -= 1
664 end = advance(start, '\0') 699 end = advance(start, '\0')
665 if bytes(m[start:end]) < s: 700 if bytes(m[start:end]) < s:
666 # we know that after the null there are 40 bytes of sha1 701 # we know that after the null there are 40 bytes of sha1
667 # this translates to the bisect lo = mid + 1 702 # this translates to the bisect lo = mid + 1
676 end = advance(end + 40, '\n') 711 end = advance(end + 40, '\n')
677 return (lo, end + 1) 712 return (lo, end + 1)
678 else: 713 else:
679 return (lo, lo) 714 return (lo, lo)
680 715
716
681 def _checkforbidden(l): 717 def _checkforbidden(l):
682 """Check filenames for illegal characters.""" 718 """Check filenames for illegal characters."""
683 for f in l: 719 for f in l:
684 if '\n' in f or '\r' in f: 720 if '\n' in f or '\r' in f:
685 raise error.StorageError( 721 raise error.StorageError(
686 _("'\\n' and '\\r' disallowed in filenames: %r") 722 _("'\\n' and '\\r' disallowed in filenames: %r")
687 % pycompat.bytestr(f)) 723 % pycompat.bytestr(f)
724 )
688 725
689 726
690 # apply the changes collected during the bisect loop to our addlist 727 # apply the changes collected during the bisect loop to our addlist
691 # return a delta suitable for addrevision 728 # return a delta suitable for addrevision
692 def _addlistdelta(addlist, x): 729 def _addlistdelta(addlist, x):
702 739
703 currentposition = end 740 currentposition = end
704 741
705 newaddlist += addlist[currentposition:] 742 newaddlist += addlist[currentposition:]
706 743
707 deltatext = "".join(struct.pack(">lll", start, end, len(content)) 744 deltatext = "".join(
708 + content for start, end, content in x) 745 struct.pack(">lll", start, end, len(content)) + content
746 for start, end, content in x
747 )
709 return deltatext, newaddlist 748 return deltatext, newaddlist
749
710 750
711 def _splittopdir(f): 751 def _splittopdir(f):
712 if '/' in f: 752 if '/' in f:
713 dir, subpath = f.split('/', 1) 753 dir, subpath = f.split('/', 1)
714 return dir + '/', subpath 754 return dir + '/', subpath
715 else: 755 else:
716 return '', f 756 return '', f
717 757
758
718 _noop = lambda s: None 759 _noop = lambda s: None
760
719 761
720 class treemanifest(object): 762 class treemanifest(object):
721 def __init__(self, dir='', text=''): 763 def __init__(self, dir='', text=''):
722 self._dir = dir 764 self._dir = dir
723 self._node = nullid 765 self._node = nullid
728 self._lazydirs = {} 770 self._lazydirs = {}
729 # Using _lazymanifest here is a little slower than plain old dicts 771 # Using _lazymanifest here is a little slower than plain old dicts
730 self._files = {} 772 self._files = {}
731 self._flags = {} 773 self._flags = {}
732 if text: 774 if text:
775
733 def readsubtree(subdir, subm): 776 def readsubtree(subdir, subm):
734 raise AssertionError('treemanifest constructor only accepts ' 777 raise AssertionError(
735 'flat manifests') 778 'treemanifest constructor only accepts ' 'flat manifests'
779 )
780
736 self.parse(text, readsubtree) 781 self.parse(text, readsubtree)
737 self._dirty = True # Mark flat manifest dirty after parsing 782 self._dirty = True # Mark flat manifest dirty after parsing
738 783
739 def _subpath(self, path): 784 def _subpath(self, path):
740 return self._dir + path 785 return self._dir + path
741 786
742 def _loadalllazy(self): 787 def _loadalllazy(self):
805 return not self._isempty() 850 return not self._isempty()
806 851
807 __bool__ = __nonzero__ 852 __bool__ = __nonzero__
808 853
809 def _isempty(self): 854 def _isempty(self):
810 self._load() # for consistency; already loaded by all callers 855 self._load() # for consistency; already loaded by all callers
811 # See if we can skip loading everything. 856 # See if we can skip loading everything.
812 if self._files or (self._dirs and 857 if self._files or (
813 any(not m._isempty() for m in self._dirs.values())): 858 self._dirs and any(not m._isempty() for m in self._dirs.values())
859 ):
814 return False 860 return False
815 self._loadalllazy() 861 self._loadalllazy()
816 return (not self._dirs or 862 return not self._dirs or all(m._isempty() for m in self._dirs.values())
817 all(m._isempty() for m in self._dirs.values()))
818 863
819 def __repr__(self): 864 def __repr__(self):
820 return ('<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s at 0x%x>' % 865 return '<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s at 0x%x>' % (
821 (self._dir, hex(self._node), 866 self._dir,
822 bool(self._loadfunc is _noop), 867 hex(self._node),
823 self._dirty, id(self))) 868 bool(self._loadfunc is _noop),
869 self._dirty,
870 id(self),
871 )
824 872
825 def dir(self): 873 def dir(self):
826 '''The directory that this tree manifest represents, including a 874 '''The directory that this tree manifest represents, including a
827 trailing '/'. Empty string for the repo root directory.''' 875 trailing '/'. Empty string for the repo root directory.'''
828 return self._dir 876 return self._dir
839 self._dirty = False 887 self._dirty = False
840 888
841 def iterentries(self): 889 def iterentries(self):
842 self._load() 890 self._load()
843 self._loadalllazy() 891 self._loadalllazy()
844 for p, n in sorted(itertools.chain(self._dirs.items(), 892 for p, n in sorted(
845 self._files.items())): 893 itertools.chain(self._dirs.items(), self._files.items())
894 ):
846 if p in self._files: 895 if p in self._files:
847 yield self._subpath(p), n, self._flags.get(p, '') 896 yield self._subpath(p), n, self._flags.get(p, '')
848 else: 897 else:
849 for x in n.iterentries(): 898 for x in n.iterentries():
850 yield x 899 yield x
851 900
852 def items(self): 901 def items(self):
853 self._load() 902 self._load()
854 self._loadalllazy() 903 self._loadalllazy()
855 for p, n in sorted(itertools.chain(self._dirs.items(), 904 for p, n in sorted(
856 self._files.items())): 905 itertools.chain(self._dirs.items(), self._files.items())
906 ):
857 if p in self._files: 907 if p in self._files:
858 yield self._subpath(p), n 908 yield self._subpath(p), n
859 else: 909 else:
860 for f, sn in n.iteritems(): 910 for f, sn in n.iteritems():
861 yield f, sn 911 yield f, sn
963 self._loadlazy(dir) 1013 self._loadlazy(dir)
964 if dir not in self._dirs: 1014 if dir not in self._dirs:
965 self._dirs[dir] = treemanifest(self._subpath(dir)) 1015 self._dirs[dir] = treemanifest(self._subpath(dir))
966 self._dirs[dir].__setitem__(subpath, n) 1016 self._dirs[dir].__setitem__(subpath, n)
967 else: 1017 else:
968 self._files[f] = n[:21] # to match manifestdict's behavior 1018 self._files[f] = n[:21] # to match manifestdict's behavior
969 self._dirty = True 1019 self._dirty = True
970 1020
971 def _load(self): 1021 def _load(self):
972 if self._loadfunc is not _noop: 1022 if self._loadfunc is not _noop:
973 lf, self._loadfunc = self._loadfunc, _noop 1023 lf, self._loadfunc = self._loadfunc, _noop
992 def copy(self): 1042 def copy(self):
993 copy = treemanifest(self._dir) 1043 copy = treemanifest(self._dir)
994 copy._node = self._node 1044 copy._node = self._node
995 copy._dirty = self._dirty 1045 copy._dirty = self._dirty
996 if self._copyfunc is _noop: 1046 if self._copyfunc is _noop:
1047
997 def _copyfunc(s): 1048 def _copyfunc(s):
998 self._load() 1049 self._load()
999 s._lazydirs = {d: (p, n, r, True) for 1050 s._lazydirs = {
1000 d, (p, n, r, c) in self._lazydirs.iteritems()} 1051 d: (p, n, r, True)
1052 for d, (p, n, r, c) in self._lazydirs.iteritems()
1053 }
1001 sdirs = s._dirs 1054 sdirs = s._dirs
1002 for d, v in self._dirs.iteritems(): 1055 for d, v in self._dirs.iteritems():
1003 sdirs[d] = v.copy() 1056 sdirs[d] = v.copy()
1004 s._files = dict.copy(self._files) 1057 s._files = dict.copy(self._files)
1005 s._flags = dict.copy(self._flags) 1058 s._flags = dict.copy(self._flags)
1059
1006 if self._loadfunc is _noop: 1060 if self._loadfunc is _noop:
1007 _copyfunc(copy) 1061 _copyfunc(copy)
1008 else: 1062 else:
1009 copy._copyfunc = _copyfunc 1063 copy._copyfunc = _copyfunc
1010 else: 1064 else:
1017 m1 = self.matches(match) 1071 m1 = self.matches(match)
1018 m2 = m2.matches(match) 1072 m2 = m2.matches(match)
1019 return m1.filesnotin(m2) 1073 return m1.filesnotin(m2)
1020 1074
1021 files = set() 1075 files = set()
1076
1022 def _filesnotin(t1, t2): 1077 def _filesnotin(t1, t2):
1023 if t1._node == t2._node and not t1._dirty and not t2._dirty: 1078 if t1._node == t2._node and not t1._dirty and not t2._dirty:
1024 return 1079 return
1025 t1._load() 1080 t1._load()
1026 t2._load() 1081 t2._load()
1259 1314
1260 def read(self, gettext, readsubtree): 1315 def read(self, gettext, readsubtree):
1261 def _load_for_read(s): 1316 def _load_for_read(s):
1262 s.parse(gettext(), readsubtree) 1317 s.parse(gettext(), readsubtree)
1263 s._dirty = False 1318 s._dirty = False
1319
1264 self._loadfunc = _load_for_read 1320 self._loadfunc = _load_for_read
1265 1321
1266 def writesubtrees(self, m1, m2, writesubtree, match): 1322 def writesubtrees(self, m1, m2, writesubtree, match):
1267 self._load() # for consistency; should never have any effect here 1323 self._load() # for consistency; should never have any effect here
1268 m1._load() 1324 m1._load()
1269 m2._load() 1325 m2._load()
1270 emptytree = treemanifest() 1326 emptytree = treemanifest()
1327
1271 def getnode(m, d): 1328 def getnode(m, d):
1272 ld = m._lazydirs.get(d) 1329 ld = m._lazydirs.get(d)
1273 if ld: 1330 if ld:
1274 return ld[1] 1331 return ld[1]
1275 return m._dirs.get(d, emptytree)._node 1332 return m._dirs.get(d, emptytree)._node
1303 # OPT: use visitchildrenset to avoid loading everything. 1360 # OPT: use visitchildrenset to avoid loading everything.
1304 self._loadalllazy() 1361 self._loadalllazy()
1305 for d, subm in self._dirs.iteritems(): 1362 for d, subm in self._dirs.iteritems():
1306 for subtree in subm.walksubtrees(matcher=matcher): 1363 for subtree in subm.walksubtrees(matcher=matcher):
1307 yield subtree 1364 yield subtree
1365
1308 1366
1309 class manifestfulltextcache(util.lrucachedict): 1367 class manifestfulltextcache(util.lrucachedict):
1310 """File-backed LRU cache for the manifest cache 1368 """File-backed LRU cache for the manifest cache
1311 1369
1312 File consists of entries, up to EOF: 1370 File consists of entries, up to EOF:
1354 1412
1355 def write(self): 1413 def write(self):
1356 if not self._dirty or self._opener is None: 1414 if not self._dirty or self._opener is None:
1357 return 1415 return
1358 # rotate backwards to the first used node 1416 # rotate backwards to the first used node
1359 with self._opener(self._file, 'w', atomictemp=True, checkambig=True 1417 with self._opener(
1360 ) as fp: 1418 self._file, 'w', atomictemp=True, checkambig=True
1419 ) as fp:
1361 node = self._head.prev 1420 node = self._head.prev
1362 while True: 1421 while True:
1363 if node.key in self._cache: 1422 if node.key in self._cache:
1364 fp.write(node.key) 1423 fp.write(node.key)
1365 fp.write(struct.pack('>L', len(node.value))) 1424 fp.write(struct.pack('>L', len(node.value)))
1415 if clear_persisted_data: 1474 if clear_persisted_data:
1416 self._dirty = True 1475 self._dirty = True
1417 self.write() 1476 self.write()
1418 self._read = False 1477 self._read = False
1419 1478
1479
1420 # and upper bound of what we expect from compression 1480 # and upper bound of what we expect from compression
1421 # (real live value seems to be "3") 1481 # (real live value seems to be "3")
1422 MAXCOMPRESSION = 3 1482 MAXCOMPRESSION = 3
1483
1423 1484
1424 @interfaceutil.implementer(repository.imanifeststorage) 1485 @interfaceutil.implementer(repository.imanifeststorage)
1425 class manifestrevlog(object): 1486 class manifestrevlog(object):
1426 '''A revlog that stores manifest texts. This is responsible for caching the 1487 '''A revlog that stores manifest texts. This is responsible for caching the
1427 full-text manifest contents. 1488 full-text manifest contents.
1428 ''' 1489 '''
1429 def __init__(self, opener, tree='', dirlogcache=None, indexfile=None, 1490
1430 treemanifest=False): 1491 def __init__(
1492 self,
1493 opener,
1494 tree='',
1495 dirlogcache=None,
1496 indexfile=None,
1497 treemanifest=False,
1498 ):
1431 """Constructs a new manifest revlog 1499 """Constructs a new manifest revlog
1432 1500
1433 `indexfile` - used by extensions to have two manifests at once, like 1501 `indexfile` - used by extensions to have two manifests at once, like
1434 when transitioning between flatmanifeset and treemanifests. 1502 when transitioning between flatmanifeset and treemanifests.
1435 1503
1466 if tree: 1534 if tree:
1467 self._dirlogcache = dirlogcache 1535 self._dirlogcache = dirlogcache
1468 else: 1536 else:
1469 self._dirlogcache = {'': self} 1537 self._dirlogcache = {'': self}
1470 1538
1471 self._revlog = revlog.revlog(opener, indexfile, 1539 self._revlog = revlog.revlog(
1472 # only root indexfile is cached 1540 opener,
1473 checkambig=not bool(tree), 1541 indexfile,
1474 mmaplargeindex=True, 1542 # only root indexfile is cached
1475 upperboundcomp=MAXCOMPRESSION) 1543 checkambig=not bool(tree),
1544 mmaplargeindex=True,
1545 upperboundcomp=MAXCOMPRESSION,
1546 )
1476 1547
1477 self.index = self._revlog.index 1548 self.index = self._revlog.index
1478 self.version = self._revlog.version 1549 self.version = self._revlog.version
1479 self._generaldelta = self._revlog._generaldelta 1550 self._generaldelta = self._revlog._generaldelta
1480 1551
1513 1584
1514 def dirlog(self, d): 1585 def dirlog(self, d):
1515 if d: 1586 if d:
1516 assert self._treeondisk 1587 assert self._treeondisk
1517 if d not in self._dirlogcache: 1588 if d not in self._dirlogcache:
1518 mfrevlog = manifestrevlog(self.opener, d, 1589 mfrevlog = manifestrevlog(
1519 self._dirlogcache, 1590 self.opener, d, self._dirlogcache, treemanifest=self._treeondisk
1520 treemanifest=self._treeondisk) 1591 )
1521 self._dirlogcache[d] = mfrevlog 1592 self._dirlogcache[d] = mfrevlog
1522 return self._dirlogcache[d] 1593 return self._dirlogcache[d]
1523 1594
1524 def add(self, m, transaction, link, p1, p2, added, removed, readtree=None, 1595 def add(
1525 match=None): 1596 self,
1597 m,
1598 transaction,
1599 link,
1600 p1,
1601 p2,
1602 added,
1603 removed,
1604 readtree=None,
1605 match=None,
1606 ):
1526 if p1 in self.fulltextcache and util.safehasattr(m, 'fastdelta'): 1607 if p1 in self.fulltextcache and util.safehasattr(m, 'fastdelta'):
1527 # If our first parent is in the manifest cache, we can 1608 # If our first parent is in the manifest cache, we can
1528 # compute a delta here using properties we know about the 1609 # compute a delta here using properties we know about the
1529 # manifest up-front, which may save time later for the 1610 # manifest up-front, which may save time later for the
1530 # revlog layer. 1611 # revlog layer.
1531 1612
1532 _checkforbidden(added) 1613 _checkforbidden(added)
1533 # combine the changed lists into one sorted iterator 1614 # combine the changed lists into one sorted iterator
1534 work = heapq.merge([(x, False) for x in sorted(added)], 1615 work = heapq.merge(
1535 [(x, True) for x in sorted(removed)]) 1616 [(x, False) for x in sorted(added)],
1617 [(x, True) for x in sorted(removed)],
1618 )
1536 1619
1537 arraytext, deltatext = m.fastdelta(self.fulltextcache[p1], work) 1620 arraytext, deltatext = m.fastdelta(self.fulltextcache[p1], work)
1538 cachedelta = self._revlog.rev(p1), deltatext 1621 cachedelta = self._revlog.rev(p1), deltatext
1539 text = util.buffer(arraytext) 1622 text = util.buffer(arraytext)
1540 n = self._revlog.addrevision(text, transaction, link, p1, p2, 1623 n = self._revlog.addrevision(
1541 cachedelta) 1624 text, transaction, link, p1, p2, cachedelta
1625 )
1542 else: 1626 else:
1543 # The first parent manifest isn't already loaded, so we'll 1627 # The first parent manifest isn't already loaded, so we'll
1544 # just encode a fulltext of the manifest and pass that 1628 # just encode a fulltext of the manifest and pass that
1545 # through to the revlog layer, and let it handle the delta 1629 # through to the revlog layer, and let it handle the delta
1546 # process. 1630 # process.
1547 if self._treeondisk: 1631 if self._treeondisk:
1548 assert readtree, "readtree must be set for treemanifest writes" 1632 assert readtree, "readtree must be set for treemanifest writes"
1549 assert match, "match must be specified for treemanifest writes" 1633 assert match, "match must be specified for treemanifest writes"
1550 m1 = readtree(self.tree, p1) 1634 m1 = readtree(self.tree, p1)
1551 m2 = readtree(self.tree, p2) 1635 m2 = readtree(self.tree, p2)
1552 n = self._addtree(m, transaction, link, m1, m2, readtree, 1636 n = self._addtree(
1553 match=match) 1637 m, transaction, link, m1, m2, readtree, match=match
1638 )
1554 arraytext = None 1639 arraytext = None
1555 else: 1640 else:
1556 text = m.text() 1641 text = m.text()
1557 n = self._revlog.addrevision(text, transaction, link, p1, p2) 1642 n = self._revlog.addrevision(text, transaction, link, p1, p2)
1558 arraytext = bytearray(text) 1643 arraytext = bytearray(text)
1563 return n 1648 return n
1564 1649
1565 def _addtree(self, m, transaction, link, m1, m2, readtree, match): 1650 def _addtree(self, m, transaction, link, m1, m2, readtree, match):
1566 # If the manifest is unchanged compared to one parent, 1651 # If the manifest is unchanged compared to one parent,
1567 # don't write a new revision 1652 # don't write a new revision
1568 if self.tree != '' and (m.unmodifiedsince(m1) or m.unmodifiedsince( 1653 if self.tree != '' and (m.unmodifiedsince(m1) or m.unmodifiedsince(m2)):
1569 m2)):
1570 return m.node() 1654 return m.node()
1655
1571 def writesubtree(subm, subp1, subp2, match): 1656 def writesubtree(subm, subp1, subp2, match):
1572 sublog = self.dirlog(subm.dir()) 1657 sublog = self.dirlog(subm.dir())
1573 sublog.add(subm, transaction, link, subp1, subp2, None, None, 1658 sublog.add(
1574 readtree=readtree, match=match) 1659 subm,
1660 transaction,
1661 link,
1662 subp1,
1663 subp2,
1664 None,
1665 None,
1666 readtree=readtree,
1667 match=match,
1668 )
1669
1575 m.writesubtrees(m1, m2, writesubtree, match) 1670 m.writesubtrees(m1, m2, writesubtree, match)
1576 text = m.dirtext() 1671 text = m.dirtext()
1577 n = None 1672 n = None
1578 if self.tree != '': 1673 if self.tree != '':
1579 # Double-check whether contents are unchanged to one parent 1674 # Double-check whether contents are unchanged to one parent
1581 n = m1.node() 1676 n = m1.node()
1582 elif text == m2.dirtext(): 1677 elif text == m2.dirtext():
1583 n = m2.node() 1678 n = m2.node()
1584 1679
1585 if not n: 1680 if not n:
1586 n = self._revlog.addrevision(text, transaction, link, m1.node(), 1681 n = self._revlog.addrevision(
1587 m2.node()) 1682 text, transaction, link, m1.node(), m2.node()
1683 )
1588 1684
1589 # Save nodeid so parent manifest can calculate its nodeid 1685 # Save nodeid so parent manifest can calculate its nodeid
1590 m.setnode(n) 1686 m.setnode(n)
1591 return n 1687 return n
1592 1688
1630 return self._revlog.cmp(node, text) 1726 return self._revlog.cmp(node, text)
1631 1727
1632 def deltaparent(self, rev): 1728 def deltaparent(self, rev):
1633 return self._revlog.deltaparent(rev) 1729 return self._revlog.deltaparent(rev)
1634 1730
1635 def emitrevisions(self, nodes, nodesorder=None, 1731 def emitrevisions(
1636 revisiondata=False, assumehaveparentrevisions=False, 1732 self,
1637 deltamode=repository.CG_DELTAMODE_STD): 1733 nodes,
1734 nodesorder=None,
1735 revisiondata=False,
1736 assumehaveparentrevisions=False,
1737 deltamode=repository.CG_DELTAMODE_STD,
1738 ):
1638 return self._revlog.emitrevisions( 1739 return self._revlog.emitrevisions(
1639 nodes, nodesorder=nodesorder, revisiondata=revisiondata, 1740 nodes,
1741 nodesorder=nodesorder,
1742 revisiondata=revisiondata,
1640 assumehaveparentrevisions=assumehaveparentrevisions, 1743 assumehaveparentrevisions=assumehaveparentrevisions,
1641 deltamode=deltamode) 1744 deltamode=deltamode,
1745 )
1642 1746
1643 def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None): 1747 def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None):
1644 return self._revlog.addgroup(deltas, linkmapper, transaction, 1748 return self._revlog.addgroup(
1645 addrevisioncb=addrevisioncb) 1749 deltas, linkmapper, transaction, addrevisioncb=addrevisioncb
1750 )
1646 1751
1647 def rawsize(self, rev): 1752 def rawsize(self, rev):
1648 return self._revlog.rawsize(rev) 1753 return self._revlog.rawsize(rev)
1649 1754
1650 def getstrippoint(self, minlink): 1755 def getstrippoint(self, minlink):
1660 if not isinstance(destrevlog, manifestrevlog): 1765 if not isinstance(destrevlog, manifestrevlog):
1661 raise error.ProgrammingError('expected manifestrevlog to clone()') 1766 raise error.ProgrammingError('expected manifestrevlog to clone()')
1662 1767
1663 return self._revlog.clone(tr, destrevlog._revlog, **kwargs) 1768 return self._revlog.clone(tr, destrevlog._revlog, **kwargs)
1664 1769
1665 def storageinfo(self, exclusivefiles=False, sharedfiles=False, 1770 def storageinfo(
1666 revisionscount=False, trackedsize=False, 1771 self,
1667 storedsize=False): 1772 exclusivefiles=False,
1773 sharedfiles=False,
1774 revisionscount=False,
1775 trackedsize=False,
1776 storedsize=False,
1777 ):
1668 return self._revlog.storageinfo( 1778 return self._revlog.storageinfo(
1669 exclusivefiles=exclusivefiles, sharedfiles=sharedfiles, 1779 exclusivefiles=exclusivefiles,
1670 revisionscount=revisionscount, trackedsize=trackedsize, 1780 sharedfiles=sharedfiles,
1671 storedsize=storedsize) 1781 revisionscount=revisionscount,
1782 trackedsize=trackedsize,
1783 storedsize=storedsize,
1784 )
1672 1785
1673 @property 1786 @property
1674 def indexfile(self): 1787 def indexfile(self):
1675 return self._revlog.indexfile 1788 return self._revlog.indexfile
1676 1789
1683 return self._revlog.opener 1796 return self._revlog.opener
1684 1797
1685 @opener.setter 1798 @opener.setter
1686 def opener(self, value): 1799 def opener(self, value):
1687 self._revlog.opener = value 1800 self._revlog.opener = value
1801
1688 1802
1689 @interfaceutil.implementer(repository.imanifestlog) 1803 @interfaceutil.implementer(repository.imanifestlog)
1690 class manifestlog(object): 1804 class manifestlog(object):
1691 """A collection class representing the collection of manifest snapshots 1805 """A collection class representing the collection of manifest snapshots
1692 referenced by commits in the repository. 1806 referenced by commits in the repository.
1693 1807
1694 In this situation, 'manifest' refers to the abstract concept of a snapshot 1808 In this situation, 'manifest' refers to the abstract concept of a snapshot
1695 of the list of files in the given commit. Consumers of the output of this 1809 of the list of files in the given commit. Consumers of the output of this
1696 class do not care about the implementation details of the actual manifests 1810 class do not care about the implementation details of the actual manifests
1697 they receive (i.e. tree or flat or lazily loaded, etc).""" 1811 they receive (i.e. tree or flat or lazily loaded, etc)."""
1812
1698 def __init__(self, opener, repo, rootstore, narrowmatch): 1813 def __init__(self, opener, repo, rootstore, narrowmatch):
1699 usetreemanifest = False 1814 usetreemanifest = False
1700 cachesize = 4 1815 cachesize = 4
1701 1816
1702 opts = getattr(opener, 'options', None) 1817 opts = getattr(opener, 'options', None)
1743 self.getstorage(tree).rev(node) 1858 self.getstorage(tree).rev(node)
1744 1859
1745 m = treemanifestctx(self, tree, node) 1860 m = treemanifestctx(self, tree, node)
1746 else: 1861 else:
1747 raise error.Abort( 1862 raise error.Abort(
1748 _("cannot ask for manifest directory '%s' in a flat " 1863 _(
1749 "manifest") % tree) 1864 "cannot ask for manifest directory '%s' in a flat "
1865 "manifest"
1866 )
1867 % tree
1868 )
1750 else: 1869 else:
1751 if verify: 1870 if verify:
1752 # Side-effect is LookupError is raised if node doesn't exist. 1871 # Side-effect is LookupError is raised if node doesn't exist.
1753 self._rootstore.rev(node) 1872 self._rootstore.rev(node)
1754 1873
1773 self._rootstore.clearcaches(clear_persisted_data=clear_persisted_data) 1892 self._rootstore.clearcaches(clear_persisted_data=clear_persisted_data)
1774 1893
1775 def rev(self, node): 1894 def rev(self, node):
1776 return self._rootstore.rev(node) 1895 return self._rootstore.rev(node)
1777 1896
1897
1778 @interfaceutil.implementer(repository.imanifestrevisionwritable) 1898 @interfaceutil.implementer(repository.imanifestrevisionwritable)
1779 class memmanifestctx(object): 1899 class memmanifestctx(object):
1780 def __init__(self, manifestlog): 1900 def __init__(self, manifestlog):
1781 self._manifestlog = manifestlog 1901 self._manifestlog = manifestlog
1782 self._manifestdict = manifestdict() 1902 self._manifestdict = manifestdict()
1794 1914
1795 def read(self): 1915 def read(self):
1796 return self._manifestdict 1916 return self._manifestdict
1797 1917
1798 def write(self, transaction, link, p1, p2, added, removed, match=None): 1918 def write(self, transaction, link, p1, p2, added, removed, match=None):
1799 return self._storage().add(self._manifestdict, transaction, link, 1919 return self._storage().add(
1800 p1, p2, added, removed, match=match) 1920 self._manifestdict,
1921 transaction,
1922 link,
1923 p1,
1924 p2,
1925 added,
1926 removed,
1927 match=match,
1928 )
1929
1801 1930
1802 @interfaceutil.implementer(repository.imanifestrevisionstored) 1931 @interfaceutil.implementer(repository.imanifestrevisionstored)
1803 class manifestctx(object): 1932 class manifestctx(object):
1804 """A class representing a single revision of a manifest, including its 1933 """A class representing a single revision of a manifest, including its
1805 contents, its parent revs, and its linkrev. 1934 contents, its parent revs, and its linkrev.
1806 """ 1935 """
1936
1807 def __init__(self, manifestlog, node): 1937 def __init__(self, manifestlog, node):
1808 self._manifestlog = manifestlog 1938 self._manifestlog = manifestlog
1809 self._data = None 1939 self._data = None
1810 1940
1811 self._node = node 1941 self._node = node
1812 1942
1813 # TODO: We eventually want p1, p2, and linkrev exposed on this class, 1943 # TODO: We eventually want p1, p2, and linkrev exposed on this class,
1814 # but let's add it later when something needs it and we can load it 1944 # but let's add it later when something needs it and we can load it
1815 # lazily. 1945 # lazily.
1816 #self.p1, self.p2 = store.parents(node) 1946 # self.p1, self.p2 = store.parents(node)
1817 #rev = store.rev(node) 1947 # rev = store.rev(node)
1818 #self.linkrev = store.linkrev(rev) 1948 # self.linkrev = store.linkrev(rev)
1819 1949
1820 def _storage(self): 1950 def _storage(self):
1821 return self._manifestlog.getstorage(b'') 1951 return self._manifestlog.getstorage(b'')
1822 1952
1823 def node(self): 1953 def node(self):
1877 return manifestdict(d) 2007 return manifestdict(d)
1878 2008
1879 def find(self, key): 2009 def find(self, key):
1880 return self.read().find(key) 2010 return self.read().find(key)
1881 2011
2012
1882 @interfaceutil.implementer(repository.imanifestrevisionwritable) 2013 @interfaceutil.implementer(repository.imanifestrevisionwritable)
1883 class memtreemanifestctx(object): 2014 class memtreemanifestctx(object):
1884 def __init__(self, manifestlog, dir=''): 2015 def __init__(self, manifestlog, dir=''):
1885 self._manifestlog = manifestlog 2016 self._manifestlog = manifestlog
1886 self._dir = dir 2017 self._dir = dir
1901 return self._treemanifest 2032 return self._treemanifest
1902 2033
1903 def write(self, transaction, link, p1, p2, added, removed, match=None): 2034 def write(self, transaction, link, p1, p2, added, removed, match=None):
1904 def readtree(dir, node): 2035 def readtree(dir, node):
1905 return self._manifestlog.get(dir, node).read() 2036 return self._manifestlog.get(dir, node).read()
1906 return self._storage().add(self._treemanifest, transaction, link, 2037
1907 p1, p2, added, removed, readtree=readtree, 2038 return self._storage().add(
1908 match=match) 2039 self._treemanifest,
2040 transaction,
2041 link,
2042 p1,
2043 p2,
2044 added,
2045 removed,
2046 readtree=readtree,
2047 match=match,
2048 )
2049
1909 2050
1910 @interfaceutil.implementer(repository.imanifestrevisionstored) 2051 @interfaceutil.implementer(repository.imanifestrevisionstored)
1911 class treemanifestctx(object): 2052 class treemanifestctx(object):
1912 def __init__(self, manifestlog, dir, node): 2053 def __init__(self, manifestlog, dir, node):
1913 self._manifestlog = manifestlog 2054 self._manifestlog = manifestlog
1917 self._node = node 2058 self._node = node
1918 2059
1919 # TODO: Load p1/p2/linkrev lazily. They need to be lazily loaded so that 2060 # TODO: Load p1/p2/linkrev lazily. They need to be lazily loaded so that
1920 # we can instantiate treemanifestctx objects for directories we don't 2061 # we can instantiate treemanifestctx objects for directories we don't
1921 # have on disk. 2062 # have on disk.
1922 #self.p1, self.p2 = store.parents(node) 2063 # self.p1, self.p2 = store.parents(node)
1923 #rev = store.rev(node) 2064 # rev = store.rev(node)
1924 #self.linkrev = store.linkrev(rev) 2065 # self.linkrev = store.linkrev(rev)
1925 2066
1926 def _storage(self): 2067 def _storage(self):
1927 narrowmatch = self._manifestlog._narrowmatch 2068 narrowmatch = self._manifestlog._narrowmatch
1928 if not narrowmatch.always(): 2069 if not narrowmatch.always():
1929 if not narrowmatch.visitdir(self._dir[:-1]): 2070 if not narrowmatch.visitdir(self._dir[:-1]):
1936 if self._node == nullid: 2077 if self._node == nullid:
1937 self._data = treemanifest() 2078 self._data = treemanifest()
1938 # TODO accessing non-public API 2079 # TODO accessing non-public API
1939 elif store._treeondisk: 2080 elif store._treeondisk:
1940 m = treemanifest(dir=self._dir) 2081 m = treemanifest(dir=self._dir)
2082
1941 def gettext(): 2083 def gettext():
1942 return store.revision(self._node) 2084 return store.revision(self._node)
2085
1943 def readsubtree(dir, subm): 2086 def readsubtree(dir, subm):
1944 # Set verify to False since we need to be able to create 2087 # Set verify to False since we need to be able to create
1945 # subtrees for trees that don't exist on disk. 2088 # subtrees for trees that don't exist on disk.
1946 return self._manifestlog.get(dir, subm, verify=False).read() 2089 return self._manifestlog.get(dir, subm, verify=False).read()
2090
1947 m.read(gettext, readsubtree) 2091 m.read(gettext, readsubtree)
1948 m.setnode(self._node) 2092 m.setnode(self._node)
1949 self._data = m 2093 self._data = m
1950 else: 2094 else:
1951 if self._node in store.fulltextcache: 2095 if self._node in store.fulltextcache:
2011 and not any submanifests. 2155 and not any submanifests.
2012 ''' 2156 '''
2013 store = self._storage() 2157 store = self._storage()
2014 r = store.rev(self._node) 2158 r = store.rev(self._node)
2015 deltaparent = store.deltaparent(r) 2159 deltaparent = store.deltaparent(r)
2016 if (deltaparent != nullrev and 2160 if deltaparent != nullrev and deltaparent in store.parentrevs(r):
2017 deltaparent in store.parentrevs(r)):
2018 return self.readdelta(shallow=shallow) 2161 return self.readdelta(shallow=shallow)
2019 2162
2020 if shallow: 2163 if shallow:
2021 return manifestdict(store.revision(self._node)) 2164 return manifestdict(store.revision(self._node))
2022 else: 2165 else:
2023 return self.read() 2166 return self.read()
2024 2167
2025 def find(self, key): 2168 def find(self, key):
2026 return self.read().find(key) 2169 return self.read().find(key)
2170
2027 2171
2028 class excludeddir(treemanifest): 2172 class excludeddir(treemanifest):
2029 """Stand-in for a directory that is excluded from the repository. 2173 """Stand-in for a directory that is excluded from the repository.
2030 2174
2031 With narrowing active on a repository that uses treemanifests, 2175 With narrowing active on a repository that uses treemanifests,
2034 some sort of pseudo-manifest to surface to internals so we can 2178 some sort of pseudo-manifest to surface to internals so we can
2035 detect a merge conflict outside the narrowspec. That's what this 2179 detect a merge conflict outside the narrowspec. That's what this
2036 class is: it stands in for a directory whose node is known, but 2180 class is: it stands in for a directory whose node is known, but
2037 whose contents are unknown. 2181 whose contents are unknown.
2038 """ 2182 """
2183
2039 def __init__(self, dir, node): 2184 def __init__(self, dir, node):
2040 super(excludeddir, self).__init__(dir) 2185 super(excludeddir, self).__init__(dir)
2041 self._node = node 2186 self._node = node
2042 # Add an empty file, which will be included by iterators and such, 2187 # Add an empty file, which will be included by iterators and such,
2043 # appearing as the directory itself (i.e. something like "dir/") 2188 # appearing as the directory itself (i.e. something like "dir/")
2050 # be of the same type as the original, which would not happen with the 2195 # be of the same type as the original, which would not happen with the
2051 # super type's copy(). 2196 # super type's copy().
2052 def copy(self): 2197 def copy(self):
2053 return self 2198 return self
2054 2199
2200
2055 class excludeddirmanifestctx(treemanifestctx): 2201 class excludeddirmanifestctx(treemanifestctx):
2056 """context wrapper for excludeddir - see that docstring for rationale""" 2202 """context wrapper for excludeddir - see that docstring for rationale"""
2203
2057 def __init__(self, dir, node): 2204 def __init__(self, dir, node):
2058 self._dir = dir 2205 self._dir = dir
2059 self._node = node 2206 self._node = node
2060 2207
2061 def read(self): 2208 def read(self):
2062 return excludeddir(self._dir, self._node) 2209 return excludeddir(self._dir, self._node)
2063 2210
2064 def write(self, *args): 2211 def write(self, *args):
2065 raise error.ProgrammingError( 2212 raise error.ProgrammingError(
2066 'attempt to write manifest from excluded dir %s' % self._dir) 2213 'attempt to write manifest from excluded dir %s' % self._dir
2214 )
2215
2067 2216
2068 class excludedmanifestrevlog(manifestrevlog): 2217 class excludedmanifestrevlog(manifestrevlog):
2069 """Stand-in for excluded treemanifest revlogs. 2218 """Stand-in for excluded treemanifest revlogs.
2070 2219
2071 When narrowing is active on a treemanifest repository, we'll have 2220 When narrowing is active on a treemanifest repository, we'll have
2078 def __init__(self, dir): 2227 def __init__(self, dir):
2079 self._dir = dir 2228 self._dir = dir
2080 2229
2081 def __len__(self): 2230 def __len__(self):
2082 raise error.ProgrammingError( 2231 raise error.ProgrammingError(
2083 'attempt to get length of excluded dir %s' % self._dir) 2232 'attempt to get length of excluded dir %s' % self._dir
2233 )
2084 2234
2085 def rev(self, node): 2235 def rev(self, node):
2086 raise error.ProgrammingError( 2236 raise error.ProgrammingError(
2087 'attempt to get rev from excluded dir %s' % self._dir) 2237 'attempt to get rev from excluded dir %s' % self._dir
2238 )
2088 2239
2089 def linkrev(self, node): 2240 def linkrev(self, node):
2090 raise error.ProgrammingError( 2241 raise error.ProgrammingError(
2091 'attempt to get linkrev from excluded dir %s' % self._dir) 2242 'attempt to get linkrev from excluded dir %s' % self._dir
2243 )
2092 2244
2093 def node(self, rev): 2245 def node(self, rev):
2094 raise error.ProgrammingError( 2246 raise error.ProgrammingError(
2095 'attempt to get node from excluded dir %s' % self._dir) 2247 'attempt to get node from excluded dir %s' % self._dir
2248 )
2096 2249
2097 def add(self, *args, **kwargs): 2250 def add(self, *args, **kwargs):
2098 # We should never write entries in dirlogs outside the narrow clone. 2251 # We should never write entries in dirlogs outside the narrow clone.
2099 # However, the method still gets called from writesubtree() in 2252 # However, the method still gets called from writesubtree() in
2100 # _addtree(), so we need to handle it. We should possibly make that 2253 # _addtree(), so we need to handle it. We should possibly make that