hgext3rd/topic/revset.py
branchmercurial-4.5
changeset 4075 dc247e648f43
parent 4064 a2c0133006c6
child 4095 aabf436c11cb
--- a/hgext3rd/topic/revset.py	Tue Aug 28 11:24:50 2018 +0200
+++ b/hgext3rd/topic/revset.py	Mon Sep 03 22:05:12 2018 +0200
@@ -1,13 +1,13 @@
 from __future__ import absolute_import
 
 from mercurial import (
+    error,
     registrar,
     revset,
     util,
 )
 
 from . import (
-    constants,
     destination,
     stack,
 )
@@ -23,36 +23,64 @@
 
 revsetpredicate = registrar.revsetpredicate()
 
-@revsetpredicate('topic([topic])')
-def topicset(repo, subset, x):
-    """Specified topic or all changes with any topic specified.
+def getstringstrict(x, err):
+    if x and (x[0] == 'string'):
+        return x[1]
+    raise error.ParseError(err)
 
-    If `topic` starts with `re:` the remainder of the name is treated
+@revsetpredicate('topic([string or set])')
+def topicset(repo, subset, x):
+    """All changesets with the specified topic or the topics of the given
+    changesets. Without the argument, all changesets with any topic specified.
+
+    If `string` starts with `re:` the remainder of the name is treated
     as a regular expression.
-
-    TODO: make `topic(revset)` work the same as `branch(revset)`.
     """
     args = revset.getargs(x, 0, 1, 'topic takes one or no arguments')
-    if args:
-        # match a specific topic
-        topic = revset.getstring(args[0], 'topic() argument must be a string')
-        if topic == '.':
-            topic = repo['.'].extra().get('topic', '')
-        _kind, _pattern, matcher = mkmatcher(topic)
-    else:
-        matcher = lambda t: bool(t)
 
     mutable = revset._notpublic(repo, revset.fullreposet(repo), ())
 
-    rawchange = repo.changelog.changelogrevision
-    key = constants.extrakey
+    if not args:
+        return (subset & mutable).filter(lambda r: bool(repo[r].topic()))
+
+    try:
+        topic = getstringstrict(args[0], '')
+    except error.ParseError:
+        # not a string, but another revset
+        pass
+    else:
+        kind, pattern, matcher = mkmatcher(topic)
+
+        def matches(r):
+            topic = repo[r].topic()
+            if not topic:
+                return False
+            return matcher(topic)
+
+        if kind == 'literal':
+            # note: falls through to the revset case if no topic with this name
+            # exists and pattern kind is not specified explicitly
 
-    def matchtopic(r):
-        topic = rawchange(r).extra.get(key)
-        if topic is None:
+            if pattern not in repo.topics and topic.startswith('literal:'):
+                raise error.RepoLookupError("topic '%s' does not exist"
+                                            % pattern)
+            return (subset & mutable).filter(matches)
+        else:
+            return (subset & mutable).filter(matches)
+
+    s = revset.getset(repo, revset.fullreposet(repo), x)
+    topics = set(repo[r].topic() for r in s)
+    topics.discard('')
+
+    def matches(r):
+        if r in s:
+            return True
+        topic = repo[r].topic()
+        if not topic:
             return False
-        return matcher(topic)
-    return (subset & mutable).filter(matchtopic)
+        return topic in topics
+
+    return (subset & mutable).filter(matches)
 
 @revsetpredicate('ngtip([branch])')
 def ngtipset(repo, subset, x):