Show More
@@ -32,7 +32,6 b' from . import (' | |||||
32 | error, |
|
32 | error, | |
33 | fileset, |
|
33 | fileset, | |
34 | match as matchmod, |
|
34 | match as matchmod, | |
35 | mdiff, |
|
|||
36 | obsolete as obsmod, |
|
35 | obsolete as obsmod, | |
37 | obsutil, |
|
36 | obsutil, | |
38 | patch, |
|
37 | patch, | |
@@ -976,22 +975,6 b' class basefilectx(object):' | |||||
976 | the line number at the first appearance in the managed file, otherwise, |
|
975 | the line number at the first appearance in the managed file, otherwise, | |
977 | number has a fixed value of False. |
|
976 | number has a fixed value of False. | |
978 | ''' |
|
977 | ''' | |
979 | annotateline = dagop.annotateline |
|
|||
980 | _annotatepair = dagop._annotatepair |
|
|||
981 |
|
||||
982 | def lines(text): |
|
|||
983 | if text.endswith("\n"): |
|
|||
984 | return text.count("\n") |
|
|||
985 | return text.count("\n") + int(bool(text)) |
|
|||
986 |
|
||||
987 | if linenumber: |
|
|||
988 | def decorate(text, rev): |
|
|||
989 | return ([annotateline(fctx=rev, lineno=i) |
|
|||
990 | for i in xrange(1, lines(text) + 1)], text) |
|
|||
991 | else: |
|
|||
992 | def decorate(text, rev): |
|
|||
993 | return ([annotateline(fctx=rev)] * lines(text), text) |
|
|||
994 |
|
||||
995 | getlog = util.lrucachefunc(lambda x: self._repo.file(x)) |
|
978 | getlog = util.lrucachefunc(lambda x: self._repo.file(x)) | |
996 |
|
979 | |||
997 | def parents(f): |
|
980 | def parents(f): | |
@@ -1027,60 +1010,8 b' class basefilectx(object):' | |||||
1027 | ac = cl.ancestors([base.rev()], inclusive=True) |
|
1010 | ac = cl.ancestors([base.rev()], inclusive=True) | |
1028 | base._ancestrycontext = ac |
|
1011 | base._ancestrycontext = ac | |
1029 |
|
1012 | |||
1030 | # This algorithm would prefer to be recursive, but Python is a |
|
1013 | return dagop.annotate(base, parents, linenumber=linenumber, | |
1031 | # bit recursion-hostile. Instead we do an iterative |
|
1014 | skiprevs=skiprevs, diffopts=diffopts) | |
1032 | # depth-first search. |
|
|||
1033 |
|
||||
1034 | # 1st DFS pre-calculates pcache and needed |
|
|||
1035 | visit = [base] |
|
|||
1036 | pcache = {} |
|
|||
1037 | needed = {base: 1} |
|
|||
1038 | while visit: |
|
|||
1039 | f = visit.pop() |
|
|||
1040 | if f in pcache: |
|
|||
1041 | continue |
|
|||
1042 | pl = parents(f) |
|
|||
1043 | pcache[f] = pl |
|
|||
1044 | for p in pl: |
|
|||
1045 | needed[p] = needed.get(p, 0) + 1 |
|
|||
1046 | if p not in pcache: |
|
|||
1047 | visit.append(p) |
|
|||
1048 |
|
||||
1049 | # 2nd DFS does the actual annotate |
|
|||
1050 | visit[:] = [base] |
|
|||
1051 | hist = {} |
|
|||
1052 | while visit: |
|
|||
1053 | f = visit[-1] |
|
|||
1054 | if f in hist: |
|
|||
1055 | visit.pop() |
|
|||
1056 | continue |
|
|||
1057 |
|
||||
1058 | ready = True |
|
|||
1059 | pl = pcache[f] |
|
|||
1060 | for p in pl: |
|
|||
1061 | if p not in hist: |
|
|||
1062 | ready = False |
|
|||
1063 | visit.append(p) |
|
|||
1064 | if ready: |
|
|||
1065 | visit.pop() |
|
|||
1066 | curr = decorate(f.data(), f) |
|
|||
1067 | skipchild = False |
|
|||
1068 | if skiprevs is not None: |
|
|||
1069 | skipchild = f._changeid in skiprevs |
|
|||
1070 | curr = _annotatepair([hist[p] for p in pl], f, curr, skipchild, |
|
|||
1071 | diffopts) |
|
|||
1072 | for p in pl: |
|
|||
1073 | if needed[p] == 1: |
|
|||
1074 | del hist[p] |
|
|||
1075 | del needed[p] |
|
|||
1076 | else: |
|
|||
1077 | needed[p] -= 1 |
|
|||
1078 |
|
||||
1079 | hist[f] = curr |
|
|||
1080 | del pcache[f] |
|
|||
1081 |
|
||||
1082 | lineattrs, text = hist[base] |
|
|||
1083 | return pycompat.ziplist(lineattrs, mdiff.splitnewlines(text)) |
|
|||
1084 |
|
1015 | |||
1085 | def ancestors(self, followfirst=False): |
|
1016 | def ancestors(self, followfirst=False): | |
1086 | visit = {} |
|
1017 | visit = {} |
@@ -17,6 +17,7 b' from . import (' | |||||
17 | mdiff, |
|
17 | mdiff, | |
18 | node, |
|
18 | node, | |
19 | patch, |
|
19 | patch, | |
|
20 | pycompat, | |||
20 | smartset, |
|
21 | smartset, | |
21 | ) |
|
22 | ) | |
22 |
|
23 | |||
@@ -429,6 +430,80 b' def _annotatepair(parents, childfctx, ch' | |||||
429 | child[0][bk] = attr.evolve(parent[0][ak], skip=True) |
|
430 | child[0][bk] = attr.evolve(parent[0][ak], skip=True) | |
430 | return child |
|
431 | return child | |
431 |
|
432 | |||
|
433 | def annotate(base, parents, linenumber=False, skiprevs=None, diffopts=None): | |||
|
434 | """Core algorithm for filectx.annotate() | |||
|
435 | ||||
|
436 | `parents(fctx)` is a function returning a list of parent filectxs. | |||
|
437 | """ | |||
|
438 | ||||
|
439 | def lines(text): | |||
|
440 | if text.endswith("\n"): | |||
|
441 | return text.count("\n") | |||
|
442 | return text.count("\n") + int(bool(text)) | |||
|
443 | ||||
|
444 | if linenumber: | |||
|
445 | def decorate(text, rev): | |||
|
446 | return ([annotateline(fctx=rev, lineno=i) | |||
|
447 | for i in xrange(1, lines(text) + 1)], text) | |||
|
448 | else: | |||
|
449 | def decorate(text, rev): | |||
|
450 | return ([annotateline(fctx=rev)] * lines(text), text) | |||
|
451 | ||||
|
452 | # This algorithm would prefer to be recursive, but Python is a | |||
|
453 | # bit recursion-hostile. Instead we do an iterative | |||
|
454 | # depth-first search. | |||
|
455 | ||||
|
456 | # 1st DFS pre-calculates pcache and needed | |||
|
457 | visit = [base] | |||
|
458 | pcache = {} | |||
|
459 | needed = {base: 1} | |||
|
460 | while visit: | |||
|
461 | f = visit.pop() | |||
|
462 | if f in pcache: | |||
|
463 | continue | |||
|
464 | pl = parents(f) | |||
|
465 | pcache[f] = pl | |||
|
466 | for p in pl: | |||
|
467 | needed[p] = needed.get(p, 0) + 1 | |||
|
468 | if p not in pcache: | |||
|
469 | visit.append(p) | |||
|
470 | ||||
|
471 | # 2nd DFS does the actual annotate | |||
|
472 | visit[:] = [base] | |||
|
473 | hist = {} | |||
|
474 | while visit: | |||
|
475 | f = visit[-1] | |||
|
476 | if f in hist: | |||
|
477 | visit.pop() | |||
|
478 | continue | |||
|
479 | ||||
|
480 | ready = True | |||
|
481 | pl = pcache[f] | |||
|
482 | for p in pl: | |||
|
483 | if p not in hist: | |||
|
484 | ready = False | |||
|
485 | visit.append(p) | |||
|
486 | if ready: | |||
|
487 | visit.pop() | |||
|
488 | curr = decorate(f.data(), f) | |||
|
489 | skipchild = False | |||
|
490 | if skiprevs is not None: | |||
|
491 | skipchild = f._changeid in skiprevs | |||
|
492 | curr = _annotatepair([hist[p] for p in pl], f, curr, skipchild, | |||
|
493 | diffopts) | |||
|
494 | for p in pl: | |||
|
495 | if needed[p] == 1: | |||
|
496 | del hist[p] | |||
|
497 | del needed[p] | |||
|
498 | else: | |||
|
499 | needed[p] -= 1 | |||
|
500 | ||||
|
501 | hist[f] = curr | |||
|
502 | del pcache[f] | |||
|
503 | ||||
|
504 | lineattrs, text = hist[base] | |||
|
505 | return pycompat.ziplist(lineattrs, mdiff.splitnewlines(text)) | |||
|
506 | ||||
432 | def toposort(revs, parentsfunc, firstbranch=()): |
|
507 | def toposort(revs, parentsfunc, firstbranch=()): | |
433 | """Yield revisions from heads to roots one (topo) branch at a time. |
|
508 | """Yield revisions from heads to roots one (topo) branch at a time. | |
434 |
|
509 |
General Comments 0
You need to be logged in to leave comments.
Login now