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