Patchwork [2,of,2] dagop: move blockancestors() and blockdescendants() from context

login
register
mail settings
Submitter Yuya Nishihara
Date June 17, 2017, 3:59 p.m.
Message ID <4b258e839f739c8c5c42.1497715163@mimosa>
Download mbox | patch
Permalink /patch/21461/
State Accepted
Headers show

Comments

Yuya Nishihara - June 17, 2017, 3:59 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1487500634 -32400
#      Sun Feb 19 19:37:14 2017 +0900
# Node ID 4b258e839f739c8c5c422b34891598aeb05858aa
# Parent  ea5c0d4b4f3ff4b78218d21e29b8c2068f78907f
dagop: move blockancestors() and blockdescendants() from context

context.py seems not a good place to host these functions.

  % wc -l mercurial/context.py mercurial/dagop.py
    2306 mercurial/context.py
     424 mercurial/dagop.py
    2730 total
Augie Fackler - June 19, 2017, 1:41 a.m.
On Sun, Jun 18, 2017 at 12:59:23AM +0900, Yuya Nishihara wrote:
> # HG changeset patch
> # User Yuya Nishihara <yuya@tcha.org>
> # Date 1487500634 -32400
> #      Sun Feb 19 19:37:14 2017 +0900
> # Node ID 4b258e839f739c8c5c422b34891598aeb05858aa
> # Parent  ea5c0d4b4f3ff4b78218d21e29b8c2068f78907f
> dagop: move blockancestors() and blockdescendants() from context

queued, thanks

(slight conflict that required rebase to fix, but diff-of-diffs looks
sensible based on recent activity in revset.py)

Patch

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -1272,89 +1272,6 @@  class filectx(basefilectx):
         return [filectx(self._repo, self._path, fileid=x,
                         filelog=self._filelog) for x in c]
 
-def _changesrange(fctx1, fctx2, linerange2, diffopts):
-    """Return `(diffinrange, linerange1)` where `diffinrange` is True
-    if diff from fctx2 to fctx1 has changes in linerange2 and
-    `linerange1` is the new line range for fctx1.
-    """
-    blocks = mdiff.allblocks(fctx1.data(), fctx2.data(), diffopts)
-    filteredblocks, linerange1 = mdiff.blocksinrange(blocks, linerange2)
-    diffinrange = any(stype == '!' for _, stype in filteredblocks)
-    return diffinrange, linerange1
-
-def blockancestors(fctx, fromline, toline, followfirst=False):
-    """Yield ancestors of `fctx` with respect to the block of lines within
-    `fromline`-`toline` range.
-    """
-    diffopts = patch.diffopts(fctx._repo.ui)
-    introrev = fctx.introrev()
-    if fctx.rev() != introrev:
-        fctx = fctx.filectx(fctx.filenode(), changeid=introrev)
-    visit = {(fctx.linkrev(), fctx.filenode()): (fctx, (fromline, toline))}
-    while visit:
-        c, linerange2 = visit.pop(max(visit))
-        pl = c.parents()
-        if followfirst:
-            pl = pl[:1]
-        if not pl:
-            # The block originates from the initial revision.
-            yield c, linerange2
-            continue
-        inrange = False
-        for p in pl:
-            inrangep, linerange1 = _changesrange(p, c, linerange2, diffopts)
-            inrange = inrange or inrangep
-            if linerange1[0] == linerange1[1]:
-                # Parent's linerange is empty, meaning that the block got
-                # introduced in this revision; no need to go futher in this
-                # branch.
-                continue
-            # Set _descendantrev with 'c' (a known descendant) so that, when
-            # _adjustlinkrev is called for 'p', it receives this descendant
-            # (as srcrev) instead possibly topmost introrev.
-            p._descendantrev = c.rev()
-            visit[p.linkrev(), p.filenode()] = p, linerange1
-        if inrange:
-            yield c, linerange2
-
-def blockdescendants(fctx, fromline, toline):
-    """Yield descendants of `fctx` with respect to the block of lines within
-    `fromline`-`toline` range.
-    """
-    # First possibly yield 'fctx' if it has changes in range with respect to
-    # its parents.
-    try:
-        c, linerange1 = next(blockancestors(fctx, fromline, toline))
-    except StopIteration:
-        pass
-    else:
-        if c == fctx:
-            yield c, linerange1
-
-    diffopts = patch.diffopts(fctx._repo.ui)
-    fl = fctx.filelog()
-    seen = {fctx.filerev(): (fctx, (fromline, toline))}
-    for i in fl.descendants([fctx.filerev()]):
-        c = fctx.filectx(i)
-        inrange = False
-        for x in fl.parentrevs(i):
-            try:
-                p, linerange2 = seen[x]
-            except KeyError:
-                # nullrev or other branch
-                continue
-            inrangep, linerange1 = _changesrange(c, p, linerange2, diffopts)
-            inrange = inrange or inrangep
-            # If revision 'i' has been seen (it's a merge), we assume that its
-            # line range is the same independently of which parents was used
-            # to compute it.
-            assert i not in seen or seen[i][1] == linerange1, (
-                'computed line range for %s is not consistent between '
-                'ancestor branches' % c)
-            seen[i] = c, linerange1
-        if inrange:
-            yield c, linerange1
-
 class committablectx(basectx):
     """A committablectx object provides common functionality for a context that
     wants the ability to commit, e.g. workingctx or memctx."""
