Patchwork D5813: revset: add expect to check the size of a set

login
register
mail settings
Submitter phabricator
Date Feb. 6, 2019, 4:16 p.m.
Message ID <3fdb75474c9b6b7c39b2d06c4f77dda1@localhost.localdomain>
Download mbox | patch
Permalink /patch/38481/
State Not Applicable
Headers show

Comments

phabricator - Feb. 6, 2019, 4:16 p.m.
navaneeth.suresh updated this revision to Diff 13851.
navaneeth.suresh edited the summary of this revision.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D5813?vs=13736&id=13851

REVISION DETAIL
  https://phab.mercurial-scm.org/D5813

AFFECTED FILES
  mercurial/revset.py
  tests/test-revset.t

CHANGE DETAILS




To: navaneeth.suresh, #hg-reviewers
Cc: yuja, pulkit, durin42, mjpieters, mercurial-devel
Yuya Nishihara - Feb. 7, 2019, 1:16 p.m.
> +  $ hg log -r 'expectsize(0:2, 3)'
> +  changeset:   0:2785f51eece5
> +  branch:      a
> +  user:        test
> +  date:        Thu Jan 01 00:00:00 1970 +0000
> +  summary:     0

Nit: the test outputs look unnecessarily verbose. Use `log` (not `hg log`)
instead.

> +@predicate('expectsize(set[, size])', safe=True, takeorder=True)
> +def expectrevsetsize(repo, subset, x, order, n=None):
> +    """Abort if the revset doesn't expect given size"""
> +    args = getargsdict(x, 'expect', 'set size')
> +    size = args.get('size', n)
> +    if size is not None:
> +        try:
> +            # size is given as integer range on expectsize(<set>, <intrange>)

The helper function has been queued. Can you rewrite this to use the
getintrange helper?

> +        if len(rev) not in range(size[0], size[1]+1):

`range()` builds a list of integers on Python 2, which isn't what we want.
Python does support `not (x <= y <= z)` syntax, so you can just compare
integer bounds.

> +@predicate('one(set)', safe=True, takeorder=True)
> +def one(repo, subset, x, order):
> +    """An alias for expect(<set>, 1)"""
> +    return expectrevsetsize(repo, subset, x, order, n=1)

Can you remove `one()` from this patch?

I don't follow the original proposal, but I guess `one()` would be meant to
a user-defined alias (i.e. `revsetalias.one(x) = expectsize(x, 1)`).
phabricator - Feb. 7, 2019, 1:18 p.m.
yuja added a comment.


  > +  $ hg log -r 'expectsize(0:2, 3)'
  >  +  changeset:   0:2785f51eece5
  >  +  branch:      a
  >  +  user:        test
  >  +  date:        Thu Jan 01 00:00:00 1970 +0000
  >  +  summary:     0
  
  Nit: the test outputs look unnecessarily verbose. Use `log` (not `hg log`)
  instead.
  
  > +@predicate('expectsize(set[, size])', safe=True, takeorder=True)
  >  +def expectrevsetsize(repo, subset, x, order, n=None):
  >  +    """Abort if the revset doesn't expect given size"""
  >  +    args = getargsdict(x, 'expect', 'set size')
  >  +    size = args.get('size', n)
  >  +    if size is not None:
  >  +        try:
  >  +            # size is given as integer range on expectsize(<set>, <intrange>)
  
  The helper function has been queued. Can you rewrite this to use the
  getintrange helper?
  
  > +        if len(rev) not in range(size[0], size[1]+1):
  
  `range()` builds a list of integers on Python 2, which isn't what we want.
  Python does support `not (x <= y <= z)` syntax, so you can just compare
  integer bounds.
  
  > +@predicate('one(set)', safe=True, takeorder=True)
  >  +def one(repo, subset, x, order):
  >  +    """An alias for expect(<set>, 1)"""
  >  +    return expectrevsetsize(repo, subset, x, order, n=1)
  
  Can you remove `one()` from this patch?
  
  I don't follow the original proposal, but I guess `one()` would be meant to
  a user-defined alias (i.e. `revsetalias.one(x) = expectsize(x, 1)`).

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D5813

To: navaneeth.suresh, #hg-reviewers
Cc: yuja, pulkit, durin42, mjpieters, mercurial-devel

Patch

diff --git a/tests/test-revset.t b/tests/test-revset.t
--- a/tests/test-revset.t
+++ b/tests/test-revset.t
@@ -2950,3 +2950,103 @@ 
   * set:
   <baseset+ [0]>
   0
