[PATCH] filemerge: move decorator definition for internal merge tools to registrar

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Sat Aug 5 18:51:49 UTC 2017


# HG changeset patch
# User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
# Date 1501949637 -32400
#      Sun Aug 06 01:13:57 2017 +0900
# Node ID 2430ac5b30e11c6cdc7309b3c2741cd3878b4b36
# Parent  93422d0068f8979b33a02e5003fd4b6c23413361
# Available At https://bitbucket.org/foozy/mercurial-wip
#              hg pull https://bitbucket.org/foozy/mercurial-wip -r 2430ac5b30e1
# EXP-Topic filemerge-refactor
filemerge: move decorator definition for internal merge tools to registrar

This patch also adds extra loading entry for internal merge tools to
extensions.py, for similarity to other decorators defined in
registrar.py.

This patch uses "internalmerge" for decorator class name, instead of
original "internaltool", because the latter is too generic.

BTW, after this patch, 4-spaces indentation is added to the 1st line
of internal merge tool description docstring, and this may make
already translated entries in *.po fuzzy.

Even though this indentation is required for "definition list" in reST
syntax, absence of it has been overlooked, because help.makeitemsdoc()
forcibly inserts it at generation of online help.

But this forcible insertion causes formatting issue (I'll send another
patch series for this). Therefore, this additional indentation should
be reasonable.

diff --git a/mercurial/extensions.py b/mercurial/extensions.py
--- a/mercurial/extensions.py
+++ b/mercurial/extensions.py
@@ -250,6 +250,7 @@ def loadall(ui, whitelist=None):
     from . import (
         color,
         commands,
+        filemerge,
         fileset,
         revset,
         templatefilters,
@@ -268,6 +269,7 @@ def loadall(ui, whitelist=None):
         ('colortable', color, 'loadcolortable'),
         ('configtable', configitems, 'loadconfigtable'),
         ('filesetpredicate', fileset, 'loadpredicate'),
+        ('internalmerge', filemerge, 'loadinternalmerge'),
         ('revsetpredicate', revset, 'loadpredicate'),
         ('templatefilter', templatefilters, 'loadfilter'),
         ('templatefunc', templater, 'loadfunction'),
diff --git a/mercurial/filemerge.py b/mercurial/filemerge.py
--- a/mercurial/filemerge.py
+++ b/mercurial/filemerge.py
@@ -21,6 +21,7 @@ from . import (
     formatter,
     match,
     pycompat,
+    registrar,
     scmutil,
     simplemerge,
     tagmerge,
@@ -44,10 +45,12 @@ internals = {}
 # Merge tools to document.
 internalsdoc = {}
 
+internaltool = registrar.internalmerge()
+
 # internal tool merge types
-nomerge = None
-mergeonly = 'mergeonly'  # just the full merge, no premerge
-fullmerge = 'fullmerge'  # both premerge and merge
+nomerge = internaltool.nomerge
+mergeonly = internaltool.mergeonly # just the full merge, no premerge
+fullmerge = internaltool.fullmerge # both premerge and merge
 
 _localchangedotherdeletedmsg = _(
     "local%(l)s changed %(fd)s which other%(o)s deleted\n"
@@ -104,21 +107,6 @@ class absentfilectx(object):
     def isabsent(self):
         return True
 
-def internaltool(name, mergetype, onfailure=None, precheck=None):
-    '''return a decorator for populating internal merge tool table'''
-    def decorator(func):
-        fullname = ':' + name
-        func.__doc__ = (pycompat.sysstr("``%s``\n" % fullname)
-                        + func.__doc__.strip())
-        internals[fullname] = func
-        internals['internal:' + name] = func
-        internalsdoc[fullname] = func
-        func.mergetype = mergetype
-        func.onfailure = onfailure
-        func.precheck = precheck
-        return func
-    return decorator
-
 def _findtool(ui, tool):
     if tool in internals:
         return tool
@@ -743,5 +731,17 @@ def premerge(repo, mynode, orig, fcd, fc
 def filemerge(repo, mynode, orig, fcd, fco, fca, labels=None):
     return _filemerge(False, repo, mynode, orig, fcd, fco, fca, labels=labels)
 
+def loadinternalmerge(ui, extname, registrarobj):
+    """Load internal merge tool from specified registrarobj
+    """
+    for name, func in registrarobj._table.iteritems():
+        fullname = ':' + name
+        internals[fullname] = func
+        internals['internal:' + name] = func
+        internalsdoc[fullname] = func
+
+# load built-in merge tools explicitly to setup internalsdoc
+loadinternalmerge(None, None, internaltool)
+
 # tell hggettext to extract docstrings from these functions:
 i18nfunctions = internals.values()
diff --git a/mercurial/registrar.py b/mercurial/registrar.py
--- a/mercurial/registrar.py
+++ b/mercurial/registrar.py
@@ -308,3 +308,64 @@ class templatefunc(_templateregistrarbas
 
     def _extrasetup(self, name, func, argspec=None):
         func._argspec = argspec
+
+class internalmerge(_funcregistrarbase):
+    """Decorator to register in-process merge tool
+
+    Usage::
+
+        internalmerge = registrar.internalmerge()
+
+        @internalmerge('mymerge', internalmerge.mergeonly,
+                       onfailure=None, precheck=None):
+        def mymergefunc(repo, mynode, orig, fcd, fco, fca,
+                        toolconf, files, labels=None):
+            '''Explanation of this internal merge tool ....
+            '''
+            return 1, False # means "conflicted", "no deletion needed"
+
+    The first string argument is used to compose actual merge tool name,
+    ":name" and "internal:name" (the latter is historical one).
+
+    The second argument is one of merge types below:
+
+    ========== ======== ======== =========
+    merge type precheck premerge fullmerge
+    ========== ======== ======== =========
+    nomerge     x        x        x
+    mergeonly   o        x        o
+    fullmerge   o        o        o
+    ========== ======== ======== =========
+
+    Optional argument 'onfalure' is the format of warning message
+    to be used at failure of merging (target filename is specified
+    at formatting). Or, None or so, if warning message should be
+    suppressed.
+
+    Optional argument 'precheck' is the function to be used
+    before actual invocation of internal merge tool itself.
+    It takes as same arguments as internal merge tool does, other than
+    'files' and 'labels'. If it returns false value, merging is aborted
+    immediately (and file is marked as "unresolved").
+
+    'internalmerge' instance in example above can be used to
+    decorate multiple functions.
+
+    Decorated functions are registered automatically at loading
+    extension, if an instance named as 'internalmerge' is used for
+    decorating in extension.
+
+    Otherwise, explicit 'filemerge.loadinternalmerge()' is needed.
+    """
+    _docformat = "``:%s``\n    %s"
+
+    # merge type definitions:
+    nomerge = None
+    mergeonly = 'mergeonly'  # just the full merge, no premerge
+    fullmerge = 'fullmerge'  # both premerge and merge
+
+    def _extrasetup(self, name, func, mergetype,
+                    onfailure=None, precheck=None):
+        func.mergetype = mergetype
+        func.onfailure = onfailure
+        func.precheck = precheck


More information about the Mercurial-devel mailing list