diff --git a/mercurial/dagop.py b/mercurial/dagop.py
--- a/mercurial/dagop.py
+++ b/mercurial/dagop.py
@@ -11,7 +11,9 @@  import heapq
 
 from . import (
     error,
+    mdiff,
     node,
+    patch,
     smartset,
 )
 
@@ -140,6 +142,89 @@  def reachableroots(repo, roots, heads, i
     revs.sort()
     return revs
 
+def _changesrange(fctx1, fctx2, linerange2, diffopts):
+    """Return `(diffinrange, linerange1)` where `diffinrange` is True
+    if diff from fctx2 to fctx1 has changes in linerange2 and
+    `linerange1` is the new line range for fctx1.
+    """
+    blocks = mdiff.allblocks(fctx1.data(), fctx2.data(), diffopts)
+    filteredblocks, linerange1 = mdiff.blocksinrange(blocks, linerange2)
+    diffinrange = any(stype == '!' for _, stype in filteredblocks)
+    return diffinrange, linerange1
+
+def blockancestors(fctx, fromline, toline, followfirst=False):
+    """Yield ancestors of `fctx` with respect to the block of lines within
+    `fromline`-`toline` range.
+    """
+    diffopts = patch.diffopts(fctx._repo.ui)
+    introrev = fctx.introrev()
+    if fctx.rev() != introrev:
+        fctx = fctx.filectx(fctx.filenode(), changeid=introrev)
+    visit = {(fctx.linkrev(), fctx.filenode()): (fctx, (fromline, toline))}
+    while visit:
+        c, linerange2 = visit.pop(max(visit))
+        pl = c.parents()
+        if followfirst:
+            pl = pl[:1]
+        if not pl:
+            # The block originates from the initial revision.
+            yield c, linerange2
+            continue
+        inrange = False
+        for p in pl:
+            inrangep, linerange1 = _changesrange(p, c, linerange2, diffopts)
+            inrange = inrange or inrangep
+            if linerange1[0] == linerange1[1]:
+                # Parent's linerange is empty, meaning that the block got
+                # introduced in this revision; no need to go futher in this
+                # branch.
+                continue
+            # Set _descendantrev with 'c' (a known descendant) so that, when
+            # _adjustlinkrev is called for 'p', it receives this descendant
+            # (as srcrev) instead possibly topmost introrev.
+            p._descendantrev = c.rev()
+            visit[p.linkrev(), p.filenode()] = p, linerange1
+        if inrange:
+            yield c, linerange2
+
+def blockdescendants(fctx, fromline, toline):
+    """Yield descendants of `fctx` with respect to the block of lines within
+    `fromline`-`toline` range.
+    """
+    # First possibly yield 'fctx' if it has changes in range with respect to
+    # its parents.
+    try:
+        c, linerange1 = next(blockancestors(fctx, fromline, toline))
+    except StopIteration:
+        pass
+    else:
+        if c == fctx:
+            yield c, linerange1
+
+    diffopts = patch.diffopts(fctx._repo.ui)
+    fl = fctx.filelog()
+    seen = {fctx.filerev(): (fctx, (fromline, toline))}
+    for i in fl.descendants([fctx.filerev()]):
+        c = fctx.filectx(i)
+        inrange = False
+        for x in fl.parentrevs(i):
+            try:
+                p, linerange2 = seen[x]
+            except KeyError:
+                # nullrev or other branch
+                continue
+            inrangep, linerange1 = _changesrange(c, p, linerange2, diffopts)
+            inrange = inrange or inrangep
+            # If revision 'i' has been seen (it's a merge), we assume that its
+            # line range is the same independently of which parents was used
+            # to compute it.
+            assert i not in seen or seen[i][1] == linerange1, (
+                'computed line range for %s is not consistent between '
+                'ancestor branches' % c)
+            seen[i] = c, linerange1
+        if inrange:
+            yield c, linerange1
+
 def toposort(revs, parentsfunc, firstbranch=()):
     """Yield revisions from heads to roots one (topo) branch at a time.
 
diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py
--- a/mercurial/hgweb/webcommands.py
+++ b/mercurial/hgweb/webcommands.py
@@ -28,7 +28,7 @@  from .common import (
 
 from .. import (
     archival,
-    context,
+    dagop,
     encoding,
     error,
     graphmod,
@@ -1013,9 +1013,9 @@  def filelog(web, req, tmpl):
         # would required a dedicated "revnav" class
         nav = None
         if descend:
-            it = context.blockdescendants(fctx, *lrange)
+            it = dagop.blockdescendants(fctx, *lrange)
         else:
-            it = context.blockancestors(fctx, *lrange)
+            it = dagop.blockancestors(fctx, *lrange)
         for i, (c, lr) in enumerate(it, 1):
             diffs = None
             if patch:
diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -827,8 +827,6 @@  def followlines(repo, subset, x):
     descendants of 'startrev' are returned though renames are (currently) not
     followed in this direction.
     """
-    from . import context  # avoid circular import issues
-
     args = getargsdict(x, 'followlines', 'file *lines startrev descend')
     if len(args['lines']) != 1:
         raise error.ParseError(_("followlines requires a line range"))
@@ -868,12 +866,12 @@  def followlines(repo, subset, x):
     if descend:
         rs = generatorset(
             (c.rev() for c, _linerange
-             in context.blockdescendants(fctx, fromline, toline)),
+             in dagop.blockdescendants(fctx, fromline, toline)),
             iterasc=True)
     else:
         rs = generatorset(
             (c.rev() for c, _linerange
-             in context.blockancestors(fctx, fromline, toline)),
+             in dagop.blockancestors(fctx, fromline, toline)),
             iterasc=False)
     return subset & rs