+
+abort if the revset doesn't expect given size
+  $ hg log -r 'expectsize()'
+  hg: parse error: invalid set of arguments
+  [255]
+  $ hg log -r 'expectsize(0:2, a)'
+  hg: parse error: expectsize requires a size range or a positive integer
+  [255]
+  $ hg log -r 'expectsize(0:2, 3)'
+  changeset:   0:2785f51eece5
+  branch:      a
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     0
+  
+  changeset:   1:d75937da8da0
+  branch:      b
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     1
+  
+  changeset:   2:5ed5505e9f1c
+  branch:      a-b-c-
+  user:        Bob
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+
+  $ hg log -r 'expectsize(2:0, 3)'
+  changeset:   2:5ed5505e9f1c
+  branch:      a-b-c-
+  user:        Bob
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  changeset:   1:d75937da8da0
+  branch:      b
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     1
+  
+  changeset:   0:2785f51eece5
+  branch:      a
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     0
+  
+  $ hg log -r 'expectsize(0:1, 1)'
+  abort: revset size mismatch. expected 1, got 2!
+  [255]
+  $ hg log -r 'expectsize(0:4, -1)'
+  hg: parse error: negative size
+  [255]
+  $ hg log -r 'expectsize(0:2, 2:4)'
+  changeset:   0:2785f51eece5
+  branch:      a
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     0
+  
+  changeset:   1:d75937da8da0
+  branch:      b
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     1
+  
+  changeset:   2:5ed5505e9f1c
+  branch:      a-b-c-
+  user:        Bob
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  $ hg log -r 'expectsize(0:1, 3:5)'
+  abort: revset size mismatch. expected between 3 and 5, got 2!
+  [255]
+  $ hg log -r 'expectsize(0:1, -1:2)'
+  hg: parse error: negative size
+  [255]
+  $ hg log -r 'expectsize(0:1, 1:-2)'
+  hg: parse error: negative size
+  [255]
+  $ hg log -r 'expectsize(0:2, a:4)'
+  hg: parse error: expectsize requires a size range or a positive integer
+  [255]
+  $ hg log -r 'expectsize(0:2, 2:b)'
+  hg: parse error: expectsize requires a size range or a positive integer
+  [255]
+  $ hg log -r 'one()'
+  hg: parse error: invalid set of arguments
+  [255]
+  $ hg log -r 'one(2)'
+  changeset:   2:5ed5505e9f1c
+  branch:      a-b-c-
+  user:        Bob
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  $ hg log -r 'one(0:2)'
+  abort: revset size mismatch. expected 1, got 3!
+  [255]
diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -815,6 +815,55 @@ 
     contentdivergent = obsmod.getrevs(repo, 'contentdivergent')
     return subset & contentdivergent
 
+@predicate('expectsize(set[, size])', safe=True, takeorder=True)
+def expectrevsetsize(repo, subset, x, order, n=None):
+    """Abort if the revset doesn't expect given size"""
+    args = getargsdict(x, 'expect', 'set size')
+    size = args.get('size', n)
+    if size is not None:
+        try:
+            # size is given as integer range on expectsize(<set>, <intrange>)
+            lr = getrange(size, _('expectsize requires a size range '
+                                  'or a positive integer'))
+            minsize, maxsize = [getinteger(a,
+                                _('size range bounds must be integers'))
+                                for a in lr]
+            size = (minsize, maxsize)
+        except error.ParseError:
+            # size is given as integer on expectsize(<set>, <int>)
+            size = getinteger(size,
+                              _('expectsize requires a size range '
+                                'or a positive integer'))
+        except TypeError:
+            # size is 1 on one(<set>)
+            pass
+    if size is None or 'set' not in args:
+        raise error.ParseError(_('invalid set of arguments'))
+    rev = getset(repo, fullreposet(repo), args['set'], order=order)
+    if isinstance(size, tuple):
+        if minsize < 0 or maxsize < 0:
+            raise error.ParseError(_('negative size'))
+        if len(rev) not in range(size[0], size[1]+1):
+            raise error.RepoLookupError(
+                _('revset size mismatch.'
+                ' expected between %d and %d, got %d') % (size[0],
+                                                          size[1],
+                                                          len(rev)))
+    if isinstance(size, int):
+        if size < 0:
+            raise error.ParseError(_('negative size'))
+        if len(rev) != size:
+            raise error.RepoLookupError(
+                _('revset size mismatch.'
+                ' expected %d, got %d') % (size, len(rev)))
+    # filter rev by subset. since we'll probably want to get an ordered
+    # result from expectsize(<set>), we'll have to conditionalize the
+    # filtering direction
+    if order == followorder:
+        return subset & rev
+    else:
+        return rev & subset
+
 @predicate('extdata(source)', safe=False, weight=100)
 def extdata(repo, subset, x):
     """Changesets in the specified extdata source. (EXPERIMENTAL)"""
@@ -1404,6 +1453,11 @@ 
     obsoletes = obsmod.getrevs(repo, 'obsolete')
     return subset & obsoletes
 
+@predicate('one(set)', safe=True, takeorder=True)
+def one(repo, subset, x, order):
+    """An alias for expect(<set>, 1)"""
+    return expectrevsetsize(repo, subset, x, order, n=1)
+
 @predicate('only(set, [set])', safe=True)
 def only(repo, subset, x):
     """Changesets that are ancestors of the first set that are not ancestors