mozext: use modern revset APIs (bug 1228088); r=dminor draft
authorGregory Szorc <gps@mozilla.com>
Wed, 02 Mar 2016 12:08:49 -0800
changeset 7418 a5788d4cafeeefc55729b98450300662c05afbfc
parent 7417 2893a7c38300204dcb32f639ac496a1a1fbc0004
child 7419 18982d7c7f4d8459d2aa5ed492088ca2c89b737a
push id675
push usergszorc@mozilla.com
push dateWed, 02 Mar 2016 22:08:21 +0000
reviewersdminor
bugs1228088
mozext: use modern revset APIs (bug 1228088); r=dminor Mercurial 3.7 is issuing warnings when running tests that the revset functions in mozext are returning lists instead of revset classes. mozext was one of the first Mercurial extensions I wrote. It is one of the oldest and doesn't exactly contain the best patterns or modern API usage. This commit brings the revset code into the modern age. Most of the changes involve calling subset.filter() to lazily evaluate a revset. Before, we iterated over the subset, which meant that we had to evaluate every element before returning. This almost certainly made a number of revset queries slower than they should have been. MozReview-Commit-ID: 6mmWIXgfEAo
hgext/mozext/__init__.py
--- a/hgext/mozext/__init__.py
+++ b/hgext/mozext/__init__.py
@@ -874,28 +874,30 @@ def revset_bug(repo, subset, x):
     err = _('bug() requires an integer argument.')
     bugstring = revset.getstring(x, err)
 
     try:
         bug = int(bugstring)
     except Exception:
         raise ParseError(err)
 
-    # We do a simple string test first because avoiding regular expressions
-    # is good for performance.
-    return [r for r in subset
-            if bugstring in repo[r].description() and
-                bug in parse_bugs(repo[r].description())]
+    def fltr(x):
+        # We do a simple string test first because avoiding regular expressions
+        # is good for performance.
+        desc = repo[x].description()
+        return bugstring in desc and bug in parse_bugs(desc)
+
+    return subset.filter(fltr)
 
 
 def revset_dontbuild(repo, subset, x):
     if x:
         raise ParseError(_('dontbuild() does not take any arguments'))
 
-    return [r for r in subset if 'DONTBUILD' in repo[r].description()]
+    return subset.filter(lambda x: 'DONTBUILD' in repo[x].description())
 
 
 def revset_me(repo, subset, x):
     """``me()``
     Changesets that you are involved in.
     """
     if x:
         raise ParseError(_('me() does not take any arguments'))
@@ -904,36 +906,31 @@ def revset_me(repo, subset, x):
     if not me:
         raise util.Abort(_('"[ui] username" must be set to use me()'))
 
     ircnick = get_ircnick(repo.ui)
 
     n = encoding.lower(me)
     kind, pattern, matcher = revset._substringmatcher(n)
 
-    revs = []
-
-    for r in subset:
-        ctx = repo[r]
+    def fltr(x):
+        ctx = repo[x]
         if matcher(encoding.lower(ctx.user())):
-            revs.append(r)
-            continue
+            return True
 
-        if ircnick in parse_reviewers(ctx.description()):
-            revs.append(r)
-            continue
+        return ircnick in parse_reviewers(ctx.description())
 
-    return revs
+    return subset.filter(fltr)
 
 
 def revset_nobug(repo, subset, x):
     if x:
         raise ParseError(_('nobug() does not take any arguments'))
 
-    return [r for r in subset if not parse_bugs(repo[r].description())]
+    return subset.filter(lambda x: not parse_bugs(repo[x].description()))
 
 
 def revset_tree(repo, subset, x):
     """``tree(X)``
     Changesets currently in the specified Mozilla tree.
 
     A tree is the name of a repository. e.g. ``central``.
     """
@@ -944,87 +941,80 @@ def revset_tree(repo, subset, x):
     if not uri:
         raise util.Abort(_("Don't know about tree: %s") % tree)
 
     ref = '%s/default' % tree
 
     head = repo[ref].rev()
     ancestors = set(repo.changelog.ancestors([head], inclusive=True))
 
-    return [r for r in subset if r in ancestors]
+    return subset & revset.baseset(ancestors)
 
 
 def revset_firstpushdate(repo, subset, x):
     """``firstpushdate(DATE)``
     Changesets that were initially pushed according to the date spec provided.
     """
     ds = revset.getstring(x, _('firstpushdate() requires a string'))
     dm = util.matchdate(ds)
 
-    revs = []
-
-    for rev in subset:
-        pushes = list(repo.changetracker.pushes_for_changeset(repo[rev].node()))
+    def fltr(x):
+        pushes = list(repo.changetracker.pushes_for_changeset(repo[x].node()))
 
         if not pushes:
-            continue
+            return False
 
         when = pushes[0][2]
 
-        if dm(when):
-            revs.append(rev)
+        return dm(when)
 
-    return revs
+    return subset.filter(fltr)
 
 
 def revset_firstpushtree(repo, subset, x):
     """``firstpushtree(X)``
     Changesets that were initially pushed to tree X.
     """
     tree = revset.getstring(x, _('firstpushtree() requires a string argument.'))
 
     tree, uri = resolve_trees_to_uris([tree])[0]
     if not uri:
         raise util.Abort(_("Don't know about tree: %s") % tree)
 
-    revs = []
-
-    for rev in subset:
+    def fltr(x):
         pushes = list(repo.changetracker.pushes_for_changeset(
-            repo[rev].node()))
+            repo[x].node()))
 
         if not pushes:
-            continue
+            return False
 
-        if pushes[0][0] == tree:
-            revs.append(rev)
+        return pushes[0][0] == tree
 
-    return revs
+    return subset.filter(fltr)
 
 
 def revset_pushdate(repo, subset, x):
     """``pushdate(DATE)``
     Changesets that were pushed according to the date spec provided.
 
     All pushes are examined.
     """
     ds = revset.getstring(x, _('pushdate() requires a string'))
     dm = util.matchdate(ds)
 
-    revs = []
-
-    for rev in subset:
-        for push in repo.changetracker.pushes_for_changeset(repo[rev].node()):
+    def fltr(x):
+        for push in repo.changetracker.pushes_for_changeset(repo[x].node()):
             when = push[2]
 
             if dm(when):
-                revs.append(rev)
-                break
+                return True
 
-    return revs
+        return False
+
+    return subset.filter(fltr)
 
 
 def revset_pushhead(repo, subset, x):
     """``pushhead([TREE])``
     Changesets that are push heads.
 
     A push head is a changeset that was a head when it was pushed to a
     repository. In other words, the automation infrastructure likely
@@ -1070,27 +1060,27 @@ def revset_pushhead(repo, subset, x):
 
 
 def revset_reviewer(repo, subset, x):
     """``reviewer(REVIEWER)``
     Changesets reviewed by a specific person.
     """
     n = revset.getstring(x, _('reviewer() requires a string argument.'))
 
-    return [r for r in subset if n in parse_reviewers(repo[r].description())]
+    return subset.filter(lambda x: n in parse_reviewers(repo[x].description()))
 
 
 def revset_reviewed(repo, subset, x):
     """``reviewed()``
     Changesets that were reviewed.
     """
     if x:
         raise ParseError(_('reviewed() does not take an argument'))
 
-    return [r for r in subset if list(parse_reviewers(repo[r].description()))]
+    return subset.filter(lambda x: list(parse_reviewers(repo[x].description())))
 
 
 def template_bug(repo, ctx, **args):
     """:bug: String. The bug this changeset is most associated with."""
     bugs = parse_bugs(ctx.description())
     return bugs[0] if bugs else None