[PATCH 3 of 3 V2] revset: add a changes(file, fromline, toline[, rev]) revset

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Tue Dec 27 02:09:43 EST 2016


At Sat, 24 Dec 2016 14:56:51 -0500,
Augie Fackler wrote:
> 
> On Fri, Dec 16, 2016 at 02:30:15PM +0100, Denis Laxalde wrote:
> > # HG changeset patch
> > # User Denis Laxalde <denis.laxalde at logilab.fr>
> > # Date 1480086890 -3600
> > #      Fri Nov 25 16:14:50 2016 +0100
> > # Node ID 5e5ec2ade2cfc829cffba145193da5801c5b20e7
> > # Parent  c8dfd10c5865cfe882a00595743f3f709f41317f
> > # EXP-Topic linerange-log/revset
> > revset: add a changes(file, fromline, toline[, rev]) revset
> 
> I'm +1 on the series as a whole. I'll do one more pass over the mdiff
> stuff to try and understand it, but realistically I'm too far removed
> from that code right now to give it a proper review.
> 
> If I hear nothing by January 5th or so, I'll take this as-is.
> 
> >
> > Added tests in test-annotate.t which already contains a reasonably complex
> > repository.
> >
> > diff --git a/mercurial/revset.py b/mercurial/revset.py
> > --- a/mercurial/revset.py
> > +++ b/mercurial/revset.py
> > @@ -1350,6 +1350,42 @@ def modifies(repo, subset, x):
> >      pat = getstring(x, _("modifies requires a pattern"))
> >      return checkstatus(repo, subset, pat, 0)
> >
> > + at predicate('changes(file, fromline, toline, rev)', safe=True)
> > +def changes(repo, subset, x):
> > +    """Changesets modifying `file` in line range ('fromline', 'toline').
> > +
> > +    Line range corresponds to 'file' content at 'rev'. If rev is not
> > +    specified, working directory's parent is used.
> > +    """
> > +    from . import context  # avoid circular import issues
> > +
> > +    args = getargs(x, 3, 4, _("changes takes at least three arguments"))
> > +    pat = getstring(args[0], _("changes requires a pattern"))
> > +    if matchmod.patkind(pat):
> > +        raise error.ParseError(_("changes does not handle file patterns"))

This error raising prevents from using "path:" prefix to specify
root-ed path from non repository-root directory (e.g. invocation with
"-R path/to/repo"). This differs from other predicates, and might be
issue at automation or so.

How about filelog()-like implementation below for similarity to other
predicates ? (this assumes that "rev" is already determined at this
point)

    if not matchmod.patkind(pat):
        fname = pathutil.canonpath(repo.root, repo.getcwd(), pat)
    else:
        m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[rev])
        files = (f for f in repo[rev] if m(f))
        if len(files) != 1:
            raise error # or apply "changes()" on each matched files ?
        fname = files[0]


> > +    fname = pathutil.canonpath(repo.root, repo.getcwd(), pat)
> > +
> > +    try:
> > +        fromline, toline = [int(getsymbol(a)) for a in args[1:3]]
> > +    except ValueError:
> > +        raise error.ParseError(_("line range bounds must be integers"))
> > +    if toline - fromline < 0:
> > +        raise error.ParseError(_("line range must be positive"))
> > +    if fromline < 1:
> > +        raise error.ParseError(_("fromline must be strictly positive"))
> > +    fromline -= 1
> > +
> > +    rev = '.'
> > +    if len(args) == 4:
> > +        revs = getset(repo, fullreposet(repo), args[3])
> > +        if len(revs) != 1:
> > +            raise error.ParseError(_("changes expects exactly one revision"))
> > +        rev = revs.last()
> > +
> > +    fctx = repo[rev].filectx(fname)
> > +    revs = (c.rev() for c in context.blockancestors(fctx, fromline, toline))
> > +    return subset & generatorset(revs, iterasc=False)
> > +
> >  @predicate('named(namespace)')
> >  def named(repo, subset, x):
> >      """The changesets in a given namespace.
> > diff --git a/tests/test-annotate.t b/tests/test-annotate.t
> > --- a/tests/test-annotate.t
> > +++ b/tests/test-annotate.t
> > @@ -480,6 +480,57 @@ annotate removed file
> >    [255]
> >  #endif
> >
> > +  $ hg revert --all --no-backup --quiet
> > +  $ hg id -n
> > +  20
> > +
> > +Test changes() revset
> > +
> > +  $ hg log -T '{rev}: {desc}\n' -r 'changes(baz, 3, 5)'
> > +  16: baz:0
> > +  19: baz:3
> > +  20: baz:4
> > +  $ hg log -T '{rev}: {desc}\n' -r 'changes(baz, 3, 5, .^)'
> > +  16: baz:0
> > +  19: baz:3
> > +  $ echo "0" | cat - baz > baz1
> > +  $ mv baz1 baz
> > +  $ hg ci -m 'added line 0'
> > +  $ hg log -T '{rev}: {desc}\n' -r 'changes(baz, 4, 6)'
> > +  16: baz:0
> > +  19: baz:3
> > +  20: baz:4
> > +  $ echo 6 >> baz
> > +  $ hg ci -m 'added line 7'
> > +  $ hg log -T '{rev}: {desc}\n' -r 'changes(baz, 4, 6)'
> > +  16: baz:0
> > +  19: baz:3
> > +  20: baz:4
> > +  $ sed 's/3/3+/' baz > baz.new
> > +  $ mv baz.new baz
> > +  $ hg ci -m 'baz:3->3+'
> > +  $ hg log -T '{rev}: {desc}\n' -r 'changes(baz, 4, 6)'
> > +  16: baz:0
> > +  19: baz:3
> > +  20: baz:4
> > +  23: baz:3->3+
> > +
> > +  $ hg log -r 'changes(baz, 1, 2, desc("b"))'
> > +  hg: parse error: changes expects exactly one revision
> > +  [255]
> > +  $ hg log -r 'changes(baz, x, 4)'
> > +  hg: parse error: line range bounds must be integers
> > +  [255]
> > +  $ hg log -r 'changes(baz, 5, 4)'
> > +  hg: parse error: line range must be positive
> > +  [255]
> > +  $ hg log -r 'changes(baz, 0, 4)'
> > +  hg: parse error: fromline must be strictly positive
> > +  [255]
> > +  $ hg log -r 'changes(baz, 2, 40)'
> > +  abort: line range exceeds file size
> > +  [255]
> > +
> >  Test annotate with whitespace options
> >
> >    $ cd ..
> > _______________________________________________
> > Mercurial-devel mailing list
> > Mercurial-devel at mercurial-scm.org
> > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

-- 
----------------------------------------------------------------------
[FUJIWARA Katsunori]                             foozy at lares.dti.ne.jp


More information about the Mercurial-devel mailing list