[PATCH 2 of 5 RFC] revset: add a predicate for finding transplants

Matt Harbison matt_harbison at yahoo.com
Mon May 14 00:30:00 CDT 2012


# HG changeset patch
# User Matt Harbison <matt_harbison at yahoo.com>
# Date 1336883077 14400
# Node ID eabdd37ccf00e44c0f94c2494fa82f5dce773e2a
# Parent  f4e3289b34bc781abb648148e6e328285ecc4301
revset: add a predicate for finding transplants

This selects changesets added because of transplants.  If a revision is
specified, the set will be empty if that revision is not the source of a
transplant, or it will contain a destination changeset for each time the
specified revision was transplanted.  This can be useful for figuring out where
a particular changeset has been propagated.

The source revision may be a local identifier, the short changeset hash or the
full hash.  The revision must exist, or the query is aborted.

I added this (and the rest of the series) to core instead of the individual
extensions because they don't use any code in the extensions, and I think it is
reasonable for a user that does not have these extensions enabled to pull from
someone that does and be able to query for this info.  Convert is probably the
most likely example of this.

I noticed after I created this that the transplant extension already has a
'transplanted' predicate (so I had to rename this one, and then the rest to be
consistent).  There's overlap with this and transplant's version when no
revision is specified: both select all of the changesets created because of a
transplant.  But when a revision is provided, transplant's version only selects
that specified revision if it was created because of a transplant.  i.e. it
seems to only answer 'was rev x transplanted from somewhere?' This patch takes
a revision and reports where it ended up.

Test cases to follow if these are generally useful/acceptable.

Questions:
- Is not living in the extensions OK?
- Is the name distinct enough from transplant's 'transplanted()' form to be
  useful?
- Since both predicates without a revision select the destination changesets,
  there's nothing to find all nodes that are transplant sources.  Should I add
  one more predicate to select the source or all sources?  I can't think of a
  good name. (I suppose this applies to all except convert).
- Given that the goal is to find where a changeset is propagated, it didn't
  seem to make sense to support taking in a set.  Or should it use
  revset.getset() anyway and make sure the size is 1 if a rev is provided?
  rev() and id() didn't take this route.
- Depending on the previous question, is it wise to abort if the revision can't
  be found?  I'm not sure how the user would know the rev value if it isn't
  present (e.g. been stripped), so it seems like a useful sanity check.

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -1138,6 +1138,26 @@
 def tagged(repo, subset, x):
     return tag(repo, subset, x)
 
+def transplantof(repo, subset, x):
+    """``transplantof([rev])``
+    Changesets transplanted from rev, or all transplanted changesets.
+    """
+
+    # i18n: "transplantof" is a keyword
+    l = getargs(x, 0, 1, _('transplantof takes one or no arguments'))
+
+    # i18n: "transplantof" is a keyword
+    rev = l and getrev(repo, l[0], _('transplantof requires a revision')) or None
+
+    def _matchvalue(r):
+        source = repo[r].extra().get('transplant_source', None)
+        if source is not None:
+            source = binascii.hexlify(source)
+
+        return source is not None and (rev is None or rev == source)
+
+    return [r for r in subset if _matchvalue(r)]
+
 def user(repo, subset, x):
     """``user(string)``
     User name contains string. The match is case-insensitive.
@@ -1207,6 +1227,7 @@
     "matching": matching,
     "tag": tag,
     "tagged": tagged,
+    "transplantof": transplantof,
     "user": user,
     "_list": _list,
 }


More information about the Mercurial-devel mailing list