dagop: move annotateline and _annotatepair from context.py
The annotate logic is large. Let's move it out of the context module, which
is basically an abstraction layer of repository operations.
--- a/mercurial/context.py Fri Mar 09 21:59:07 2018 -0500
+++ b/mercurial/context.py Wed Feb 28 15:09:05 2018 -0500
@@ -26,10 +26,8 @@
wdirnodes,
wdirrev,
)
-from .thirdparty import (
- attr,
-)
from . import (
+ dagop,
encoding,
error,
fileset,
@@ -978,6 +976,8 @@
the line number at the first appearance in the managed file, otherwise,
number has a fixed value of False.
'''
+ annotateline = dagop.annotateline
+ _annotatepair = dagop._annotatepair
def lines(text):
if text.endswith("\n"):
@@ -1105,74 +1105,6 @@
"""
return self._repo.wwritedata(self.path(), self.data())
-@attr.s(slots=True, frozen=True)
-class annotateline(object):
- fctx = attr.ib()
- lineno = attr.ib(default=False)
- # Whether this annotation was the result of a skip-annotate.
- skip = attr.ib(default=False)
-
-def _annotatepair(parents, childfctx, child, skipchild, diffopts):
- r'''
- Given parent and child fctxes and annotate data for parents, for all lines
- in either parent that match the child, annotate the child with the parent's
- data.
-
- Additionally, if `skipchild` is True, replace all other lines with parent
- annotate data as well such that child is never blamed for any lines.
-
- See test-annotate.py for unit tests.
- '''
- pblocks = [(parent, mdiff.allblocks(parent[1], child[1], opts=diffopts))
- for parent in parents]
-
- if skipchild:
- # Need to iterate over the blocks twice -- make it a list
- pblocks = [(p, list(blocks)) for (p, blocks) in pblocks]
- # Mercurial currently prefers p2 over p1 for annotate.
- # TODO: change this?
- for parent, blocks in pblocks:
- for (a1, a2, b1, b2), t in blocks:
- # Changed blocks ('!') or blocks made only of blank lines ('~')
- # belong to the child.
- if t == '=':
- child[0][b1:b2] = parent[0][a1:a2]
-
- if skipchild:
- # Now try and match up anything that couldn't be matched,
- # Reversing pblocks maintains bias towards p2, matching above
- # behavior.
- pblocks.reverse()
-
- # The heuristics are:
- # * Work on blocks of changed lines (effectively diff hunks with -U0).
- # This could potentially be smarter but works well enough.
- # * For a non-matching section, do a best-effort fit. Match lines in
- # diff hunks 1:1, dropping lines as necessary.
- # * Repeat the last line as a last resort.
-
- # First, replace as much as possible without repeating the last line.
- remaining = [(parent, []) for parent, _blocks in pblocks]
- for idx, (parent, blocks) in enumerate(pblocks):
- for (a1, a2, b1, b2), _t in blocks:
- if a2 - a1 >= b2 - b1:
- for bk in xrange(b1, b2):
- if child[0][bk].fctx == childfctx:
- ak = min(a1 + (bk - b1), a2 - 1)
- child[0][bk] = attr.evolve(parent[0][ak], skip=True)
- else:
- remaining[idx][1].append((a1, a2, b1, b2))
-
- # Then, look at anything left, which might involve repeating the last
- # line.
- for parent, blocks in remaining:
- for a1, a2, b1, b2 in blocks:
- for bk in xrange(b1, b2):
- if child[0][bk].fctx == childfctx:
- ak = min(a1 + (bk - b1), a2 - 1)
- child[0][bk] = attr.evolve(parent[0][ak], skip=True)
- return child
-
class filectx(basefilectx):
"""A filecontext object makes access to data related to a particular
filerevision convenient."""
--- a/mercurial/dagop.py Fri Mar 09 21:59:07 2018 -0500
+++ b/mercurial/dagop.py Wed Feb 28 15:09:05 2018 -0500
@@ -9,6 +9,9 @@
import heapq
+from .thirdparty import (
+ attr,
+)
from . import (
error,
mdiff,
@@ -358,6 +361,74 @@
if inrange:
yield c, linerange1
+@attr.s(slots=True, frozen=True)
+class annotateline(object):
+ fctx = attr.ib()
+ lineno = attr.ib(default=False)
+ # Whether this annotation was the result of a skip-annotate.
+ skip = attr.ib(default=False)
+
+def _annotatepair(parents, childfctx, child, skipchild, diffopts):
+ r'''
+ Given parent and child fctxes and annotate data for parents, for all lines
+ in either parent that match the child, annotate the child with the parent's
+ data.
+
+ Additionally, if `skipchild` is True, replace all other lines with parent
+ annotate data as well such that child is never blamed for any lines.
+
+ See test-annotate.py for unit tests.
+ '''
+ pblocks = [(parent, mdiff.allblocks(parent[1], child[1], opts=diffopts))
+ for parent in parents]
+
+ if skipchild:
+ # Need to iterate over the blocks twice -- make it a list
+ pblocks = [(p, list(blocks)) for (p, blocks) in pblocks]
+ # Mercurial currently prefers p2 over p1 for annotate.
+ # TODO: change this?
+ for parent, blocks in pblocks:
+ for (a1, a2, b1, b2), t in blocks:
+ # Changed blocks ('!') or blocks made only of blank lines ('~')
+ # belong to the child.
+ if t == '=':
+ child[0][b1:b2] = parent[0][a1:a2]
+
+ if skipchild:
+ # Now try and match up anything that couldn't be matched,
+ # Reversing pblocks maintains bias towards p2, matching above
+ # behavior.
+ pblocks.reverse()
+
+ # The heuristics are:
+ # * Work on blocks of changed lines (effectively diff hunks with -U0).
+ # This could potentially be smarter but works well enough.
+ # * For a non-matching section, do a best-effort fit. Match lines in
+ # diff hunks 1:1, dropping lines as necessary.
+ # * Repeat the last line as a last resort.
+
+ # First, replace as much as possible without repeating the last line.
+ remaining = [(parent, []) for parent, _blocks in pblocks]
+ for idx, (parent, blocks) in enumerate(pblocks):
+ for (a1, a2, b1, b2), _t in blocks:
+ if a2 - a1 >= b2 - b1:
+ for bk in xrange(b1, b2):
+ if child[0][bk].fctx == childfctx:
+ ak = min(a1 + (bk - b1), a2 - 1)
+ child[0][bk] = attr.evolve(parent[0][ak], skip=True)
+ else:
+ remaining[idx][1].append((a1, a2, b1, b2))
+
+ # Then, look at anything left, which might involve repeating the last
+ # line.
+ for parent, blocks in remaining:
+ for a1, a2, b1, b2 in blocks:
+ for bk in xrange(b1, b2):
+ if child[0][bk].fctx == childfctx:
+ ak = min(a1 + (bk - b1), a2 - 1)
+ child[0][bk] = attr.evolve(parent[0][ak], skip=True)
+ return child
+
def toposort(revs, parentsfunc, firstbranch=()):
"""Yield revisions from heads to roots one (topo) branch at a time.
--- a/tests/test-annotate.py Fri Mar 09 21:59:07 2018 -0500
+++ b/tests/test-annotate.py Wed Feb 28 15:09:05 2018 -0500
@@ -6,7 +6,7 @@
from mercurial import (
mdiff,
)
-from mercurial.context import (
+from mercurial.dagop import (
annotateline,
_annotatepair,
)