Patchwork [3,of,4] registrar: add filesetpredicate to mark a function as fileset predicate

login
register
mail settings
Submitter Katsunori FUJIWARA
Date March 9, 2016, 2:29 p.m.
Message ID <94c9f8cd6931758a98ff.1457533749@feefifofum>
Download mbox | patch
Permalink /patch/13722/
State Superseded
Commit 4eb5496c2bd479cb6f059d9fa15fef0e43405a66
Delegated to: Sean Farley
Headers show

Comments

Katsunori FUJIWARA - March 9, 2016, 2:29 p.m.
# HG changeset patch
# User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
# Date 1457533235 -32400
#      Wed Mar 09 23:20:35 2016 +0900
# Node ID 94c9f8cd6931758a98ff8113b30ec9a4bf770f76
# Parent  29d4db42f38fa6cdf75ea794b1fd1c5b2e59b8a8
registrar: add filesetpredicate to mark a function as fileset predicate

filesetpredicate is used to replace fileset.predicate in subsequent
patch.

This patch also adds loadpredicate() to fileset, because this
combination helps to figure out how the name of "status caller" (or
"existing caller") predicate is put into _statuscallers (or
_existingcallers).

Listing up loadpredicate() in dispatch.extraloaders causes implicit
loading fileset predicate functions at loading (3rd party) extension.

Patch

diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
--- a/mercurial/dispatch.py
+++ b/mercurial/dispatch.py
@@ -31,6 +31,7 @@  from . import (
     error,
     extensions,
     fancyopts,
+    fileset,
     hg,
     hook,
     revset,
@@ -753,6 +754,7 @@  def _checkshellalias(lui, ui, args, prec
 #   extraobj) arguments
 extraloaders = [
     ('cmdtable', commands, 'loadcmdtable'),
+    ('filesetpredicate', fileset, 'loadpredicate'),
     ('revsetpredicate', revset, 'loadpredicate'),
 ]
 
diff --git a/mercurial/fileset.py b/mercurial/fileset.py
--- a/mercurial/fileset.py
+++ b/mercurial/fileset.py
@@ -560,5 +560,15 @@  def getfileset(ctx, expr):
 def prettyformat(tree):
     return parser.prettyformat(tree, ('string', 'symbol'))
 
+def loadpredicate(ui, extname, registrarobj):
+    """Load fileset predicates from specified registrarobj
+    """
+    for name, func in registrarobj._table.iteritems():
+        symbols[name] = func
+        if func._callstatus:
+            _statuscallers.add(name)
+        if func._callexisting:
+            _existingcallers.add(name)
+
 # tell hggettext to extract docstrings from these functions:
 i18nfunctions = symbols.values()
diff --git a/mercurial/registrar.py b/mercurial/registrar.py
--- a/mercurial/registrar.py
+++ b/mercurial/registrar.py
@@ -122,3 +122,42 @@  class revsetpredicate(_funcregistrarbase
 
     def _extrasetup(self, name, func, safe=False):
         func._safe = safe
+
+class filesetpredicate(_funcregistrarbase):
+    """Decorator to register fileset predicate
+
+    Usage::
+
+        filesetpredicate = registrar.filesetpredicate()
+
+        @filesetpredicate('mypredicate()')
+        def mypredicatefunc(mctx, x):
+            '''Explanation of this fileset predicate ....
+            '''
+            pass
+
+    The first string argument is used also in online help.
+
+    Optional argument 'callstatus' indicates whether a predicate
+     implies 'matchctx.status()' at runtime or not (False, by
+     default).
+
+    Optional argument 'callexisting' indicates whether a predicate
+    implies 'matchctx.existing()' at runtime or not (False, by
+    default).
+
+    'filesetpredicate' instance in example above can be used to
+    decorate multiple functions.
+
+    Decorated functions are registered automatically at loading
+    extension, if an instance named as 'filesetpredicate' is used for
+    decorating in extension.
+
+    Otherwise, explicit 'fileset.loadpredicate()' is needed.
+    """
+    _getname = _funcregistrarbase._parsefuncdecl
+    _docformat = "``%s``\n    %s"
+
+    def _extrasetup(self, name, func, callstatus=False, callexisting=False):
+        func._callstatus = callstatus
+        func._callexisting = callexisting
diff --git a/tests/test-fileset.t b/tests/test-fileset.t
--- a/tests/test-fileset.t
+++ b/tests/test-fileset.t
@@ -351,9 +351,10 @@  Test safety of 'encoding' on removed fil
 Test detection of unintentional 'matchctx.existing()' invocation
 
   $ cat > $TESTTMP/existingcaller.py <<EOF
-  > from mercurial import fileset
+  > from mercurial import registrar
   > 
-  > @fileset.predicate('existingcaller()', callexisting=False)
+  > filesetpredicate = registrar.filesetpredicate()
+  > @filesetpredicate('existingcaller()', callexisting=False)
   > def existingcaller(mctx, x):
   >     # this 'mctx.existing()' invocation is unintentional
   >     return [f for f in mctx.existing()]