[PATCH] revset: fix crash if range set endpoint not in current subset

Matt Mackall mpm at selenic.com
Mon Jun 28 11:09:52 CDT 2010


On Sun, 2010-06-27 at 22:36 -1000, Julian Cowley wrote:
> # HG changeset patch
> # User Julian Cowley <julian at lava.net>
> # Date 1277713087 36000
> # Branch stable
> # Node ID 8e13bae85245766e023097955e7a42f37894785f
> # Parent  ed2bb0f9b27d165b3fc76605b5904c2b4da9a3b7
> revset: fix crash if range set endpoint not in current subset
> 
> Currently, if either endpoint of a range set is not in the current
> subset of revisions, an index error is raised.  For example, this
> crashes:
> 
>   hg log -r '1:2 and 0:2'
> 
> This does not:
> 
>   hg log -r '0:2 and 1:2'

Also:

-r 'not 1 and 1:2'

> The fix is to generate the range set independently of the current
> subset, then return the intersection of the two.  This potentially
> runs slowly and there are probably numerous ways this can be optimized,
> but for now this returns the right answer.

It's not sufficient. All you need to break it again is an empty set:

-r '(1 and 2):3'

And this also currently breaks:

-r '(1 and 2)::'

As that's "descendants of the empty set", it should give us an empty set
too, so:

-r '(1 and 2):' -> empty set
-r '(1 and 2):3' -> still empty?


I've queued up a different fix that looks like this, thanks:

# HG changeset patch
# User Matt Mackall <mpm at selenic.com>
# Date 1277741247 18000
# Branch stable
# Node ID 88abbb046e66d6b1c4e5458ffd74dc804af14e60
# Parent  3827728b54e20febd05a862663191293a431dc90
revset: deal with empty sets in range endpoints

(spotted by Julian Cowley <julian at lava.net>)

diff -r 3827728b54e2 -r 88abbb046e66 mercurial/revset.py
--- a/mercurial/revset.py	Sun Jun 27 18:20:49 2010 -0500
+++ b/mercurial/revset.py	Mon Jun 28 11:07:27 2010 -0500
@@ -129,11 +129,24 @@
     return stringset(repo, subset, x)
 
 def rangeset(repo, subset, x, y):
-    m = getset(repo, subset, x)[0]
-    n = getset(repo, subset, y)[-1]
+    m = getset(repo, subset, x)
+    if not m:
+        m = getset(repo, range(len(repo)), x)
+
+    n = getset(repo, subset, y)
+    if not n:
+        n = getset(repo, range(len(repo)), y)
+
+    if not m or not n:
+        return []
+    m, n = m[0], n[-1]
+
     if m < n:
-        return range(m, n + 1)
-    return range(m, n - 1, -1)
+        r = range(m, n + 1)
+    else:
+        r = range(m, n - 1, -1)
+    s = set(subset)
+    return [x for x in r if x in s]
 
 def andset(repo, subset, x, y):
     return getset(repo, getset(repo, subset, x), y)
@@ -222,11 +235,15 @@
 
 def ancestors(repo, subset, x):
     args = getset(repo, range(len(repo)), x)
+    if not args:
+        return []
     s = set(repo.changelog.ancestors(*args)) | set(args)
     return [r for r in subset if r in s]
 
 def descendants(repo, subset, x):
     args = getset(repo, range(len(repo)), x)
+    if not args:
+        return []
     s = set(repo.changelog.descendants(*args)) | set(args)
     return [r for r in subset if r in s]
 
diff -r 3827728b54e2 -r 88abbb046e66 tests/test-revset
--- a/tests/test-revset	Sun Jun 27 18:20:49 2010 -0500
+++ b/tests/test-revset	Mon Jun 28 11:07:27 2010 -0500
@@ -126,3 +126,10 @@
 log '4:8'
 
 log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
+
+log 'not 0 and 0:2'
+log 'not 1 and 0:2'
+log 'not 2 and 0:2'
+log '(1 and 2)::'
+log '(1 and 2):'
+log '(1 and 2):3'
diff -r 3827728b54e2 -r 88abbb046e66 tests/test-revset.out
--- a/tests/test-revset.out	Sun Jun 27 18:20:49 2010 -0500
+++ b/tests/test-revset.out	Mon Jun 28 11:07:27 2010 -0500
@@ -198,3 +198,15 @@
 4
 2
 5
+% log 'not 0 and 0:2'
+1
+2
+% log 'not 1 and 0:2'
+0
+2
+% log 'not 2 and 0:2'
+0
+1
+% log '(1 and 2)::'
+% log '(1 and 2):'
+% log '(1 and 2):3'

-- 
Mathematics is the supreme nostalgia of our time.




More information about the Mercurial-devel mailing list