Mercurial > hg
comparison hgext/fastannotate/context.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 | 0152a907f714 |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
21 node, | 21 node, |
22 pycompat, | 22 pycompat, |
23 scmutil, | 23 scmutil, |
24 util, | 24 util, |
25 ) | 25 ) |
26 from mercurial.utils import ( | 26 from mercurial.utils import stringutil |
27 stringutil, | |
28 ) | |
29 | 27 |
30 from . import ( | 28 from . import ( |
31 error as faerror, | 29 error as faerror, |
32 revmap as revmapmod, | 30 revmap as revmapmod, |
33 ) | 31 ) |
34 | 32 |
35 # given path, get filelog, cached | 33 # given path, get filelog, cached |
36 @util.lrucachefunc | 34 @util.lrucachefunc |
37 def _getflog(repo, path): | 35 def _getflog(repo, path): |
38 return repo.file(path) | 36 return repo.file(path) |
37 | |
39 | 38 |
40 # extracted from mercurial.context.basefilectx.annotate | 39 # extracted from mercurial.context.basefilectx.annotate |
41 def _parents(f, follow=True): | 40 def _parents(f, follow=True): |
42 # Cut _descendantrev here to mitigate the penalty of lazy linkrev | 41 # Cut _descendantrev here to mitigate the penalty of lazy linkrev |
43 # adjustment. Otherwise, p._adjustlinkrev() would walk changelog | 42 # adjustment. Otherwise, p._adjustlinkrev() would walk changelog |
56 if not '_filelog' in p.__dict__: | 55 if not '_filelog' in p.__dict__: |
57 p._filelog = _getflog(f._repo, p.path()) | 56 p._filelog = _getflog(f._repo, p.path()) |
58 | 57 |
59 return pl | 58 return pl |
60 | 59 |
60 | |
61 # extracted from mercurial.context.basefilectx.annotate. slightly modified | 61 # extracted from mercurial.context.basefilectx.annotate. slightly modified |
62 # so it takes a fctx instead of a pair of text and fctx. | 62 # so it takes a fctx instead of a pair of text and fctx. |
63 def _decorate(fctx): | 63 def _decorate(fctx): |
64 text = fctx.data() | 64 text = fctx.data() |
65 linecount = text.count('\n') | 65 linecount = text.count('\n') |
66 if text and not text.endswith('\n'): | 66 if text and not text.endswith('\n'): |
67 linecount += 1 | 67 linecount += 1 |
68 return ([(fctx, i) for i in pycompat.xrange(linecount)], text) | 68 return ([(fctx, i) for i in pycompat.xrange(linecount)], text) |
69 | |
69 | 70 |
70 # extracted from mercurial.context.basefilectx.annotate. slightly modified | 71 # extracted from mercurial.context.basefilectx.annotate. slightly modified |
71 # so it takes an extra "blocks" parameter calculated elsewhere, instead of | 72 # so it takes an extra "blocks" parameter calculated elsewhere, instead of |
72 # calculating diff here. | 73 # calculating diff here. |
73 def _pair(parent, child, blocks): | 74 def _pair(parent, child, blocks): |
76 # belong to the child. | 77 # belong to the child. |
77 if t == '=': | 78 if t == '=': |
78 child[0][b1:b2] = parent[0][a1:a2] | 79 child[0][b1:b2] = parent[0][a1:a2] |
79 return child | 80 return child |
80 | 81 |
82 | |
81 # like scmutil.revsingle, but with lru cache, so their states (like manifests) | 83 # like scmutil.revsingle, but with lru cache, so their states (like manifests) |
82 # could be reused | 84 # could be reused |
83 _revsingle = util.lrucachefunc(scmutil.revsingle) | 85 _revsingle = util.lrucachefunc(scmutil.revsingle) |
86 | |
84 | 87 |
85 def resolvefctx(repo, rev, path, resolverev=False, adjustctx=None): | 88 def resolvefctx(repo, rev, path, resolverev=False, adjustctx=None): |
86 """(repo, str, str) -> fctx | 89 """(repo, str, str) -> fctx |
87 | 90 |
88 get the filectx object from repo, rev, path, in an efficient way. | 91 get the filectx object from repo, rev, path, in an efficient way. |
123 if introrev != ctx.rev(): | 126 if introrev != ctx.rev(): |
124 fctx._changeid = introrev | 127 fctx._changeid = introrev |
125 fctx._changectx = repo[introrev] | 128 fctx._changectx = repo[introrev] |
126 return fctx | 129 return fctx |
127 | 130 |
131 | |
128 # like mercurial.store.encodedir, but use linelog suffixes: .m, .l, .lock | 132 # like mercurial.store.encodedir, but use linelog suffixes: .m, .l, .lock |
129 def encodedir(path): | 133 def encodedir(path): |
130 return (path | 134 return ( |
131 .replace('.hg/', '.hg.hg/') | 135 path.replace('.hg/', '.hg.hg/') |
132 .replace('.l/', '.l.hg/') | 136 .replace('.l/', '.l.hg/') |
133 .replace('.m/', '.m.hg/') | 137 .replace('.m/', '.m.hg/') |
134 .replace('.lock/', '.lock.hg/')) | 138 .replace('.lock/', '.lock.hg/') |
139 ) | |
140 | |
135 | 141 |
136 def hashdiffopts(diffopts): | 142 def hashdiffopts(diffopts): |
137 diffoptstr = stringutil.pprint(sorted( | 143 diffoptstr = stringutil.pprint( |
138 (k, getattr(diffopts, k)) | 144 sorted((k, getattr(diffopts, k)) for k in mdiff.diffopts.defaults) |
139 for k in mdiff.diffopts.defaults | 145 ) |
140 )) | |
141 return node.hex(hashlib.sha1(diffoptstr).digest())[:6] | 146 return node.hex(hashlib.sha1(diffoptstr).digest())[:6] |
142 | 147 |
148 | |
143 _defaultdiffopthash = hashdiffopts(mdiff.defaultopts) | 149 _defaultdiffopthash = hashdiffopts(mdiff.defaultopts) |
150 | |
144 | 151 |
145 class annotateopts(object): | 152 class annotateopts(object): |
146 """like mercurial.mdiff.diffopts, but is for annotate | 153 """like mercurial.mdiff.diffopts, but is for annotate |
147 | 154 |
148 followrename: follow renames, like "hg annotate -f" | 155 followrename: follow renames, like "hg annotate -f" |
173 diffopthash = hashdiffopts(self.diffopts) | 180 diffopthash = hashdiffopts(self.diffopts) |
174 if diffopthash != _defaultdiffopthash: | 181 if diffopthash != _defaultdiffopthash: |
175 result += 'i' + diffopthash | 182 result += 'i' + diffopthash |
176 return result or 'default' | 183 return result or 'default' |
177 | 184 |
185 | |
178 defaultopts = annotateopts() | 186 defaultopts = annotateopts() |
187 | |
179 | 188 |
180 class _annotatecontext(object): | 189 class _annotatecontext(object): |
181 """do not use this class directly as it does not use lock to protect | 190 """do not use this class directly as it does not use lock to protect |
182 writes. use "with annotatecontext(...)" instead. | 191 writes. use "with annotatecontext(...)" instead. |
183 """ | 192 """ |
189 self.opts = opts | 198 self.opts = opts |
190 self.linelogpath = linelogpath | 199 self.linelogpath = linelogpath |
191 self.revmappath = revmappath | 200 self.revmappath = revmappath |
192 self._linelog = None | 201 self._linelog = None |
193 self._revmap = None | 202 self._revmap = None |
194 self._node2path = {} # {str: str} | 203 self._node2path = {} # {str: str} |
195 | 204 |
196 @property | 205 @property |
197 def linelog(self): | 206 def linelog(self): |
198 if self._linelog is None: | 207 if self._linelog is None: |
199 if os.path.exists(self.linelogpath): | 208 if os.path.exists(self.linelogpath): |
296 | 305 |
297 # fast path: if rev is in the main branch already | 306 # fast path: if rev is in the main branch already |
298 directly, revfctx = self.canannotatedirectly(rev) | 307 directly, revfctx = self.canannotatedirectly(rev) |
299 if directly: | 308 if directly: |
300 if self.ui.debugflag: | 309 if self.ui.debugflag: |
301 self.ui.debug('fastannotate: %s: using fast path ' | 310 self.ui.debug( |
302 '(resolved fctx: %s)\n' | 311 'fastannotate: %s: using fast path ' |
303 % (self.path, | 312 '(resolved fctx: %s)\n' |
304 stringutil.pprint(util.safehasattr(revfctx, | 313 % ( |
305 'node')))) | 314 self.path, |
315 stringutil.pprint(util.safehasattr(revfctx, 'node')), | |
316 ) | |
317 ) | |
306 return self.annotatedirectly(revfctx, showpath, showlines) | 318 return self.annotatedirectly(revfctx, showpath, showlines) |
307 | 319 |
308 # resolve master | 320 # resolve master |
309 masterfctx = None | 321 masterfctx = None |
310 if master: | 322 if master: |
311 try: | 323 try: |
312 masterfctx = self._resolvefctx(master, resolverev=True, | 324 masterfctx = self._resolvefctx( |
313 adjustctx=True) | 325 master, resolverev=True, adjustctx=True |
314 except LookupError: # master does not have the file | 326 ) |
327 except LookupError: # master does not have the file | |
315 pass | 328 pass |
316 else: | 329 else: |
317 if masterfctx in self.revmap: # no need to update linelog | 330 if masterfctx in self.revmap: # no need to update linelog |
318 masterfctx = None | 331 masterfctx = None |
319 | 332 |
320 # ... - @ <- rev (can be an arbitrary changeset, | 333 # ... - @ <- rev (can be an arbitrary changeset, |
321 # / not necessarily a descendant | 334 # / not necessarily a descendant |
322 # master -> o of master) | 335 # master -> o of master) |
340 # "needed" is a simple reference counting dict to free items in | 353 # "needed" is a simple reference counting dict to free items in |
341 # "hist", reducing its memory usage otherwise could be huge. | 354 # "hist", reducing its memory usage otherwise could be huge. |
342 initvisit = [revfctx] | 355 initvisit = [revfctx] |
343 if masterfctx: | 356 if masterfctx: |
344 if masterfctx.rev() is None: | 357 if masterfctx.rev() is None: |
345 raise error.Abort(_('cannot update linelog to wdir()'), | 358 raise error.Abort( |
346 hint=_('set fastannotate.mainbranch')) | 359 _('cannot update linelog to wdir()'), |
360 hint=_('set fastannotate.mainbranch'), | |
361 ) | |
347 initvisit.append(masterfctx) | 362 initvisit.append(masterfctx) |
348 visit = initvisit[:] | 363 visit = initvisit[:] |
349 pcache = {} | 364 pcache = {} |
350 needed = {revfctx: 1} | 365 needed = {revfctx: 1} |
351 hist = {} # {fctx: ([(llrev or fctx, linenum)], text)} | 366 hist = {} # {fctx: ([(llrev or fctx, linenum)], text)} |
352 while visit: | 367 while visit: |
353 f = visit.pop() | 368 f = visit.pop() |
354 if f in pcache or f in hist: | 369 if f in pcache or f in hist: |
355 continue | 370 continue |
356 if f in self.revmap: # in the old main branch, it's a joint | 371 if f in self.revmap: # in the old main branch, it's a joint |
357 llrev = self.revmap.hsh2rev(f.node()) | 372 llrev = self.revmap.hsh2rev(f.node()) |
358 self.linelog.annotate(llrev) | 373 self.linelog.annotate(llrev) |
359 result = self.linelog.annotateresult | 374 result = self.linelog.annotateresult |
360 hist[f] = (result, f.data()) | 375 hist[f] = (result, f.data()) |
361 continue | 376 continue |
385 if masterfctx is not None: | 400 if masterfctx is not None: |
386 self._checklastmasterhead(f) | 401 self._checklastmasterhead(f) |
387 | 402 |
388 if self.ui.debugflag: | 403 if self.ui.debugflag: |
389 if newmainbranch: | 404 if newmainbranch: |
390 self.ui.debug('fastannotate: %s: %d new changesets in the main' | 405 self.ui.debug( |
391 ' branch\n' % (self.path, len(newmainbranch))) | 406 'fastannotate: %s: %d new changesets in the main' |
392 elif not hist: # no joints, no updates | 407 ' branch\n' % (self.path, len(newmainbranch)) |
393 self.ui.debug('fastannotate: %s: linelog cannot help in ' | 408 ) |
394 'annotating this revision\n' % self.path) | 409 elif not hist: # no joints, no updates |
410 self.ui.debug( | |
411 'fastannotate: %s: linelog cannot help in ' | |
412 'annotating this revision\n' % self.path | |
413 ) | |
395 | 414 |
396 # prepare annotateresult so we can update linelog incrementally | 415 # prepare annotateresult so we can update linelog incrementally |
397 self.linelog.annotate(self.linelog.maxrev) | 416 self.linelog.annotate(self.linelog.maxrev) |
398 | 417 |
399 # 3rd DFS does the actual annotate | 418 # 3rd DFS does the actual annotate |
400 visit = initvisit[:] | 419 visit = initvisit[:] |
401 progress = self.ui.makeprogress(('building cache'), | 420 progress = self.ui.makeprogress( |
402 total=len(newmainbranch)) | 421 'building cache', total=len(newmainbranch) |
422 ) | |
403 while visit: | 423 while visit: |
404 f = visit[-1] | 424 f = visit[-1] |
405 if f in hist: | 425 if f in hist: |
406 visit.pop() | 426 visit.pop() |
407 continue | 427 continue |
414 visit.append(p) | 434 visit.append(p) |
415 if not ready: | 435 if not ready: |
416 continue | 436 continue |
417 | 437 |
418 visit.pop() | 438 visit.pop() |
419 blocks = None # mdiff blocks, used for appending linelog | 439 blocks = None # mdiff blocks, used for appending linelog |
420 ismainbranch = (f in newmainbranch) | 440 ismainbranch = f in newmainbranch |
421 # curr is the same as the traditional annotate algorithm, | 441 # curr is the same as the traditional annotate algorithm, |
422 # if we only care about linear history (do not follow merge), | 442 # if we only care about linear history (do not follow merge), |
423 # then curr is not actually used. | 443 # then curr is not actually used. |
424 assert f not in hist | 444 assert f not in hist |
425 curr = _decorate(f) | 445 curr = _decorate(f) |
435 needed[p] -= 1 | 455 needed[p] -= 1 |
436 | 456 |
437 hist[f] = curr | 457 hist[f] = curr |
438 del pcache[f] | 458 del pcache[f] |
439 | 459 |
440 if ismainbranch: # need to write to linelog | 460 if ismainbranch: # need to write to linelog |
441 progress.increment() | 461 progress.increment() |
442 bannotated = None | 462 bannotated = None |
443 if len(pl) == 2 and self.opts.followmerge: # merge | 463 if len(pl) == 2 and self.opts.followmerge: # merge |
444 bannotated = curr[0] | 464 bannotated = curr[0] |
445 if blocks is None: # no parents, add an empty one | 465 if blocks is None: # no parents, add an empty one |
446 blocks = list(self._diffblocks('', curr[1])) | 466 blocks = list(self._diffblocks('', curr[1])) |
447 self._appendrev(f, blocks, bannotated) | 467 self._appendrev(f, blocks, bannotated) |
448 elif showpath: # not append linelog, but we need to record path | 468 elif showpath: # not append linelog, but we need to record path |
449 self._node2path[f.node()] = f.path() | 469 self._node2path[f.node()] = f.path() |
450 | 470 |
451 progress.complete() | 471 progress.complete() |
452 | 472 |
453 result = [ | 473 result = [ |
454 ((self.revmap.rev2hsh(fr) if isinstance(fr, int) else fr.node()), l) | 474 ((self.revmap.rev2hsh(fr) if isinstance(fr, int) else fr.node()), l) |
455 for fr, l in hist[revfctx][0]] # [(node, linenumber)] | 475 for fr, l in hist[revfctx][0] |
476 ] # [(node, linenumber)] | |
456 return self._refineannotateresult(result, revfctx, showpath, showlines) | 477 return self._refineannotateresult(result, revfctx, showpath, showlines) |
457 | 478 |
458 def canannotatedirectly(self, rev): | 479 def canannotatedirectly(self, rev): |
459 """(str) -> bool, fctx or node. | 480 """(str) -> bool, fctx or node. |
460 return (True, f) if we can annotate without updating the linelog, pass | 481 return (True, f) if we can annotate without updating the linelog, pass |
555 for (rev, _linenum), idxs in key2idxs.iteritems(): | 576 for (rev, _linenum), idxs in key2idxs.iteritems(): |
556 if revmap.rev2flag(rev) & revmapmod.sidebranchflag: | 577 if revmap.rev2flag(rev) & revmapmod.sidebranchflag: |
557 continue | 578 continue |
558 hsh = annotateresult[idxs[0]][0] | 579 hsh = annotateresult[idxs[0]][0] |
559 break | 580 break |
560 except StopIteration: # no more unresolved lines | 581 except StopIteration: # no more unresolved lines |
561 return result | 582 return result |
562 if hsh is None: | 583 if hsh is None: |
563 # the remaining key2idxs are not in main branch, resolving them | 584 # the remaining key2idxs are not in main branch, resolving them |
564 # using the hard way... | 585 # using the hard way... |
565 revlines = {} | 586 revlines = {} |
566 for (rev, linenum), idxs in key2idxs.iteritems(): | 587 for (rev, linenum), idxs in key2idxs.iteritems(): |
567 if rev not in revlines: | 588 if rev not in revlines: |
568 hsh = annotateresult[idxs[0]][0] | 589 hsh = annotateresult[idxs[0]][0] |
569 if self.ui.debugflag: | 590 if self.ui.debugflag: |
570 self.ui.debug('fastannotate: reading %s line #%d ' | 591 self.ui.debug( |
571 'to resolve lines %r\n' | 592 'fastannotate: reading %s line #%d ' |
572 % (node.short(hsh), linenum, idxs)) | 593 'to resolve lines %r\n' |
594 % (node.short(hsh), linenum, idxs) | |
595 ) | |
573 fctx = self._resolvefctx(hsh, revmap.rev2path(rev)) | 596 fctx = self._resolvefctx(hsh, revmap.rev2path(rev)) |
574 lines = mdiff.splitnewlines(fctx.data()) | 597 lines = mdiff.splitnewlines(fctx.data()) |
575 revlines[rev] = lines | 598 revlines[rev] = lines |
576 for idx in idxs: | 599 for idx in idxs: |
577 result[idx] = revlines[rev][linenum] | 600 result[idx] = revlines[rev][linenum] |
578 assert all(x is not None for x in result) | 601 assert all(x is not None for x in result) |
579 return result | 602 return result |
580 | 603 |
581 # run the annotate and the lines should match to the file content | 604 # run the annotate and the lines should match to the file content |
582 self.ui.debug('fastannotate: annotate %s to resolve lines\n' | 605 self.ui.debug( |
583 % node.short(hsh)) | 606 'fastannotate: annotate %s to resolve lines\n' % node.short(hsh) |
607 ) | |
584 linelog.annotate(rev) | 608 linelog.annotate(rev) |
585 fctx = self._resolvefctx(hsh, revmap.rev2path(rev)) | 609 fctx = self._resolvefctx(hsh, revmap.rev2path(rev)) |
586 annotated = linelog.annotateresult | 610 annotated = linelog.annotateresult |
587 lines = mdiff.splitnewlines(fctx.data()) | 611 lines = mdiff.splitnewlines(fctx.data()) |
588 if len(lines) != len(annotated): | 612 if len(lines) != len(annotated): |
606 hsh = f | 630 hsh = f |
607 else: | 631 else: |
608 hsh = f.node() | 632 hsh = f.node() |
609 llrev = self.revmap.hsh2rev(hsh) | 633 llrev = self.revmap.hsh2rev(hsh) |
610 if not llrev: | 634 if not llrev: |
611 raise faerror.CorruptedFileError('%s is not in revmap' | 635 raise faerror.CorruptedFileError( |
612 % node.hex(hsh)) | 636 '%s is not in revmap' % node.hex(hsh) |
637 ) | |
613 if (self.revmap.rev2flag(llrev) & revmapmod.sidebranchflag) != 0: | 638 if (self.revmap.rev2flag(llrev) & revmapmod.sidebranchflag) != 0: |
614 raise faerror.CorruptedFileError('%s is not in revmap mainbranch' | 639 raise faerror.CorruptedFileError( |
615 % node.hex(hsh)) | 640 '%s is not in revmap mainbranch' % node.hex(hsh) |
641 ) | |
616 self.linelog.annotate(llrev) | 642 self.linelog.annotate(llrev) |
617 result = [(self.revmap.rev2hsh(r), l) | 643 result = [ |
618 for r, l in self.linelog.annotateresult] | 644 (self.revmap.rev2hsh(r), l) for r, l in self.linelog.annotateresult |
645 ] | |
619 return self._refineannotateresult(result, f, showpath, showlines) | 646 return self._refineannotateresult(result, f, showpath, showlines) |
620 | 647 |
621 def _refineannotateresult(self, result, f, showpath, showlines): | 648 def _refineannotateresult(self, result, f, showpath, showlines): |
622 """add the missing path or line contents, they can be expensive. | 649 """add the missing path or line contents, they can be expensive. |
623 f could be either node or fctx. | 650 f could be either node or fctx. |
624 """ | 651 """ |
625 if showpath: | 652 if showpath: |
626 result = self._addpathtoresult(result) | 653 result = self._addpathtoresult(result) |
627 if showlines: | 654 if showlines: |
628 if isinstance(f, bytes): # f: node or fctx | 655 if isinstance(f, bytes): # f: node or fctx |
629 llrev = self.revmap.hsh2rev(f) | 656 llrev = self.revmap.hsh2rev(f) |
630 fctx = self._resolvefctx(f, self.revmap.rev2path(llrev)) | 657 fctx = self._resolvefctx(f, self.revmap.rev2path(llrev)) |
631 else: | 658 else: |
632 fctx = f | 659 fctx = f |
633 lines = mdiff.splitnewlines(fctx.data()) | 660 lines = mdiff.splitnewlines(fctx.data()) |
634 if len(lines) != len(result): # linelog is probably corrupted | 661 if len(lines) != len(result): # linelog is probably corrupted |
635 raise faerror.CorruptedFileError() | 662 raise faerror.CorruptedFileError() |
636 result = (result, lines) | 663 result = (result, lines) |
637 return result | 664 return result |
638 | 665 |
639 def _appendrev(self, fctx, blocks, bannotated=None): | 666 def _appendrev(self, fctx, blocks, bannotated=None): |
658 rev = revmap.append(hsh, sidebranch=True, path=f.path()) | 685 rev = revmap.append(hsh, sidebranch=True, path=f.path()) |
659 return rev | 686 return rev |
660 | 687 |
661 # append sidebranch revisions to revmap | 688 # append sidebranch revisions to revmap |
662 siderevs = [] | 689 siderevs = [] |
663 siderevmap = {} # node: int | 690 siderevmap = {} # node: int |
664 if bannotated is not None: | 691 if bannotated is not None: |
665 for (a1, a2, b1, b2), op in blocks: | 692 for (a1, a2, b1, b2), op in blocks: |
666 if op != '=': | 693 if op != '=': |
667 # f could be either linelong rev, or fctx. | 694 # f could be either linelong rev, or fctx. |
668 siderevs += [f for f, l in bannotated[b1:b2] | 695 siderevs += [ |
669 if not isinstance(f, int)] | 696 f |
697 for f, l in bannotated[b1:b2] | |
698 if not isinstance(f, int) | |
699 ] | |
670 siderevs = set(siderevs) | 700 siderevs = set(siderevs) |
671 if fctx in siderevs: # mainnode must be appended seperately | 701 if fctx in siderevs: # mainnode must be appended seperately |
672 siderevs.remove(fctx) | 702 siderevs.remove(fctx) |
673 for f in siderevs: | 703 for f in siderevs: |
674 siderevmap[f] = getllrev(f) | 704 siderevmap[f] = getllrev(f) |
675 | 705 |
676 # the changeset in the main branch, could be a merge | 706 # the changeset in the main branch, could be a merge |
681 if op == '=': | 711 if op == '=': |
682 continue | 712 continue |
683 if bannotated is None: | 713 if bannotated is None: |
684 linelog.replacelines(llrev, a1, a2, b1, b2) | 714 linelog.replacelines(llrev, a1, a2, b1, b2) |
685 else: | 715 else: |
686 blines = [((r if isinstance(r, int) else siderevmap[r]), l) | 716 blines = [ |
687 for r, l in bannotated[b1:b2]] | 717 ((r if isinstance(r, int) else siderevmap[r]), l) |
718 for r, l in bannotated[b1:b2] | |
719 ] | |
688 linelog.replacelines_vec(llrev, a1, a2, blines) | 720 linelog.replacelines_vec(llrev, a1, a2, blines) |
689 | 721 |
690 def _addpathtoresult(self, annotateresult, revmap=None): | 722 def _addpathtoresult(self, annotateresult, revmap=None): |
691 """(revmap, [(node, linenum)]) -> [(node, linenum, path)]""" | 723 """(revmap, [(node, linenum)]) -> [(node, linenum, path)]""" |
692 if revmap is None: | 724 if revmap is None: |
715 @util.propertycache | 747 @util.propertycache |
716 def _parentfunc(self): | 748 def _parentfunc(self): |
717 """-> (fctx) -> [fctx]""" | 749 """-> (fctx) -> [fctx]""" |
718 followrename = self.opts.followrename | 750 followrename = self.opts.followrename |
719 followmerge = self.opts.followmerge | 751 followmerge = self.opts.followmerge |
752 | |
720 def parents(f): | 753 def parents(f): |
721 pl = _parents(f, follow=followrename) | 754 pl = _parents(f, follow=followrename) |
722 if not followmerge: | 755 if not followmerge: |
723 pl = pl[:1] | 756 pl = pl[:1] |
724 return pl | 757 return pl |
758 | |
725 return parents | 759 return parents |
726 | 760 |
727 @util.propertycache | 761 @util.propertycache |
728 def _perfhack(self): | 762 def _perfhack(self): |
729 return self.ui.configbool('fastannotate', 'perfhack') | 763 return self.ui.configbool('fastannotate', 'perfhack') |
730 | 764 |
731 def _resolvefctx(self, rev, path=None, **kwds): | 765 def _resolvefctx(self, rev, path=None, **kwds): |
732 return resolvefctx(self.repo, rev, (path or self.path), **kwds) | 766 return resolvefctx(self.repo, rev, (path or self.path), **kwds) |
767 | |
733 | 768 |
734 def _unlinkpaths(paths): | 769 def _unlinkpaths(paths): |
735 """silent, best-effort unlink""" | 770 """silent, best-effort unlink""" |
736 for path in paths: | 771 for path in paths: |
737 try: | 772 try: |
738 util.unlink(path) | 773 util.unlink(path) |
739 except OSError: | 774 except OSError: |
740 pass | 775 pass |
741 | 776 |
777 | |
742 class pathhelper(object): | 778 class pathhelper(object): |
743 """helper for getting paths for lockfile, linelog and revmap""" | 779 """helper for getting paths for lockfile, linelog and revmap""" |
744 | 780 |
745 def __init__(self, repo, path, opts=defaultopts): | 781 def __init__(self, repo, path, opts=defaultopts): |
746 # different options use different directories | 782 # different options use different directories |
747 self._vfspath = os.path.join('fastannotate', | 783 self._vfspath = os.path.join( |
748 opts.shortstr, encodedir(path)) | 784 'fastannotate', opts.shortstr, encodedir(path) |
785 ) | |
749 self._repo = repo | 786 self._repo = repo |
750 | 787 |
751 @property | 788 @property |
752 def dirname(self): | 789 def dirname(self): |
753 return os.path.dirname(self._repo.vfs.join(self._vfspath)) | 790 return os.path.dirname(self._repo.vfs.join(self._vfspath)) |
760 return lockmod.lock(self._repo.vfs, self._vfspath + '.lock') | 797 return lockmod.lock(self._repo.vfs, self._vfspath + '.lock') |
761 | 798 |
762 @property | 799 @property |
763 def revmappath(self): | 800 def revmappath(self): |
764 return self._repo.vfs.join(self._vfspath + '.m') | 801 return self._repo.vfs.join(self._vfspath + '.m') |
802 | |
765 | 803 |
766 @contextlib.contextmanager | 804 @contextlib.contextmanager |
767 def annotatecontext(repo, path, opts=defaultopts, rebuild=False): | 805 def annotatecontext(repo, path, opts=defaultopts, rebuild=False): |
768 """context needed to perform (fast) annotate on a file | 806 """context needed to perform (fast) annotate on a file |
769 | 807 |
797 raise | 835 raise |
798 finally: | 836 finally: |
799 if actx is not None: | 837 if actx is not None: |
800 actx.close() | 838 actx.close() |
801 | 839 |
840 | |
802 def fctxannotatecontext(fctx, follow=True, diffopts=None, rebuild=False): | 841 def fctxannotatecontext(fctx, follow=True, diffopts=None, rebuild=False): |
803 """like annotatecontext but get the context from a fctx. convenient when | 842 """like annotatecontext but get the context from a fctx. convenient when |
804 used in fctx.annotate | 843 used in fctx.annotate |
805 """ | 844 """ |
806 repo = fctx._repo | 845 repo = fctx._repo |