Mercurial > hg
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 |