pushlog: add pushid(N) and pushrev(set) revsets (
bug 1295780); r?glandium
We add support for querying for changesets based on their push id
(find changesets in push X) and for changesets in the same push as
a changeset.
MozReview-Commit-ID: 33s1zUtg7SH
--- a/hgext/pushlog/__init__.py
+++ b/hgext/pushlog/__init__.py
@@ -625,16 +625,56 @@ def revset_pushuser(repo, subset, x):
def getrevs():
for push in repo.pushlog.pushes():
if matcher(encoding.lower(push.user)):
for node in push.nodes:
yield repo[node].rev()
return subset & revset.generatorset(getrevs())
+@revsetpredicate('pushid(int)')
+def revset_pushid(repo, subset, x):
+ """Changesets that were part of the specified numeric push id."""
+ l = revset.getargs(x, 1, 1, 'pushid requires one argument')
+ try:
+ pushid = int(revset.getstring(l[0], 'pushid requires a number'))
+ except (TypeError, ValueError):
+ raise error.ParseError('pushid expects a number')
+
+ with repo.pushlog.conn(readonly=True) as conn:
+ push = repo.pushlog.pushfromid(conn, pushid) if conn else None
+
+ if not push:
+ return revset.baseset()
+
+ pushrevs = set()
+ for node in push.nodes:
+ try:
+ pushrevs.add(repo[node].rev())
+ except RepoLookupError:
+ pass
+
+ return subset & pushrevs
+
+@revsetpredicate('pushrev(set)')
+def revset_pushrev(repo, subset, x):
+ """Changesets that were part of the same push as the specified changeset(s)."""
+ l = revset.getset(repo, subset, x)
+
+ # This isn't the most optimal implementation, especially if the input
+ # set is large. But it gets the job done.
+ revs = set()
+ for rev in l:
+ push = repo.pushlog.pushfromchangeset(repo[rev])
+ if push:
+ for node in push.nodes:
+ revs.add(repo[node].rev())
+
+ return subset.filter(revs.__contains__)
+
# Again, for performance reasons we read the entire pushlog database and cache
# the results. Again, this is unfortunate. But, the alternative is a potential
# very expensive series of database lookups.
#
# The justification for doing this for templates is even less than doing it for
# revsets because where revsets typically need to operate on lots of
# changesets, templates typically only render a small handful of changesets.
# Performing a query for each changeset being templatized is an easier pill to
--- a/hgext/pushlog/tests/test-revset.t
+++ b/hgext/pushlog/tests/test-revset.t
@@ -86,8 +86,64 @@ pushuser() does regex matching
$ hg log -r 'pushuser("re:user1")' -T '{rev}\n'
0
pushuser() matching is case insensitive
$ hg log -r 'pushuser(user2@EXAMPLE.COM)' -T '{rev}\n'
1
2
+
+pushid() requires an argument
+
+ $ hg log -r 'pushid()'
+ hg: parse error: pushid requires one argument
+ [255]
+
+pushid() requires an integer argument
+
+ $ hg log -r 'pushid("foo")'
+ hg: parse error: pushid expects a number
+ [255]
+
+pushid() returns revisions part of the specified push
+
+ $ hg log -r 'pushid(1)' -T '{rev}\n'
+ 0
+ $ hg log -r 'pushid(2)' -T '{rev}\n'
+ 1
+ 2
+
+pushid() works with unknown pushid values
+
+ $ hg log -r 'pushid(3)' -T '{rev}\n'
+
+pushid() set intersection works
+
+ $ hg log -r '6c9721b3b4df & pushid(2)' -T '{rev}\n'
+ 1
+
+pushrev() returns an empty set by default
+
+ $ hg log -r 'pushrev()'
+ hg: parse error: missing argument
+ [255]
+
+pushrev() returns values for single revision
+
+ $ hg log -r 'pushrev(55482a6fb4b1)' -T '{rev}\n'
+ 0
+
+ $ hg log -r 'pushrev(6c9721b3b4df)' -T '{rev}\n'
+ 1
+ 2
+
+pushrev() returns values for multiple revisions
+
+ $ hg log -r 'pushrev(0:tip)' -T '{rev}\n'
+ 0
+ 1
+ 2
+
+pushrev() set intersection works
+
+ $ hg log -r '6c9721b3b4df & pushrev(1)' -T '{rev}\n'
+ 1