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
--- a/mercurial/context.py Sun Oct 16 18:03:24 2016 +0900
+++ b/mercurial/context.py Sun Feb 19 19:37:14 2017 +0900
@@ -1272,89 +1272,6 @@
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."""
--- a/mercurial/dagop.py Sun Oct 16 18:03:24 2016 +0900
+++ b/mercurial/dagop.py Sun Feb 19 19:37:14 2017 +0900
@@ -11,7 +11,9 @@
from . import (
error,
+ mdiff,
node,
+ patch,
smartset,
)
@@ -140,6 +142,89 @@
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.
--- a/mercurial/hgweb/webcommands.py Sun Oct 16 18:03:24 2016 +0900
+++ b/mercurial/hgweb/webcommands.py Sun Feb 19 19:37:14 2017 +0900
@@ -28,7 +28,7 @@
from .. import (
archival,
- context,
+ dagop,
encoding,
error,
graphmod,
@@ -1013,9 +1013,9 @@
# 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:
--- a/mercurial/revset.py Sun Oct 16 18:03:24 2016 +0900
+++ b/mercurial/revset.py Sun Feb 19 19:37:14 2017 +0900
@@ -827,8 +827,6 @@
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 @@
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