mercurial/extensions.py
author Alexander Solovyov <piranha@piranha.org.ua>
Fri, 27 Mar 2009 01:28:09 +0200
changeset 7916 f779e1996e23
parent 7876 53c72ba36c2b
child 7960 5c794e7331e7
permissions -rw-r--r--
ability to load hooks from arbitrary python module
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     1
# extensions.py - extension handling for mercurial
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     2
#
4635
63b9d2deed48 Updated copyright notices and add "and others" to "hg version"
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4633
diff changeset
     3
# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     4
#
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     6
# of the GNU General Public License, incorporated herein by reference.
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     7
4569
622d8ed78b47 extensions: load modules in module/__init__.py form.
Brendan Cully <brendan@kublai.com>
parents: 4558
diff changeset
     8
import imp, os
7215
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
     9
import util, cmdutil
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    10
from i18n import _
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    11
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    12
_extensions = {}
5192
60acf1432ee0 Move cmdtable and reposetup handling out of extensions.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5152
diff changeset
    13
_order = []
60acf1432ee0 Move cmdtable and reposetup handling out of extensions.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5152
diff changeset
    14
60acf1432ee0 Move cmdtable and reposetup handling out of extensions.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5152
diff changeset
    15
def extensions():
60acf1432ee0 Move cmdtable and reposetup handling out of extensions.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5152
diff changeset
    16
    for name in _order:
60acf1432ee0 Move cmdtable and reposetup handling out of extensions.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5152
diff changeset
    17
        module = _extensions[name]
60acf1432ee0 Move cmdtable and reposetup handling out of extensions.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5152
diff changeset
    18
        if module:
60acf1432ee0 Move cmdtable and reposetup handling out of extensions.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5152
diff changeset
    19
            yield name, module
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    20
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    21
def find(name):
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    22
    '''return module with given extension name'''
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    23
    try:
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    24
        return _extensions[name]
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    25
    except KeyError:
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    26
        for k, v in _extensions.iteritems():
4560
3daed3680554 extensions: fix lookup of hgext.foo modules
Matt Mackall <mpm@selenic.com>
parents: 4558
diff changeset
    27
            if k.endswith('.' + name) or k.endswith('/' + name):
3daed3680554 extensions: fix lookup of hgext.foo modules
Matt Mackall <mpm@selenic.com>
parents: 4558
diff changeset
    28
                return v
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    29
        raise KeyError(name)
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    30
7916
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    31
def loadpath(path, module_name):
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    32
    module_name = module_name.replace('.', '_')
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    33
    path = os.path.expanduser(path)
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    34
    if os.path.isdir(path):
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    35
        # module/__init__.py style
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    36
        d, f = os.path.split(path)
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    37
        fd, fpath, desc = imp.find_module(f, [d])
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    38
        return imp.load_module(module_name, fd, fpath, desc)
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    39
    else:
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    40
        return imp.load_source(module_name, path)
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    41
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    42
def load(ui, name, path):
7011
7da76778dbd7 Do not try to load extensions twice (issue811)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 6212
diff changeset
    43
    if name.startswith('hgext.') or name.startswith('hgext/'):
5031
af0995261f02 extensions: don't get confused by aliasing between "foo" and "hgext.foo"
Bryan O'Sullivan <bos@serpentine.com>
parents: 4818
diff changeset
    44
        shortname = name[6:]
af0995261f02 extensions: don't get confused by aliasing between "foo" and "hgext.foo"
Bryan O'Sullivan <bos@serpentine.com>
parents: 4818
diff changeset
    45
    else:
af0995261f02 extensions: don't get confused by aliasing between "foo" and "hgext.foo"
Bryan O'Sullivan <bos@serpentine.com>
parents: 4818
diff changeset
    46
        shortname = name
af0995261f02 extensions: don't get confused by aliasing between "foo" and "hgext.foo"
Bryan O'Sullivan <bos@serpentine.com>
parents: 4818
diff changeset
    47
    if shortname in _extensions:
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    48
        return
5087
b3cc62268a91 Cache extension load failures.
Brendan Cully <brendan@kublai.com>
parents: 4635
diff changeset
    49
    _extensions[shortname] = None
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    50
    if path:
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    51
        # the module will be loaded in sys.modules
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    52
        # choose an unique name so that it doesn't
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    53
        # conflicts with other modules
7916
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    54
        mod = loadpath(path, 'hgext.%s' % name)
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    55
    else:
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    56
        def importh(name):
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    57
            mod = __import__(name)
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    58
            components = name.split('.')
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    59
            for comp in components[1:]:
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    60
                mod = getattr(mod, comp)
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    61
            return mod
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    62
        try:
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    63
            mod = importh("hgext.%s" % name)
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    64
        except ImportError:
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    65
            mod = importh(name)
