Patchwork [STABLE,v2] log: map None rev to wdirrev when filtering revisions with --line-range

login
register
mail settings
Submitter Denis Laxalde
Date Nov. 30, 2019, 11:16 a.m.
Message ID <411d301683935cb02d1c.1575112576@marimba>
Download mbox | patch
Permalink /patch/43543/
State Superseded
Headers show

Comments

Denis Laxalde - Nov. 30, 2019, 11:16 a.m.
# HG changeset patch
# User Denis Laxalde <denis@laxalde.org>
# Date 1575060193 -3600
#      Fri Nov 29 21:43:13 2019 +0100
# Branch stable
# Node ID 411d301683935cb02d1c15adbe1d7ef58789da76
# Parent  969e8a52e3842d19387d02e91d6a19a993950ac0
log: map None rev to wdirrev when filtering revisions with --line-range

When 'hg log -f --line-range <file>,<range>' is invoked with <range>
containing uncommitted changes, the command crashes on Python 3 as
follows:

      [...]
      File "/usr/lib/python3/dist-packages/mercurial/commands.py", line 4725, in log
        revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
      File "/usr/lib/python3/dist-packages/mercurial/logcmdutil.py", line 933, in getlinerangerevs
        if rev not in userrevs:
      File "/usr/lib/python3/dist-packages/mercurial/smartset.py", line 969, in __contains__
        if l < x:
    TypeError: '<' not supported between instances of 'int' and 'NoneType'

The None value is because requested line range has uncommitted changes,
so 'rev' is the working directory revision. This only occurs in Python 3
as Python 2 allows comparing None with int.

As suggested by Yuya Nishihara, mapping None to node.wdirrev resolves
the issue and also make the '--line-range' option properly work with -r
'wdir()'. We add extra tests for non-regression and to illustrate
handling of 'wdir()'.
Yuya Nishihara - Nov. 30, 2019, 2:42 p.m.
On Sat, 30 Nov 2019 12:16:16 +0100, Denis Laxalde wrote:
> # HG changeset patch
> # User Denis Laxalde <denis@laxalde.org>
> # Date 1575060193 -3600
> #      Fri Nov 29 21:43:13 2019 +0100
> # Branch stable
> # Node ID 411d301683935cb02d1c15adbe1d7ef58789da76
> # Parent  969e8a52e3842d19387d02e91d6a19a993950ac0
> log: map None rev to wdirrev when filtering revisions with --line-range

> @@ -940,7 +945,7 @@ def getlinerangerevs(repo, userrevs, opt
>          return hunks
>  
>      def hunksfilter(ctx):
> -        fctxlineranges = linerangesbyrev.get(ctx.rev())
> +        fctxlineranges = linerangesbyrev.get(mapwdir(ctx.rev()))
>          if fctxlineranges is None:
>              return nofilterhunksfn
>  
> @@ -960,7 +965,7 @@ def getlinerangerevs(repo, userrevs, opt
>          return filterfn
>  
>      def filematcher(ctx):
> -        files = list(linerangesbyrev.get(ctx.rev(), []))
> +        files = list(linerangesbyrev.get(mapwdir(ctx.rev()), []))

For ctx.rev(), scmutil.intrev(ctx) can be used instead.

Patch

diff --git a/mercurial/logcmdutil.py b/mercurial/logcmdutil.py
--- a/mercurial/logcmdutil.py
+++ b/mercurial/logcmdutil.py
@@ -920,6 +920,11 @@  def getlinerangerevs(repo, userrevs, opt
     """
     wctx = repo[None]
 
+    def mapwdir(rev):
+        if rev is None:
+            return wdirrev
+        return rev
+
     # Two-levels map of "rev -> file ctx -> [line range]".
     linerangesbyrev = {}
     for fname, (fromline, toline) in _parselinerangeopt(repo, opts):
@@ -929,7 +934,7 @@  def getlinerangerevs(repo, userrevs, opt
             )
         fctx = wctx.filectx(fname)
         for fctx, linerange in dagop.blockancestors(fctx, fromline, toline):
-            rev = fctx.introrev()
+            rev = mapwdir(fctx.introrev())
             if rev not in userrevs:
                 continue
             linerangesbyrev.setdefault(rev, {}).setdefault(
@@ -940,7 +945,7 @@  def getlinerangerevs(repo, userrevs, opt
         return hunks
 
     def hunksfilter(ctx):
-        fctxlineranges = linerangesbyrev.get(ctx.rev())
+        fctxlineranges = linerangesbyrev.get(mapwdir(ctx.rev()))
         if fctxlineranges is None:
             return nofilterhunksfn
 
@@ -960,7 +965,7 @@  def getlinerangerevs(repo, userrevs, opt
         return filterfn
 
     def filematcher(ctx):
-        files = list(linerangesbyrev.get(ctx.rev(), []))
+        files = list(linerangesbyrev.get(mapwdir(ctx.rev()), []))
         return scmutil.matchfiles(repo, files)
 
     revs = sorted(linerangesbyrev, reverse=True)
diff --git a/tests/test-log-linerange.t b/tests/test-log-linerange.t
--- a/tests/test-log-linerange.t
+++ b/tests/test-log-linerange.t
@@ -898,6 +898,99 @@  Uncommitted changes with a rename
   date:        Thu Jan 01 00:00:00 1970 +0000
   summary:     init
   
+
+Uncommitted changes in requested line range
+
+  $ sed 's/2/  /' bazn > bazn.new
+  $ mv bazn.new bazn
+  $ hg diff
+  diff --git a/dir/baz b/dir/bazn
+  rename from dir/baz
+  rename to dir/bazn
+  --- a/dir/baz
+  +++ b/dir/bazn
+  @@ -3,7 +3,7 @@
+   0
+   0
+    1+
+  -2+
+  +  +
+   3+
+   4
+   5
+  $ hg log -f -L bazn,5:7
+  changeset:   9:6af29c3a778f
+  tag:         tip
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     foo -> dir/baz; 1-1+
+  
+  changeset:   5:cfdf972b3971
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     foo: 3 -> 3+ and 11+ -> 11-; bar: a -> a+
+  
+  changeset:   4:eaec41c1a0c9
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     11 -> 11+; leading space before "1"
+  
+  changeset:   2:63a884426fd0
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2 -> 2+; added bar
+  
+  changeset:   0:5ae1f82b9a00
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     init
+  
+
+Uncommitted changes in line-range + wdir()
+
+  $ hg log -r 'wdir()' -f -L bazn,5:7 --limit 2 -p
+  changeset:   2147483647:ffffffffffff
+  parent:      9:6af29c3a778f
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  
+  diff --git a/dir/baz b/dir/bazn
+  copy from dir/baz
+  copy to dir/bazn
+  --- a/dir/baz
+  +++ b/dir/bazn
+  @@ -3,7 +3,7 @@
+   0
+   0
+    1+
+  -2+
+  +  +
+   3+
+   4
+   5
+  
+  changeset:   9:6af29c3a778f
+  tag:         tip
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     foo -> dir/baz; 1-1+
+  
+  diff --git a/foo b/dir/baz
+  copy from foo
+  copy to dir/baz
+  --- a/foo
+  +++ b/dir/baz
+  @@ -2,7 +2,7 @@
+   0
+   0
+   0
+  - 1
+  + 1+
+   2+
+   3+
+   4
+  
+
   $ hg revert -a -C -q
 
 Binary files work but without diff hunks filtering.