view mercurial/registrar.py @ 27766:198f78a52a2f

util: adjust hgcmd() to handle frozen Mercurial on OS X Previously, 'hg serve -d' was trying to exec the bundled python executable, which failed with: Unknown option: -- usage: python [option] ... Try 'python -h'... abort: child process failed to start See the previous patch for details about the content of the various command variables. Note that unlike the previous patch here an application bundling Mercurial could set $HG in the environment to get the correct result, there isn't anything that a bundling application could do to get the correct result here. 'hg serve -d' now launches under TortoiseHg, and there is a process listed in the background, but a client process cannot connect to it for some reason, so more investigation is needed.
author Matt Harbison <matt_harbison@yahoo.com>
date Sun, 10 Jan 2016 18:15:39 -0500
parents 60bf90eb8bf8
children b983a2f04987
line wrap: on
line source

# registrar.py - utilities to register function for specific purpose
#
#  Copyright FUJIWARA Katsunori <foozy@lares.dti.ne.jp> and others
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

from __future__ import absolute_import

from . import (
    util,
)

class funcregistrar(object):
    """Base of decorator to register a fuction for specific purpose

    The least derived class can be defined by overriding 'table' and
    'formatdoc', for example::

        symbols = {}
        class keyword(funcregistrar):
            table = symbols
            formatdoc = ":%s: %s"

        @keyword('bar')
        def barfunc(*args, **kwargs):
            '''Explanation of bar keyword ....
            '''
            pass

    In this case:

    - 'barfunc' is registered as 'bar' in 'symbols'
    - online help uses ":bar: Explanation of bar keyword"
    """

    def __init__(self, decl):
        """'decl' is a name or more descriptive string of a function

        Specification of 'decl' depends on registration purpose.
        """
        self.decl = decl

    table = None

    def __call__(self, func):
        """Execute actual registration for specified function
        """
        name = self.getname()

        if func.__doc__ and not util.safehasattr(func, '_origdoc'):
            doc = func.__doc__.strip()
            func._origdoc = doc
            if callable(self.formatdoc):
                func.__doc__ = self.formatdoc(doc)
            else:
                # convenient shortcut for simple format
                func.__doc__ = self.formatdoc % (self.decl, doc)

        self.table[name] = func
        self.extraaction(name, func)

        return func

    def getname(self):
        """Return the name of the registered function from self.decl

        Derived class should override this, if it allows more
        descriptive 'decl' string than just a name.
        """
        return self.decl

    def parsefuncdecl(self):
        """Parse function declaration and return the name of function in it
        """
        i = self.decl.find('(')
        if i > 0:
            return self.decl[:i]
        else:
            return self.decl

    def formatdoc(self, doc):
        """Return formatted document of the registered function for help

        'doc' is '__doc__.strip()' of the registered function.

        If this is overridden by non-callable object in derived class,
        such value is treated as "format string" and used to format
        document by 'self.formatdoc % (self.decl, doc)' for convenience.
        """
        raise NotImplementedError()

    def extraaction(self, name, func):
        """Execute exra action for registered function, if needed
        """
        pass

class delayregistrar(object):
    """Decorator to delay actual registration until uisetup or so

    For example, the decorator class to delay registration by
    'keyword' funcregistrar can be defined as below::

        class extkeyword(delayregistrar):
            registrar = keyword
    """
    def __init__(self):
        self._list = []

    registrar = None

    def __call__(self, *args, **kwargs):
        """Return the decorator to delay actual registration until setup
        """
        assert self.registrar is not None
        def decorator(func):
            # invocation of self.registrar() here can detect argument
            # mismatching immediately
            self._list.append((func, self.registrar(*args, **kwargs)))
            return func
        return decorator

    def setup(self):
        """Execute actual registration
        """
        while self._list:
            func, decorator = self._list.pop(0)
            decorator(func)