5031
af0995261f02 extensions: don't get confused by aliasing between "foo" and "hgext.foo"
Bryan O'Sullivan <bos@serpentine.com>
parents: 4818
diff changeset
    66
    _extensions[shortname] = mod
5192
60acf1432ee0 Move cmdtable and reposetup handling out of extensions.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5152
diff changeset
    67
    _order.append(shortname)
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    68
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    69
    uisetup = getattr(mod, 'uisetup', None)
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    70
    if uisetup:
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    71
        uisetup(ui)
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    72
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    73
def loadall(ui):
4617
669e76b7df24 extensions: pull extension-aware bits out of ui
Matt Mackall <mpm@selenic.com>
parents: 4582
diff changeset
    74
    result = ui.configitems("extensions")
7876
53c72ba36c2b cleanup: drop enumerate() when index is not used
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7644
diff changeset
    75
    for (name, path) in result:
4617
669e76b7df24 extensions: pull extension-aware bits out of ui
Matt Mackall <mpm@selenic.com>
parents: 4582
diff changeset
    76
        if path:
5469
b12432b1c2c7 Allow explicit disabling of extensions
Steve Borho <steve@borho.org>
parents: 5192
diff changeset
    77
            if path[0] == '!':
b12432b1c2c7 Allow explicit disabling of extensions
Steve Borho <steve@borho.org>
parents: 5192
diff changeset
    78
                continue
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    79
        try:
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    80
            load(ui, name, path)
7644
182b7114d35a error: move SignalInterrupt
Matt Mackall <mpm@selenic.com>
parents: 7388
diff changeset
    81
        except KeyboardInterrupt:
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    82
            raise
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    83
        except Exception, inst:
6204
f8a86ea7521b When failing to load an extension, show where Hg tried to load it from.
Jesse Glick <jesse.glick@sun.com>
parents: 5469
diff changeset
    84
            if path:
f8a86ea7521b When failing to load an extension, show where Hg tried to load it from.
Jesse Glick <jesse.glick@sun.com>
parents: 5469
diff changeset
    85
                ui.warn(_("*** failed to import extension %s from %s: %s\n")
f8a86ea7521b When failing to load an extension, show where Hg tried to load it from.
Jesse Glick <jesse.glick@sun.com>
parents: 5469
diff changeset
    86
                        % (name, path, inst))
f8a86ea7521b When failing to load an extension, show where Hg tried to load it from.
Jesse Glick <jesse.glick@sun.com>
parents: 5469
diff changeset
    87
            else:
f8a86ea7521b When failing to load an extension, show where Hg tried to load it from.
Jesse Glick <jesse.glick@sun.com>
parents: 5469
diff changeset
    88
                ui.warn(_("*** failed to import extension %s: %s\n")
f8a86ea7521b When failing to load an extension, show where Hg tried to load it from.
Jesse Glick <jesse.glick@sun.com>
parents: 5469
diff changeset
    89
                        % (name, inst))
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    90
            if ui.print_exc():
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    91
                return 1
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    92
7215
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
    93
def wrapcommand(table, command, wrapper):
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
    94
    aliases, entry = cmdutil.findcmd(command, table)
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
    95
    for alias, e in table.iteritems():
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
    96
        if e is entry:
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
    97
            key = alias
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
    98
            break
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
    99
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   100
    origfn = entry[0]
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   101
    def wrap(*args, **kwargs):
7388
5751631246de dispatch: generalize signature checking for extension command wrapping
Matt Mackall <mpm@selenic.com>
parents: 7373
diff changeset
   102
        return util.checksignature(wrapper)(
5751631246de dispatch: generalize signature checking for extension command wrapping
Matt Mackall <mpm@selenic.com>
parents: 7373
diff changeset
   103
            util.checksignature(origfn), *args, **kwargs)
7215
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   104
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   105
    wrap.__doc__ = getattr(origfn, '__doc__')
7373
d9e9dd2b00fb extensions: copy __module__ for wrapped commands
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 7215
diff changeset
   106
    wrap.__module__ = getattr(origfn, '__module__')
7215
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   107
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   108
    newentry = list(entry)
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   109
    newentry[0] = wrap
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   110
    table[key] = tuple(newentry)
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   111
    return entry
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   112
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   113
def wrapfunction(container, funcname, wrapper):
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   114
    def wrap(*args, **kwargs):
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   115
        return wrapper(origfn, *args, **kwargs)
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   116
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   117
    origfn = getattr(container, funcname)
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   118
    setattr(container, funcname, wrap)
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   119
    return origfn