mercurial/extensions.py
author Paul Morelle <paul.morelle@octobus.net>
Tue, 19 Jun 2018 15:03:58 +0200
changeset 38634 f0ea8b847831
parent 38350 c6f82a18a63d
child 38727 fcb517ff9562
permissions -rw-r--r--
revlog: early return in _slicechunk when density is already good We don't need to do anything if we know we won't enter the second while loop. Save the overhead of the first loop by returning earlier.
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
#
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8206
diff changeset
     5
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9679
diff changeset
     6
# GNU General Public License version 2 or any later version.
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     7
25946
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     8
from __future__ import absolute_import
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
     9
38195
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
    10
import ast
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
    11
import collections
34104
5361771f9714 wrapfunction: use functools.partial if possible
Jun Wu <quark@fb.com>
parents: 34065
diff changeset
    12
import functools
25946
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    13
import imp
31273
d79761fe697f extensions: use inspect module instead of func_code.co_argcount
Augie Fackler <raf@durin42.com>
parents: 31091
diff changeset
    14
import inspect
25946
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    15
import os
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    16
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    17
from .i18n import (
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    18
    _,
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    19
    gettext,
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    20
)
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    21
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    22
from . import (
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    23
    cmdutil,
33139
c467d13334ee configitems: add an official API for extensions to register config item
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 33064
diff changeset
    24
    configitems,
25946
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    25
    error,
30575
c4c51fd0e11d py3: use pycompat.sysstr() in __import__()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30319
diff changeset
    26
    pycompat,
25946
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    27
    util,
5e0d80195a0f extensions: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
    28
)
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    29
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36928
diff changeset
    30
from .utils import (
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36928
diff changeset
    31
    stringutil,
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36928
diff changeset
    32
)
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36928
diff changeset
    33
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    34
_extensions = {}
29899
b1ebc767563d help: show content for explicitly disabled extension (issue5228)
liscju <piotr.listkiewicz@gmail.com>
parents: 29852
diff changeset
    35
_disabledextensions = {}
24065
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
    36
_aftercallbacks = {}
5192
60acf1432ee0 Move cmdtable and reposetup handling out of extensions.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5152
diff changeset
    37
_order = []
33526
792d121f22ba extensions: expand the builtins extensions declaration
Boris Feld <boris.feld@octobus.net>
parents: 33327
diff changeset
    38
_builtin = {
792d121f22ba extensions: expand the builtins extensions declaration
Boris Feld <boris.feld@octobus.net>
parents: 33327
diff changeset
    39
    'hbisect',
792d121f22ba extensions: expand the builtins extensions declaration
Boris Feld <boris.feld@octobus.net>
parents: 33327
diff changeset
    40
    'bookmarks',
33527
6a3e83781c6e color: drop the now useless color extension
Boris Feld <boris.feld@octobus.net>
parents: 33526
diff changeset
    41
    'color',
33526
792d121f22ba extensions: expand the builtins extensions declaration
Boris Feld <boris.feld@octobus.net>
parents: 33327
diff changeset
    42
    'parentrevspec',
792d121f22ba extensions: expand the builtins extensions declaration
Boris Feld <boris.feld@octobus.net>
parents: 33327
diff changeset
    43
    'progress',
792d121f22ba extensions: expand the builtins extensions declaration
Boris Feld <boris.feld@octobus.net>
parents: 33327
diff changeset
    44
    'interhg',
792d121f22ba extensions: expand the builtins extensions declaration
Boris Feld <boris.feld@octobus.net>
parents: 33327
diff changeset
    45
    'inotify',
792d121f22ba extensions: expand the builtins extensions declaration
Boris Feld <boris.feld@octobus.net>
parents: 33327
diff changeset
    46
    'hgcia'
792d121f22ba extensions: expand the builtins extensions declaration
Boris Feld <boris.feld@octobus.net>
parents: 33327
diff changeset
    47
}
5192
60acf1432ee0 Move cmdtable and reposetup handling out of extensions.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5152
diff changeset
    48
19777
6f72e7d28b35 extensions: list up only enabled extensions, if "ui" is specified
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19769
diff changeset
    49
def extensions(ui=None):
6f72e7d28b35 extensions: list up only enabled extensions, if "ui" is specified
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19769
diff changeset
    50
    if ui:
6f72e7d28b35 extensions: list up only enabled extensions, if "ui" is specified
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19769
diff changeset
    51
        def enabled(name):
6f72e7d28b35 extensions: list up only enabled extensions, if "ui" is specified
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19769
diff changeset
    52
            for format in ['%s', 'hgext.%s']:
6f72e7d28b35 extensions: list up only enabled extensions, if "ui" is specified
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19769
diff changeset
    53
                conf = ui.config('extensions', format % name)
6f72e7d28b35 extensions: list up only enabled extensions, if "ui" is specified
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19769
diff changeset
    54
                if conf is not None and not conf.startswith('!'):
6f72e7d28b35 extensions: list up only enabled extensions, if "ui" is specified
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19769
diff changeset
    55
                    return True
6f72e7d28b35 extensions: list up only enabled extensions, if "ui" is specified
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19769
diff changeset
    56
    else:
6f72e7d28b35 extensions: list up only enabled extensions, if "ui" is specified
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19769
diff changeset
    57
        enabled = lambda name: True
5192
60acf1432ee0 Move cmdtable and reposetup handling out of extensions.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5152
diff changeset
    58
    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
    59
        module = _extensions[name]
19777
6f72e7d28b35 extensions: list up only enabled extensions, if "ui" is specified
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 19769
diff changeset
    60
        if module and enabled(name):
5192
60acf1432ee0 Move cmdtable and reposetup handling out of extensions.py
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5152
diff changeset
    61
            yield name, module
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    62
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    63
def find(name):
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    64
    '''return module with given extension name'''
14415
c238b12a1ed4 extensions: raise when trying to find an extension that failed to load
Idan Kamara <idankk86@gmail.com>
parents: 14318
diff changeset
    65
    mod = None
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    66
    try:
27637
b502138f5faa cleanup: remove superfluous space after space after equals (python)
timeless <timeless@mozdev.org>
parents: 27142
diff changeset
    67
        mod = _extensions[name]
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    68
    except KeyError:
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    69
        for k, v in _extensions.iteritems():
4560
3daed3680554 extensions: fix lookup of hgext.foo modules
Matt Mackall <mpm@selenic.com>
parents: 4558
diff changeset
    70
            if k.endswith('.' + name) or k.endswith('/' + name):
14415
c238b12a1ed4 extensions: raise when trying to find an extension that failed to load
Idan Kamara <idankk86@gmail.com>
parents: 14318
diff changeset
    71
                mod = v
c238b12a1ed4 extensions: raise when trying to find an extension that failed to load
Idan Kamara <idankk86@gmail.com>
parents: 14318
diff changeset
    72
                break
c238b12a1ed4 extensions: raise when trying to find an extension that failed to load
Idan Kamara <idankk86@gmail.com>
parents: 14318
diff changeset
    73
    if not mod:
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    74
        raise KeyError(name)
14415
c238b12a1ed4 extensions: raise when trying to find an extension that failed to load
Idan Kamara <idankk86@gmail.com>
parents: 14318
diff changeset
    75
    return mod
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    76
7916
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    77
def loadpath(path, module_name):
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    78
    module_name = module_name.replace('.', '_')
20645
7d83c3b6e8d9 extensions: use normpath to allow trailing '\' on Windows (issue4187)
Ed Morley <emorley@mozilla.com>
parents: 20622
diff changeset
    79
    path = util.normpath(util.expandpath(path))
30580
5ffbaba9acac py3: use pycompat.fsdecode() to pass to imp.* functions
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30575
diff changeset
    80
    module_name = pycompat.fsdecode(module_name)
5ffbaba9acac py3: use pycompat.fsdecode() to pass to imp.* functions
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30575
diff changeset
    81
    path = pycompat.fsdecode(path)
7916
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    82
    if os.path.isdir(path):
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    83
        # module/__init__.py style
20645
7d83c3b6e8d9 extensions: use normpath to allow trailing '\' on Windows (issue4187)
Ed Morley <emorley@mozilla.com>
parents: 20622
diff changeset
    84
        d, f = os.path.split(path)
7916
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    85
        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
    86
        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
    87
    else:
17217
1b2b727a885f hooks: print out more information when loading a python hook fails
Simon Heimberg <simohe@besonet.ch>
parents: 16709
diff changeset
    88
        try:
1b2b727a885f hooks: print out more information when loading a python hook fails
Simon Heimberg <simohe@besonet.ch>
parents: 16709
diff changeset
    89
            return imp.load_source(module_name, path)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25364
diff changeset
    90
        except IOError as exc:
17217
1b2b727a885f hooks: print out more information when loading a python hook fails
Simon Heimberg <simohe@besonet.ch>
parents: 16709
diff changeset
    91
            if not exc.filename:
1b2b727a885f hooks: print out more information when loading a python hook fails
Simon Heimberg <simohe@besonet.ch>
parents: 16709
diff changeset
    92
                exc.filename = path # python does not fill this
1b2b727a885f hooks: print out more information when loading a python hook fails
Simon Heimberg <simohe@besonet.ch>
parents: 16709
diff changeset
    93
            raise
7916
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7876
diff changeset
    94
28505
d5512a0a8ad6 extensions: extract the 'importh' closure as normal function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 28312
diff changeset
    95
def _importh(name):
d5512a0a8ad6 extensions: extract the 'importh' closure as normal function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 28312
diff changeset
    96
    """import and return the <name> module"""
30575
c4c51fd0e11d py3: use pycompat.sysstr() in __import__()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30319
diff changeset
    97
    mod = __import__(pycompat.sysstr(name))
28505
d5512a0a8ad6 extensions: extract the 'importh' closure as normal function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 28312
diff changeset
    98
    components = name.split('.')
d5512a0a8ad6 extensions: extract the 'importh' closure as normal function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 28312
diff changeset
    99
    for comp in components[1:]:
d5512a0a8ad6 extensions: extract the 'importh' closure as normal function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 28312
diff changeset
   100
        mod = getattr(mod, comp)
d5512a0a8ad6 extensions: extract the 'importh' closure as normal function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 28312
diff changeset
   101
    return mod
d5512a0a8ad6 extensions: extract the 'importh' closure as normal function
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 28312
diff changeset
   102
30058
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   103
def _importext(name, path=None, reportfunc=None):
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   104
    if path:
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   105
        # the module will be loaded in sys.modules
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   106
        # choose an unique name so that it doesn't
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   107
        # conflicts with other modules
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   108
        mod = loadpath(path, 'hgext.%s' % name)
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   109
    else:
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   110
        try:
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   111
            mod = _importh("hgext.%s" % name)
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   112
        except ImportError as err:
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   113
            if reportfunc:
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   114
                reportfunc(err, "hgext.%s" % name, "hgext3rd.%s" % name)
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   115
            try:
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   116
                mod = _importh("hgext3rd.%s" % name)
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   117
            except ImportError as err:
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   118
                if reportfunc:
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   119
                    reportfunc(err, "hgext3rd.%s" % name, name)
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   120
                mod = _importh(name)
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   121
    return mod
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   122
28506
10252652c6e4 extensions: factor import error reporting out
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 28505
diff changeset
   123
def _reportimporterror(ui, err, failed, next):
30030
3741a8f86e88 extensions: add a note about debug output during extensions search
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 30029
diff changeset
   124
    # note: this ui.debug happens before --debug is processed,
3741a8f86e88 extensions: add a note about debug output during extensions search
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 30029
diff changeset
   125
    #       Use --config ui.debug=1 to see them.
28506
10252652c6e4 extensions: factor import error reporting out
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 28505
diff changeset
   126
    ui.debug('could not import %s (%s): trying %s\n'
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36928
diff changeset
   127
             % (failed, stringutil.forcebytestr(err), next))
28506
10252652c6e4 extensions: factor import error reporting out
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 28505
diff changeset
   128
    if ui.debugflag:
10252652c6e4 extensions: factor import error reporting out
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 28505
diff changeset
   129
        ui.traceback()
10252652c6e4 extensions: factor import error reporting out
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 28505
diff changeset
   130
36302
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   131
def _rejectunicode(name, xs):
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   132
    if isinstance(xs, (list, set, tuple)):
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   133
        for x in xs:
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   134
            _rejectunicode(name, x)
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   135
    elif isinstance(xs, dict):
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   136
        for k, v in xs.items():
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   137
            _rejectunicode(name, k)
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36928
diff changeset
   138
            _rejectunicode(b'%s.%s' % (name, stringutil.forcebytestr(k)), v)
36302
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   139
    elif isinstance(xs, type(u'')):
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   140
        raise error.ProgrammingError(b"unicode %r found in %s" % (xs, name),
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   141
                                     hint="use b'' to make it byte string")
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   142
32381
e5fbf9687600 extensions: prohibit registration of command without using @command (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32380
diff changeset
   143
# attributes set by registrar.command
e5fbf9687600 extensions: prohibit registration of command without using @command (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32380
diff changeset
   144
_cmdfuncattrs = ('norepo', 'optionalrepo', 'inferrepo')
e5fbf9687600 extensions: prohibit registration of command without using @command (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32380
diff changeset
   145
32382
d47d7d3bd07b extensions: show deprecation warning for the use of cmdutil.command
Yuya Nishihara <yuya@tcha.org>
parents: 32381
diff changeset
   146
def _validatecmdtable(ui, cmdtable):
32381
e5fbf9687600 extensions: prohibit registration of command without using @command (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32380
diff changeset
   147
    """Check if extension commands have required attributes"""
e5fbf9687600 extensions: prohibit registration of command without using @command (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32380
diff changeset
   148
    for c, e in cmdtable.iteritems():
e5fbf9687600 extensions: prohibit registration of command without using @command (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32380
diff changeset
   149
        f = e[0]
e5fbf9687600 extensions: prohibit registration of command without using @command (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32380
diff changeset
   150
        missing = [a for a in _cmdfuncattrs if not util.safehasattr(f, a)]
e5fbf9687600 extensions: prohibit registration of command without using @command (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32380
diff changeset
   151
        if not missing:
e5fbf9687600 extensions: prohibit registration of command without using @command (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32380
diff changeset
   152
            continue
e5fbf9687600 extensions: prohibit registration of command without using @command (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32380
diff changeset
   153
        raise error.ProgrammingError(
e5fbf9687600 extensions: prohibit registration of command without using @command (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32380
diff changeset
   154
            'missing attributes: %s' % ', '.join(missing),
e5fbf9687600 extensions: prohibit registration of command without using @command (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32380
diff changeset
   155
            hint="use @command decorator to register '%s'" % c)
e5fbf9687600 extensions: prohibit registration of command without using @command (API)
Yuya Nishihara <yuya@tcha.org>
parents: 32380
diff changeset
   156
36302
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   157
def _validatetables(ui, mod):
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   158
    """Sanity check for loadable tables provided by extension module"""
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   159
    for t in ['cmdtable', 'colortable', 'configtable']:
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   160
        _rejectunicode(t, getattr(mod, t, {}))
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   161
    for t in ['filesetpredicate', 'internalmerge', 'revsetpredicate',
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   162
              'templatefilter', 'templatefunc', 'templatekeyword']:
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   163
        o = getattr(mod, t, None)
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   164
        if o:
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   165
            _rejectunicode(t, o._table)
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   166
    _validatecmdtable(ui, getattr(mod, 'cmdtable', {}))
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   167
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   168
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
   169
    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
   170
        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
   171
    else:
af0995261f02 extensions: don't get confused by aliasing between "foo" and "hgext.foo"
Bryan O'Sullivan <bos@serpentine.com>
parents: 4818
diff changeset
   172
        shortname = name
27111
9de814b35808 extensions: rename _ignore to _builtin, add descriptive comment
Bryan O'Sullivan <bos@serpentine.com>
parents: 26781
diff changeset
   173
    if shortname in _builtin:
13349
0d3f35394af4 extensions: add an ignore list for old extensions
Matt Mackall <mpm@selenic.com>
parents: 13191
diff changeset
   174
        return None
5031
af0995261f02 extensions: don't get confused by aliasing between "foo" and "hgext.foo"
Bryan O'Sullivan <bos@serpentine.com>
parents: 4818
diff changeset
   175
    if shortname in _extensions:
12779
891ddf76b73e extensions.load: return module
Erik Zielke <ez@aragost.com>
parents: 11521
diff changeset
   176
        return _extensions[shortname]
5087
b3cc62268a91 Cache extension load failures.
Brendan Cully <brendan@kublai.com>
parents: 4635
diff changeset
   177
    _extensions[shortname] = None
30058
8f54f9b8010d extensions: move the "import" logic out from "load"
Jun Wu <quark@fb.com>
parents: 30030
diff changeset
   178
    mod = _importext(name, path, bind(_reportimporterror, ui))
27142
060f83d219b9 extensions: refuse to load extensions if minimum hg version not met
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27116
diff changeset
   179
060f83d219b9 extensions: refuse to load extensions if minimum hg version not met
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27116
diff changeset
   180
    # Before we do anything with the extension, check against minimum stated
060f83d219b9 extensions: refuse to load extensions if minimum hg version not met
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27116
diff changeset
   181
    # compatibility. This gives extension authors a mechanism to have their
060f83d219b9 extensions: refuse to load extensions if minimum hg version not met
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27116
diff changeset
   182
    # extensions short circuit when loaded with a known incompatible version
060f83d219b9 extensions: refuse to load extensions if minimum hg version not met
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27116
diff changeset
   183
    # of Mercurial.
060f83d219b9 extensions: refuse to load extensions if minimum hg version not met
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27116
diff changeset
   184
    minver = getattr(mod, 'minimumhgversion', None)
060f83d219b9 extensions: refuse to load extensions if minimum hg version not met
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27116
diff changeset
   185
    if minver and util.versiontuple(minver, 2) > util.versiontuple(n=2):
060f83d219b9 extensions: refuse to load extensions if minimum hg version not met
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27116
diff changeset
   186
        ui.warn(_('(third party extension %s requires version %s or newer '
060f83d219b9 extensions: refuse to load extensions if minimum hg version not met
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27116
diff changeset
   187
                  'of Mercurial; disabling)\n') % (shortname, minver))
060f83d219b9 extensions: refuse to load extensions if minimum hg version not met
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27116
diff changeset
   188
        return
36302
4088e568a411 extensions: reject any unicode strings in tables before loading
Yuya Nishihara <yuya@tcha.org>
parents: 36216
diff changeset
   189
    _validatetables(ui, mod)
27142
060f83d219b9 extensions: refuse to load extensions if minimum hg version not met
Gregory Szorc <gregory.szorc@gmail.com>
parents: 27116
diff changeset
   190
5031
af0995261f02 extensions: don't get confused by aliasing between "foo" and "hgext.foo"
Bryan O'Sullivan <bos@serpentine.com>
parents: 4818
diff changeset
   191
    _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
   192
    _order.append(shortname)
24065
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   193
    for fn in _aftercallbacks.get(shortname, []):
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   194
        fn(loaded=True)
12779
891ddf76b73e extensions.load: return module
Erik Zielke <ez@aragost.com>
parents: 11521
diff changeset
   195
    return mod
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   196
29461
7d88fde2309f extensions: move uisetup and extsetup to standalone functions
Jun Wu <quark@fb.com>
parents: 29162
diff changeset
   197
def _runuisetup(name, ui):
7d88fde2309f extensions: move uisetup and extsetup to standalone functions
Jun Wu <quark@fb.com>
parents: 29162
diff changeset
   198
    uisetup = getattr(_extensions[name], 'uisetup', None)
7d88fde2309f extensions: move uisetup and extsetup to standalone functions
Jun Wu <quark@fb.com>
parents: 29162
diff changeset
   199
    if uisetup:
32744
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   200
        try:
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   201
            uisetup(ui)
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   202
        except Exception as inst:
34845
78d9a7b7cdb6 extensions: always include traceback when extension setup fails
Martin von Zweigbergk <martinvonz@google.com>
parents: 34199
diff changeset
   203
            ui.traceback(force=True)
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36928
diff changeset
   204
            msg = stringutil.forcebytestr(inst)
32744
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   205
            ui.warn(_("*** failed to set up extension %s: %s\n") % (name, msg))
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   206
            return False
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   207
    return True
29461
7d88fde2309f extensions: move uisetup and extsetup to standalone functions
Jun Wu <quark@fb.com>
parents: 29162
diff changeset
   208
7d88fde2309f extensions: move uisetup and extsetup to standalone functions
Jun Wu <quark@fb.com>
parents: 29162
diff changeset
   209
def _runextsetup(name, ui):
7d88fde2309f extensions: move uisetup and extsetup to standalone functions
Jun Wu <quark@fb.com>
parents: 29162
diff changeset
   210
    extsetup = getattr(_extensions[name], 'extsetup', None)
7d88fde2309f extensions: move uisetup and extsetup to standalone functions
Jun Wu <quark@fb.com>
parents: 29162
diff changeset
   211
    if extsetup:
7d88fde2309f extensions: move uisetup and extsetup to standalone functions
Jun Wu <quark@fb.com>
parents: 29162
diff changeset
   212
        try:
32744
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   213
            try:
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   214
                extsetup(ui)
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   215
            except TypeError:
36216
646002338365 py3: introduce and use pycompat.getargspec
Augie Fackler <augie@google.com>
parents: 34845
diff changeset
   216
                if pycompat.getargspec(extsetup).args:
32744
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   217
                    raise
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   218
                extsetup() # old extsetup with no ui argument
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   219
        except Exception as inst:
34845
78d9a7b7cdb6 extensions: always include traceback when extension setup fails
Martin von Zweigbergk <martinvonz@google.com>
parents: 34199
diff changeset
   220
            ui.traceback(force=True)
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36928
diff changeset
   221
            msg = stringutil.forcebytestr(inst)
32744
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   222
            ui.warn(_("*** failed to set up extension %s: %s\n") % (name, msg))
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   223
            return False
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   224
    return True
29461
7d88fde2309f extensions: move uisetup and extsetup to standalone functions
Jun Wu <quark@fb.com>
parents: 29162
diff changeset
   225
32454
9a3e88d4a030 extensions: allow loading a whitelisted subset of extensions
Jun Wu <quark@fb.com>
parents: 32382
diff changeset
   226
def loadall(ui, whitelist=None):
4617
669e76b7df24 extensions: pull extension-aware bits out of ui
Matt Mackall <mpm@selenic.com>
parents: 4582
diff changeset
   227
    result = ui.configitems("extensions")
32455
f40dc6f7c12f profiling: allow loading profiling extension before everything else
Jun Wu <quark@fb.com>
parents: 32454
diff changeset
   228
    if whitelist is not None:
32454
9a3e88d4a030 extensions: allow loading a whitelisted subset of extensions
Jun Wu <quark@fb.com>
parents: 32382
diff changeset
   229
        result = [(k, v) for (k, v) in result if k in whitelist]
9410
1c83938b6a8e extensions: load and configure extensions in well-defined phases
Martin Geisler <mg@lazybytes.net>
parents: 9136
diff changeset
   230
    newindex = len(_order)
7876
53c72ba36c2b cleanup: drop enumerate() when index is not used
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 7644
diff changeset
   231
    for (name, path) in result:
4617
669e76b7df24 extensions: pull extension-aware bits out of ui
Matt Mackall <mpm@selenic.com>
parents: 4582
diff changeset
   232
        if path:
31274
063d7957fa12 extensions: use [0:1] slice on config path instead of [0]
Augie Fackler <raf@durin42.com>
parents: 31273
diff changeset
   233
            if path[0:1] == '!':
29899
b1ebc767563d help: show content for explicitly disabled extension (issue5228)
liscju <piotr.listkiewicz@gmail.com>
parents: 29852
diff changeset
   234
                _disabledextensions[name] = path[1:]
5469
b12432b1c2c7 Allow explicit disabling of extensions
Steve Borho <steve@borho.org>
parents: 5192
diff changeset
   235
                continue
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   236
        try:
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   237
            load(ui, name, path)
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25364
diff changeset
   238
        except Exception as inst:
37087
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36928
diff changeset
   239
            msg = stringutil.forcebytestr(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
   240
            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
   241
                ui.warn(_("*** failed to import extension %s from %s: %s\n")
32380
b88d879e468a extensions: optionally print hint on import failure
Yuya Nishihara <yuya@tcha.org>
parents: 32331
diff changeset
   242
                        % (name, path, msg))
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
   243
            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
   244
                ui.warn(_("*** failed to import extension %s: %s\n")
32380
b88d879e468a extensions: optionally print hint on import failure
Yuya Nishihara <yuya@tcha.org>
parents: 32331
diff changeset
   245
                        % (name, msg))
b88d879e468a extensions: optionally print hint on import failure
Yuya Nishihara <yuya@tcha.org>
parents: 32331
diff changeset
   246
            if isinstance(inst, error.Hint) and inst.hint:
b88d879e468a extensions: optionally print hint on import failure
Yuya Nishihara <yuya@tcha.org>
parents: 32331
diff changeset
   247
                ui.warn(_("*** (%s)\n") % inst.hint)
25364
de23a552fc23 extensions: show traceback on load failure if --traceback flag is set
Yuya Nishihara <yuya@tcha.org>
parents: 24950
diff changeset
   248
            ui.traceback()
34199
4c5730c21523 extensions: register config item early
Boris Feld <boris.feld@octobus.net>
parents: 34198
diff changeset
   249
    # list of (objname, loadermod, loadername) tuple:
4c5730c21523 extensions: register config item early
Boris Feld <boris.feld@octobus.net>
parents: 34198
diff changeset
   250
    # - objname is the name of an object in extension module,
4c5730c21523 extensions: register config item early
Boris Feld <boris.feld@octobus.net>
parents: 34198
diff changeset
   251
    #   from which extra information is loaded
4c5730c21523 extensions: register config item early
Boris Feld <boris.feld@octobus.net>
parents: 34198
diff changeset
   252
    # - loadermod is the module where loader is placed
4c5730c21523 extensions: register config item early
Boris Feld <boris.feld@octobus.net>
parents: 34198
diff changeset
   253
    # - loadername is the name of the function,
4c5730c21523 extensions: register config item early
Boris Feld <boris.feld@octobus.net>
parents: 34198
diff changeset
   254
    #   which takes (ui, extensionname, extraobj) arguments
4c5730c21523 extensions: register config item early
Boris Feld <boris.feld@octobus.net>
parents: 34198
diff changeset
   255
    #
4c5730c21523 extensions: register config item early
Boris Feld <boris.feld@octobus.net>
parents: 34198
diff changeset
   256
    # This one is for the list of item that must be run before running any setup
4c5730c21523 extensions: register config item early
Boris Feld <boris.feld@octobus.net>
parents: 34198
diff changeset
   257
    earlyextraloaders = [
4c5730c21523 extensions: register config item early
Boris Feld <boris.feld@octobus.net>
parents: 34198
diff changeset
   258
        ('configtable', configitems, 'loadconfigtable'),
4c5730c21523 extensions: register config item early
Boris Feld <boris.feld@octobus.net>
parents: 34198
diff changeset
   259
    ]
4c5730c21523 extensions: register config item early
Boris Feld <boris.feld@octobus.net>
parents: 34198
diff changeset
   260
    _loadextra(ui, newindex, earlyextraloaders)
4544
930ed513c864 Create a separate module for managing extensions
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   261
32744
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   262
    broken = set()
9410
1c83938b6a8e extensions: load and configure extensions in well-defined phases
Martin Geisler <mg@lazybytes.net>
parents: 9136
diff changeset
   263
    for name in _order[newindex:]:
32744
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   264
        if not _runuisetup(name, ui):
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   265
            broken.add(name)
9410
1c83938b6a8e extensions: load and configure extensions in well-defined phases
Martin Geisler <mg@lazybytes.net>
parents: 9136
diff changeset
   266
9660
e0eae93e6c67 extensions: changed to call extsetup() from extensions.loadall()
Yuya Nishihara <yuya@tcha.org>
parents: 9610
diff changeset
   267
    for name in _order[newindex:]:
32744
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   268
        if name in broken:
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   269
            continue
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   270
        if not _runextsetup(name, ui):
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   271
            broken.add(name)
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   272
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   273
    for name in broken:
ea1c2eb7abd3 extensions: catch uisetup and extsetup failures and don't let them break hg
Augie Fackler <augie@google.com>
parents: 32742
diff changeset
   274
        _extensions[name] = None
9660
e0eae93e6c67 extensions: changed to call extsetup() from extensions.loadall()
Yuya Nishihara <yuya@tcha.org>
parents: 9610
diff changeset
   275
24065
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   276
    # Call aftercallbacks that were never met.
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   277
    for shortname in _aftercallbacks:
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   278
        if shortname in _extensions:
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   279
            continue
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   280
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   281
        for fn in _aftercallbacks[shortname]:
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   282
            fn(loaded=False)
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   283
24950
e6e7d1cce04d extensions: clear aftercallbacks after execution (issue4646)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24734
diff changeset
   284
    # loadall() is called multiple times and lingering _aftercallbacks
e6e7d1cce04d extensions: clear aftercallbacks after execution (issue4646)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24734
diff changeset
   285
    # entries could result in double execution. See issue4646.
e6e7d1cce04d extensions: clear aftercallbacks after execution (issue4646)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24734
diff changeset
   286
    _aftercallbacks.clear()
e6e7d1cce04d extensions: clear aftercallbacks after execution (issue4646)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 24734
diff changeset
   287
33064
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   288
    # delay importing avoids cyclic dependency (especially commands)
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   289
    from . import (
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   290
        color,
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   291
        commands,
33725
50c44dee741a filemerge: move decorator definition for internal merge tools to registrar
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33708
diff changeset
   292
        filemerge,
33064
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   293
        fileset,
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   294
        revset,
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   295
        templatefilters,
36928
521f6c7e1756 templater: split template functions to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36302
diff changeset
   296
        templatefuncs,
33064
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   297
        templatekw,
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   298
    )
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   299
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   300
    # list of (objname, loadermod, loadername) tuple:
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   301
    # - objname is the name of an object in extension module,
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   302
    #   from which extra information is loaded
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   303
    # - loadermod is the module where loader is placed
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   304
    # - loadername is the name of the function,
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   305
    #   which takes (ui, extensionname, extraobj) arguments
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   306
    extraloaders = [
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   307
        ('cmdtable', commands, 'loadcmdtable'),
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   308
        ('colortable', color, 'loadcolortable'),
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   309
        ('filesetpredicate', fileset, 'loadpredicate'),
33725
50c44dee741a filemerge: move decorator definition for internal merge tools to registrar
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33708
diff changeset
   310
        ('internalmerge', filemerge, 'loadinternalmerge'),
33064
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   311
        ('revsetpredicate', revset, 'loadpredicate'),
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   312
        ('templatefilter', templatefilters, 'loadfilter'),
36928
521f6c7e1756 templater: split template functions to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36302
diff changeset
   313
        ('templatefunc', templatefuncs, 'loadfunction'),
33064
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   314
        ('templatekeyword', templatekw, 'loadkeyword'),
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   315
    ]
34198
f7c9c5d8c7f4 extensions: factor extra data loading out
Boris Feld <boris.feld@octobus.net>
parents: 34143
diff changeset
   316
    _loadextra(ui, newindex, extraloaders)
33064
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   317
34198
f7c9c5d8c7f4 extensions: factor extra data loading out
Boris Feld <boris.feld@octobus.net>
parents: 34143
diff changeset
   318
def _loadextra(ui, newindex, extraloaders):
33064
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   319
    for name in _order[newindex:]:
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   320
        module = _extensions[name]
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   321
        if not module:
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   322
            continue # loading this module failed
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   323
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   324
        for objname, loadermod, loadername in extraloaders:
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   325
            extraobj = getattr(module, objname, None)
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   326
            if extraobj is not None:
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   327
                getattr(loadermod, loadername)(ui, name, extraobj)
45b0e9d05ee9 extensions: register functions always at loading extension (issue5601)
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 33030
diff changeset
   328
24065
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   329
def afterloaded(extension, callback):
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   330
    '''Run the specified function after a named extension is loaded.
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   331
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   332
    If the named extension is already loaded, the callback will be called
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   333
    immediately.
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   334
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   335
    If the named extension never loads, the callback will be called after
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   336
    all extensions have been loaded.
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   337
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   338
    The callback receives the named argument ``loaded``, which is a boolean
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   339
    indicating whether the dependent extension actually loaded.
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   340
    '''
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   341
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   342
    if extension in _extensions:
33030
80a5d237a4ae extensions: call afterloaded() with loaded=False for disabled extensions
Adam Simpkins <simpkins@fb.com>
parents: 32744
diff changeset
   343
        # Report loaded as False if the extension is disabled
80a5d237a4ae extensions: call afterloaded() with loaded=False for disabled extensions
Adam Simpkins <simpkins@fb.com>
parents: 32744
diff changeset
   344
        loaded = (_extensions[extension] is not None)
80a5d237a4ae extensions: call afterloaded() with loaded=False for disabled extensions
Adam Simpkins <simpkins@fb.com>
parents: 32744
diff changeset
   345
        callback(loaded=loaded)
24065
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   346
    else:
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   347
        _aftercallbacks.setdefault(extension, []).append(callback)
d8837ad682dd extensions: support callbacks after another extension loads
Gregory Szorc <gregory.szorc@gmail.com>
parents: 23953
diff changeset
   348
24734
fb6cb1b82f4f extensions: extract partial application into a bind() function
Eric Sumner <ericsumner@fb.com>
parents: 24145
diff changeset
   349
def bind(func, *args):
fb6cb1b82f4f extensions: extract partial application into a bind() function
Eric Sumner <ericsumner@fb.com>
parents: 24145
diff changeset
   350
    '''Partial function application
fb6cb1b82f4f extensions: extract partial application into a bind() function
Eric Sumner <ericsumner@fb.com>
parents: 24145
diff changeset
   351
fb6cb1b82f4f extensions: extract partial application into a bind() function
Eric Sumner <ericsumner@fb.com>
parents: 24145
diff changeset
   352
      Returns a new function that is the partial application of args and kwargs
fb6cb1b82f4f extensions: extract partial application into a bind() function
Eric Sumner <ericsumner@fb.com>
parents: 24145
diff changeset
   353
      to func.  For example,
fb6cb1b82f4f extensions: extract partial application into a bind() function
Eric Sumner <ericsumner@fb.com>
parents: 24145
diff changeset
   354
fb6cb1b82f4f extensions: extract partial application into a bind() function
Eric Sumner <ericsumner@fb.com>
parents: 24145
diff changeset
   355
          f(1, 2, bar=3) === bind(f, 1)(2, bar=3)'''
fb6cb1b82f4f extensions: extract partial application into a bind() function
Eric Sumner <ericsumner@fb.com>
parents: 24145
diff changeset
   356
    assert callable(func)
fb6cb1b82f4f extensions: extract partial application into a bind() function
Eric Sumner <ericsumner@fb.com>
parents: 24145
diff changeset
   357
    def closure(*a, **kw):
fb6cb1b82f4f extensions: extract partial application into a bind() function
Eric Sumner <ericsumner@fb.com>
parents: 24145
diff changeset
   358
        return func(*(args + a), **kw)
fb6cb1b82f4f extensions: extract partial application into a bind() function
Eric Sumner <ericsumner@fb.com>
parents: 24145
diff changeset
   359
    return closure
fb6cb1b82f4f extensions: extract partial application into a bind() function
Eric Sumner <ericsumner@fb.com>
parents: 24145
diff changeset
   360
29775
ce6317dcb944 extensions: set attributes to wrappers so we can trace them back
Jun Wu <quark@fb.com>
parents: 29461
diff changeset
   361
def _updatewrapper(wrap, origfn, unboundwrapper):
ce6317dcb944 extensions: set attributes to wrappers so we can trace them back
Jun Wu <quark@fb.com>
parents: 29461
diff changeset
   362
    '''Copy and add some useful attributes to wrapper'''
34143
82bd4c5a81e5 extensions: fix wrapcommand/function of class instance
Yuya Nishihara <yuya@tcha.org>
parents: 34105
diff changeset
   363
    try:
82bd4c5a81e5 extensions: fix wrapcommand/function of class instance
Yuya Nishihara <yuya@tcha.org>
parents: 34105
diff changeset
   364
        wrap.__name__ = origfn.__name__
82bd4c5a81e5 extensions: fix wrapcommand/function of class instance
Yuya Nishihara <yuya@tcha.org>
parents: 34105
diff changeset
   365
    except AttributeError:
82bd4c5a81e5 extensions: fix wrapcommand/function of class instance
Yuya Nishihara <yuya@tcha.org>
parents: 34105
diff changeset
   366
        pass
28310
01dc11e7191f extensions: extract function that copies function attributes to wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 28155
diff changeset
   367
    wrap.__module__ = getattr(origfn, '__module__')
01dc11e7191f extensions: extract function that copies function attributes to wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 28155
diff changeset
   368
    wrap.__doc__ = getattr(origfn, '__doc__')
28312
24f1d3c70c41 extensions: copy extra __dict__ of original function
Yuya Nishihara <yuya@tcha.org>
parents: 28311
diff changeset
   369
    wrap.__dict__.update(getattr(origfn, '__dict__', {}))
29775
ce6317dcb944 extensions: set attributes to wrappers so we can trace them back
Jun Wu <quark@fb.com>
parents: 29461
diff changeset
   370
    wrap._origfunc = origfn
ce6317dcb944 extensions: set attributes to wrappers so we can trace them back
Jun Wu <quark@fb.com>
parents: 29461
diff changeset
   371
    wrap._unboundwrapper = unboundwrapper
28310
01dc11e7191f extensions: extract function that copies function attributes to wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 28155
diff changeset
   372
24124
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   373
def wrapcommand(table, command, wrapper, synopsis=None, docstring=None):
11519
bbdf1fb1d3e3 extensions: add docstring for wrapcommand().
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11402
diff changeset
   374
    '''Wrap the command named `command' in table
bbdf1fb1d3e3 extensions: add docstring for wrapcommand().
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11402
diff changeset
   375
bbdf1fb1d3e3 extensions: add docstring for wrapcommand().
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11402
diff changeset
   376
    Replace command in the command table with wrapper. The wrapped command will
bbdf1fb1d3e3 extensions: add docstring for wrapcommand().
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11402
diff changeset
   377
    be inserted into the command table specified by the table argument.
bbdf1fb1d3e3 extensions: add docstring for wrapcommand().
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11402
diff changeset
   378
bbdf1fb1d3e3 extensions: add docstring for wrapcommand().
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11402
diff changeset
   379
    The wrapper will be called like
bbdf1fb1d3e3 extensions: add docstring for wrapcommand().
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11402
diff changeset
   380
bbdf1fb1d3e3 extensions: add docstring for wrapcommand().
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11402
diff changeset
   381
      wrapper(orig, *args, **kwargs)
bbdf1fb1d3e3 extensions: add docstring for wrapcommand().
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11402
diff changeset
   382
bbdf1fb1d3e3 extensions: add docstring for wrapcommand().
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11402
diff changeset
   383
    where orig is the original (wrapped) function, and *args, **kwargs
bbdf1fb1d3e3 extensions: add docstring for wrapcommand().
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11402
diff changeset
   384
    are the arguments passed to it.
24124
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   385
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   386
    Optionally append to the command synopsis and docstring, used for help.
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   387
    For example, if your extension wraps the ``bookmarks`` command to add the
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   388
    flags ``--remote`` and ``--all`` you might call this function like so:
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   389
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   390
      synopsis = ' [-a] [--remote]'
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   391
      docstring = """
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   392
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   393
      The ``remotenames`` extension adds the ``--remote`` and ``--all`` (``-a``)
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   394
      flags to the bookmarks command. Either flag will show the remote bookmarks
26781
1aee2ab0f902 spelling: trivial spell checking
Mads Kiilerich <madski@unity3d.com>
parents: 25946
diff changeset
   395
      known to the repository; ``--remote`` will also suppress the output of the
24124
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   396
      local bookmarks.
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   397
      """
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   398
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   399
      extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   400
                             synopsis, docstring)
11519
bbdf1fb1d3e3 extensions: add docstring for wrapcommand().
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11402
diff changeset
   401
    '''
21795
711498bb4ff5 extensions: restore use of callable() since it was readded in Python 3.2
Augie Fackler <raf@durin42.com>
parents: 21229
diff changeset
   402
    assert callable(wrapper)
7215
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   403
    aliases, entry = cmdutil.findcmd(command, table)
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   404
    for alias, e in table.iteritems():
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   405
        if e is entry:
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   406
            key = alias
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   407
            break
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   408
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   409
    origfn = entry[0]
34105
a763c891f36e wrapcommand: use functools.partial
Jun Wu <quark@fb.com>
parents: 34104
diff changeset
   410
    wrap = functools.partial(util.checksignature(wrapper),
a763c891f36e wrapcommand: use functools.partial
Jun Wu <quark@fb.com>
parents: 34104
diff changeset
   411
                             util.checksignature(origfn))
29775
ce6317dcb944 extensions: set attributes to wrappers so we can trace them back
Jun Wu <quark@fb.com>
parents: 29461
diff changeset
   412
    _updatewrapper(wrap, origfn, wrapper)
24124
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   413
    if docstring is not None:
28310
01dc11e7191f extensions: extract function that copies function attributes to wrapper
Yuya Nishihara <yuya@tcha.org>
parents: 28155
diff changeset
   414
        wrap.__doc__ += docstring
24124
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   415
7215
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   416
    newentry = list(entry)
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   417
    newentry[0] = wrap
24124
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   418
    if synopsis is not None:
042d95beeee8 extensions: allow extending command synopsis and docstring
Ryan McElroy <rm@fb.com>
parents: 24065
diff changeset
   419
        newentry[2] += synopsis
7215
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   420
    table[key] = tuple(newentry)
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   421
    return entry
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   422
32742
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   423
def wrapfilecache(cls, propname, wrapper):
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   424
    """Wraps a filecache property.
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   425
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   426
    These can't be wrapped using the normal wrapfunction.
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   427
    """
33857
38a3767975a7 extensions: if on py3 and propname is a bytestr, convert to sysstr
Augie Fackler <augie@google.com>
parents: 33748
diff changeset
   428
    propname = pycompat.sysstr(propname)
32742
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   429
    assert callable(wrapper)
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   430
    for currcls in cls.__mro__:
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   431
        if propname in currcls.__dict__:
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   432
            origfn = currcls.__dict__[propname].func
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   433
            assert callable(origfn)
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   434
            def wrap(*args, **kwargs):
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   435
                return wrapper(origfn, *args, **kwargs)
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   436
            currcls.__dict__[propname].func = wrap
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   437
            break
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   438
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   439
    if currcls is object:
33858
0646608368a9 extensions: don't give AttributeError bytes message on Python 3
Augie Fackler <augie@google.com>
parents: 33857
diff changeset
   440
        raise AttributeError(r"type '%s' has no property '%s'" % (
0646608368a9 extensions: don't give AttributeError bytes message on Python 3
Augie Fackler <augie@google.com>
parents: 33857
diff changeset
   441
            cls, propname))
32742
de09138bf0f5 extensions: move wrapfilecache function from fsmonitor
Augie Fackler <augie@google.com>
parents: 32455
diff changeset
   442
34032
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   443
class wrappedfunction(object):
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   444
    '''context manager for temporarily wrapping a function'''
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   445
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   446
    def __init__(self, container, funcname, wrapper):
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   447
        assert callable(wrapper)
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   448
        self._container = container
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   449
        self._funcname = funcname
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   450
        self._wrapper = wrapper
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   451
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   452
    def __enter__(self):
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   453
        wrapfunction(self._container, self._funcname, self._wrapper)
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   454
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   455
    def __exit__(self, exctype, excvalue, traceback):
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   456
        unwrapfunction(self._container, self._funcname, self._wrapper)
47e52f079a57 extensions: add wrappedfunction() context manager
Martin von Zweigbergk <martinvonz@google.com>
parents: 33858
diff changeset
   457
7215
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   458
def wrapfunction(container, funcname, wrapper):
11402
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   459
    '''Wrap the function named funcname in container
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   460
11520
94b3bbc886cf extensions: improve language for wrapfunction() docstring.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11519
diff changeset
   461
    Replace the funcname member in the given container with the specified
94b3bbc886cf extensions: improve language for wrapfunction() docstring.
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 11519
diff changeset
   462
    wrapper. The container is typically a module, class, or instance.
11402
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   463
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   464
    The wrapper will be called like
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   465
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   466
      wrapper(orig, *args, **kwargs)
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   467
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   468
    where orig is the original (wrapped) function, and *args, **kwargs
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   469
    are the arguments passed to it.
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   470
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   471
    Wrapping methods of the repository object is not recommended since
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   472
    it conflicts with extensions that extend the repository by
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   473
    subclassing. All extensions that need to extend methods of
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   474
    localrepository should use this subclassing trick: namely,
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   475
    reposetup() should look like
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   476
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   477
      def reposetup(ui, repo):
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   478
          class myrepo(repo.__class__):
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   479
              def whatever(self, *args, **kwargs):
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   480
                  [...extension stuff...]
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   481
                  super(myrepo, self).whatever(*args, **kwargs)
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   482
                  [...extension stuff...]
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   483
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   484
          repo.__class__ = myrepo
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   485
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   486
    In general, combining wrapfunction() with subclassing does not
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   487
    work. Since you cannot control what other extensions are loaded by
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   488
    your end users, you should play nicely with others by using the
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   489
    subclass trick.
367ce8514da0 extensions: recommend against using wrapfunction for repo methods
Greg Ward <greg-hg@gerg.ca>
parents: 10364
diff changeset
   490
    '''
21795
711498bb4ff5 extensions: restore use of callable() since it was readded in Python 3.2
Augie Fackler <raf@durin42.com>
parents: 21229
diff changeset
   491
    assert callable(wrapper)
7215
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   492
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   493
    origfn = getattr(container, funcname)
21795
711498bb4ff5 extensions: restore use of callable() since it was readded in Python 3.2
Augie Fackler <raf@durin42.com>
parents: 21229
diff changeset
   494
    assert callable(origfn)
34104
5361771f9714 wrapfunction: use functools.partial if possible
Jun Wu <quark@fb.com>
parents: 34065
diff changeset
   495
    if inspect.ismodule(container):
5361771f9714 wrapfunction: use functools.partial if possible
Jun Wu <quark@fb.com>
parents: 34065
diff changeset
   496
        # origfn is not an instance or class method. "partial" can be used.
5361771f9714 wrapfunction: use functools.partial if possible
Jun Wu <quark@fb.com>
parents: 34065
diff changeset
   497
        # "partial" won't insert a frame in traceback.
5361771f9714 wrapfunction: use functools.partial if possible
Jun Wu <quark@fb.com>
parents: 34065
diff changeset
   498
        wrap = functools.partial(wrapper, origfn)
5361771f9714 wrapfunction: use functools.partial if possible
Jun Wu <quark@fb.com>
parents: 34065
diff changeset
   499
    else:
5361771f9714 wrapfunction: use functools.partial if possible
Jun Wu <quark@fb.com>
parents: 34065
diff changeset
   500
        # "partial" cannot be safely used. Emulate its effect by using "bind".
5361771f9714 wrapfunction: use functools.partial if possible
Jun Wu <quark@fb.com>
parents: 34065
diff changeset
   501
        # The downside is one more frame in traceback.
5361771f9714 wrapfunction: use functools.partial if possible
Jun Wu <quark@fb.com>
parents: 34065
diff changeset
   502
        wrap = bind(wrapper, origfn)
29775
ce6317dcb944 extensions: set attributes to wrappers so we can trace them back
Jun Wu <quark@fb.com>
parents: 29461
diff changeset
   503
    _updatewrapper(wrap, origfn, wrapper)
28311
1b0ef07ba783 extensions: copy attributes to wrapper by wrapfunction()
Yuya Nishihara <yuya@tcha.org>
parents: 28310
diff changeset
   504
    setattr(container, funcname, wrap)
7215
0ab5f21c390b extensions: add wrapping functions
Matt Mackall <mpm@selenic.com>
parents: 7011
diff changeset
   505
    return origfn
8871
20a25042fadc extensions: move extensions listing functions from mercurial.help
Cédric Duval <cedricduval@free.fr>
parents: 8225
diff changeset
   506
29777
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   507
def unwrapfunction(container, funcname, wrapper=None):
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   508
    '''undo wrapfunction
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   509
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   510
    If wrappers is None, undo the last wrap. Otherwise removes the wrapper
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   511
    from the chain of wrappers.
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   512
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   513
    Return the removed wrapper.
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   514
    Raise IndexError if wrapper is None and nothing to unwrap; ValueError if
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   515
    wrapper is not None but is not found in the wrapper chain.
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   516
    '''
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   517
    chain = getwrapperchain(container, funcname)
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   518
    origfn = chain.pop()
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   519
    if wrapper is None:
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   520
        wrapper = chain[0]
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   521
    chain.remove(wrapper)
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   522
    setattr(container, funcname, origfn)
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   523
    for w in reversed(chain):
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   524
        wrapfunction(container, funcname, w)
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   525
    return wrapper
19578bb84731 extensions: add unwrapfunction to undo wrapfunction
Jun Wu <quark@fb.com>
parents: 29776
diff changeset
   526
29776
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   527
def getwrapperchain(container, funcname):
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   528
    '''get a chain of wrappers of a function
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   529
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   530
    Return a list of functions: [newest wrapper, ..., oldest wrapper, origfunc]
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   531
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   532
    The wrapper functions are the ones passed to wrapfunction, whose first
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   533
    argument is origfunc.
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   534
    '''
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   535
    result = []
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   536
    fn = getattr(container, funcname)
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   537
    while fn:
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   538
        assert callable(fn)
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   539
        result.append(getattr(fn, '_unboundwrapper', fn))
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   540
        fn = getattr(fn, '_origfunc', None)
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   541
    return result
8bf97c4c6c2a extensions: add getwrapperchain to get a list of wrappers
Jun Wu <quark@fb.com>
parents: 29775
diff changeset
   542
38196
b39958d6b81b extensions: remove strip_init=True from _disabledpaths()
Yuya Nishihara <yuya@tcha.org>
parents: 38195
diff changeset
   543
def _disabledpaths():
b39958d6b81b extensions: remove strip_init=True from _disabledpaths()
Yuya Nishihara <yuya@tcha.org>
parents: 38195
diff changeset
   544
    '''find paths of disabled extensions. returns a dict of {name: path}'''
8872
d0c0013f8713 extensions: simplify by selecting primary hgext
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8871
diff changeset
   545
    import hgext
31091
2912b06905dc py3: use pycompat.fsencode() to convert __file__ to bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30580
diff changeset
   546
    extpath = os.path.dirname(
2912b06905dc py3: use pycompat.fsencode() to convert __file__ to bytes
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30580
diff changeset
   547
        os.path.abspath(pycompat.fsencode(hgext.__file__)))
8964
119d1f664eae extensions: catch OSError when hgext is not accessible (issue1708)
Cédric Duval <cedricduval@free.fr>
parents: 8896
diff changeset
   548
    try: # might not be a filesystem path
119d1f664eae extensions: catch OSError when hgext is not accessible (issue1708)
Cédric Duval <cedricduval@free.fr>
parents: 8896
diff changeset
   549
        files = os.listdir(extpath)
119d1f664eae extensions: catch OSError when hgext is not accessible (issue1708)
Cédric Duval <cedricduval@free.fr>
parents: 8896
diff changeset
   550
    except OSError:
10363
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   551
        return {}
8964
119d1f664eae extensions: catch OSError when hgext is not accessible (issue1708)
Cédric Duval <cedricduval@free.fr>
parents: 8896
diff changeset
   552
8871
20a25042fadc extensions: move extensions listing functions from mercurial.help
Cédric Duval <cedricduval@free.fr>
parents: 8225
diff changeset
   553
    exts = {}
8964
119d1f664eae extensions: catch OSError when hgext is not accessible (issue1708)
Cédric Duval <cedricduval@free.fr>
parents: 8896
diff changeset
   554
    for e in files:
8872
d0c0013f8713 extensions: simplify by selecting primary hgext
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8871
diff changeset
   555
        if e.endswith('.py'):
d0c0013f8713 extensions: simplify by selecting primary hgext
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8871
diff changeset
   556
            name = e.rsplit('.', 1)[0]
d0c0013f8713 extensions: simplify by selecting primary hgext
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8871
diff changeset
   557
            path = os.path.join(extpath, e)
d0c0013f8713 extensions: simplify by selecting primary hgext
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8871
diff changeset
   558
        else:
d0c0013f8713 extensions: simplify by selecting primary hgext
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8871
diff changeset
   559
            name = e
d0c0013f8713 extensions: simplify by selecting primary hgext
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8871
diff changeset
   560
            path = os.path.join(extpath, e, '__init__.py')
8877
08636e18268f extensions: check for path existence only when necessary
Cédric Duval <cedricduval@free.fr>
parents: 8876
diff changeset
   561
            if not os.path.exists(path):
08636e18268f extensions: check for path existence only when necessary
Cédric Duval <cedricduval@free.fr>
parents: 8876
diff changeset
   562
                continue
10363
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   563
        if name in exts or name in _order or name == '__init__':
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   564
            continue
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   565
        exts[name] = path
33327
68b7ceda99d7 dispatch: fix typo suggestion for disabled extension
Martin von Zweigbergk <martinvonz@google.com>
parents: 33139
diff changeset
   566
    for name, path in _disabledextensions.iteritems():
68b7ceda99d7 dispatch: fix typo suggestion for disabled extension
Martin von Zweigbergk <martinvonz@google.com>
parents: 33139
diff changeset
   567
        # If no path was provided for a disabled extension (e.g. "color=!"),
68b7ceda99d7 dispatch: fix typo suggestion for disabled extension
Martin von Zweigbergk <martinvonz@google.com>
parents: 33139
diff changeset
   568
        # don't replace the path we already found by the scan above.
68b7ceda99d7 dispatch: fix typo suggestion for disabled extension
Martin von Zweigbergk <martinvonz@google.com>
parents: 33139
diff changeset
   569
        if path:
68b7ceda99d7 dispatch: fix typo suggestion for disabled extension
Martin von Zweigbergk <martinvonz@google.com>
parents: 33139
diff changeset
   570
            exts[name] = path
10363
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   571
    return exts
8872
d0c0013f8713 extensions: simplify by selecting primary hgext
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents: 8871
diff changeset
   572
14317
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   573
def _moduledoc(file):
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   574
    '''return the top-level python documentation for the given file
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   575
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   576
    Loosely inspired by pydoc.source_synopsis(), but rewritten to
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   577
    handle triple quotes and to return the whole text instead of just
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   578
    the synopsis'''
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   579
    result = []
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   580
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   581
    line = file.readline()
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   582
    while line[:1] == '#' or not line.strip():
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   583
        line = file.readline()
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   584
        if not line:
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   585
            break
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   586
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   587
    start = line[:3]
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   588
    if start == '"""' or start == "'''":
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   589
        line = line[3:]
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   590
        while line:
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   591
            if line.rstrip().endswith(start):
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   592
                line = line.split(start)[0]
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   593
                if line:
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   594
                    result.append(line)
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   595
                break
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   596
            elif not line:
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   597
                return None # unmatched delimiter
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   598
            result.append(line)
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   599
            line = file.readline()
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   600
    else:
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   601
        return None
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   602
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   603
    return ''.join(result)
660b0c1b6196 extensions: move moduledoc to break import loop with help
Matt Mackall <mpm@selenic.com>
parents: 14316
diff changeset
   604
10363
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   605
def _disabledhelp(path):
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   606
    '''retrieve help synopsis of a disabled extension (without importing)'''
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   607
    try:
38350
c6f82a18a63d extensions: use context manger for open()
Yuya Nishihara <yuya@tcha.org>
parents: 38349
diff changeset
   608
        with open(path, 'rb') as src:
c6f82a18a63d extensions: use context manger for open()
Yuya Nishihara <yuya@tcha.org>
parents: 38349
diff changeset
   609
            doc = _moduledoc(src)
10363
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   610
    except IOError:
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   611
        return
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   612
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   613
    if doc: # extracting localized synopsis
30319
5581b294f3c6 help: show help for disabled extensions (issue5228)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30058
diff changeset
   614
        return gettext(doc)
10363
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   615
    else:
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   616
        return _('(no help text available)')
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   617
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   618
def disabled():
14530
cd31a1cc1521 extensions: update doc of enabled() and disabled() according to d5b525697ddb
Yuya Nishihara <yuya@tcha.org>
parents: 14415
diff changeset
   619
    '''find disabled extensions from hgext. returns a dict of {name: desc}'''
14539
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   620
    try:
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   621
        from hgext import __index__
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   622
        return dict((name, gettext(desc))
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   623
                    for name, desc in __index__.docs.iteritems()
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   624
                    if name not in _order)
21229
54d7657d7d1e setup.py, make: avoid problems with outdated, existing hgext/__index__.py*
Thomas Arendsen Hein <thomas@intevation.de>
parents: 20645
diff changeset
   625
    except (ImportError, AttributeError):
14539
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   626
        pass
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   627
10363
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   628
    paths = _disabledpaths()
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   629
    if not paths:
16709
9eca39a91964 extensions.disabled: return {} instead of None no extensions are disabled
Augie Fackler <raf@durin42.com>
parents: 16667
diff changeset
   630
        return {}
10363
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   631
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   632
    exts = {}
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   633
    for name, path in paths.iteritems():
c07974215b3d extensions: refactor disabled()
Brodie Rao <me+hg@dackz.net>
parents: 10263
diff changeset
   634
        doc = _disabledhelp(path)
14316
d5b525697ddb extensions: drop maxlength from enabled and disabled
Matt Mackall <mpm@selenic.com>
parents: 14079
diff changeset
   635
        if doc:
30319
5581b294f3c6 help: show help for disabled extensions (issue5228)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30058
diff changeset
   636
            exts[name] = doc.splitlines()[0]
8871
20a25042fadc extensions: move extensions listing functions from mercurial.help
Cédric Duval <cedricduval@free.fr>
parents: 8225
diff changeset
   637
14316
d5b525697ddb extensions: drop maxlength from enabled and disabled
Matt Mackall <mpm@selenic.com>
parents: 14079
diff changeset
   638
    return exts
8871
20a25042fadc extensions: move extensions listing functions from mercurial.help
Cédric Duval <cedricduval@free.fr>
parents: 8225
diff changeset
   639
10364
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   640
def disabledext(name):
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   641
    '''find a specific disabled extension from hgext. returns desc'''
14539
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   642
    try:
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   643
        from hgext import __index__
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   644
        if name in _order:  # enabled
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   645
            return
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   646
        else:
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   647
            return gettext(__index__.docs.get(name))
21229
54d7657d7d1e setup.py, make: avoid problems with outdated, existing hgext/__index__.py*
Thomas Arendsen Hein <thomas@intevation.de>
parents: 20645
diff changeset
   648
    except (ImportError, AttributeError):
14539
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   649
        pass
558ec14ba6be extensions: make disabled()/disabledext() load prebuilt index if available
Yuya Nishihara <yuya@tcha.org>
parents: 14530
diff changeset
   650
10364
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   651
    paths = _disabledpaths()
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   652
    if name in paths:
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   653
        return _disabledhelp(paths[name])
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   654
38195
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   655
def _walkcommand(node):
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   656
    """Scan @command() decorators in the tree starting at node"""
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   657
    todo = collections.deque([node])
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   658
    while todo:
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   659
        node = todo.popleft()
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   660
        if not isinstance(node, ast.FunctionDef):
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   661
            todo.extend(ast.iter_child_nodes(node))
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   662
            continue
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   663
        for d in node.decorator_list:
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   664
            if not isinstance(d, ast.Call):
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   665
                continue
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   666
            if not isinstance(d.func, ast.Name):
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   667
                continue
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   668
            if d.func.id != r'command':
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   669
                continue
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   670
            yield d
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   671
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   672
def _disabledcmdtable(path):
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   673
    """Construct a dummy command table without loading the extension module
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   674
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   675
    This may raise IOError or SyntaxError.
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   676
    """
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   677
    with open(path, 'rb') as src:
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   678
        root = ast.parse(src.read(), path)
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   679
    cmdtable = {}
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   680
    for node in _walkcommand(root):
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   681
        if not node.args:
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   682
            continue
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   683
        a = node.args[0]
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   684
        if isinstance(a, ast.Str):
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   685
            name = pycompat.sysbytes(a.s)
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   686
        elif pycompat.ispy3 and isinstance(a, ast.Bytes):
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   687
            name = a.s
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   688
        else:
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   689
            continue
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   690
        cmdtable[name] = (None, [], b'')
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   691
    return cmdtable
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   692
38018
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   693
def _finddisabledcmd(ui, cmd, name, path, strict):
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   694
    try:
38195
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   695
        cmdtable = _disabledcmdtable(path)
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   696
    except (IOError, SyntaxError):
38018
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   697
        return
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   698
    try:
38195
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   699
        aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
38018
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   700
    except (error.AmbiguousCommand, error.UnknownCommand):
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   701
        return
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   702
    for c in aliases:
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   703
        if c.startswith(cmd):
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   704
            cmd = c
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   705
            break
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   706
    else:
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   707
        cmd = aliases[0]
38195
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   708
    doc = _disabledhelp(path)
38019
6e526b0961a8 help: load module doc of disabled extension in extensions.disabledcmd()
Yuya Nishihara <yuya@tcha.org>
parents: 38018
diff changeset
   709
    return (cmd, name, doc)
38018
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   710
13191
1aea66b71f4f extensions: warn about invalid extensions when listing disabled commands
Mads Kiilerich <mads@kiilerich.com>
parents: 12779
diff changeset
   711
def disabledcmd(ui, cmd, strict=False):
38195
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   712
    '''find cmd from disabled extensions without importing.
38019
6e526b0961a8 help: load module doc of disabled extension in extensions.disabledcmd()
Yuya Nishihara <yuya@tcha.org>
parents: 38018
diff changeset
   713
    returns (cmdname, extname, doc)'''
10364
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   714
38195
bdf344aea0ee extensions: peek command table of disabled extensions without importing
Yuya Nishihara <yuya@tcha.org>
parents: 38062
diff changeset
   715
    paths = _disabledpaths()
10364
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   716
    if not paths:
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   717
        raise error.UnknownCommand(cmd)
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   718
16667
bdb7ae65c27c extensions: don't suggest commands from deprecated extensions
Martin Geisler <mg@lazybytes.net>
parents: 16666
diff changeset
   719
    ext = None
10364
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   720
    # first, search for an extension with the same name as the command
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   721
    path = paths.pop(cmd, None)
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   722
    if path:
38018
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   723
        ext = _finddisabledcmd(ui, cmd, cmd, path, strict=strict)
16667
bdb7ae65c27c extensions: don't suggest commands from deprecated extensions
Martin Geisler <mg@lazybytes.net>
parents: 16666
diff changeset
   724
    if not ext:
bdb7ae65c27c extensions: don't suggest commands from deprecated extensions
Martin Geisler <mg@lazybytes.net>
parents: 16666
diff changeset
   725
        # otherwise, interrogate each extension until there's a match
bdb7ae65c27c extensions: don't suggest commands from deprecated extensions
Martin Geisler <mg@lazybytes.net>
parents: 16666
diff changeset
   726
        for name, path in paths.iteritems():
38018
b45f4c1532c0 extensions: extract closure that looks for commands from disabled module
Yuya Nishihara <yuya@tcha.org>
parents: 38017
diff changeset
   727
            ext = _finddisabledcmd(ui, cmd, name, path, strict=strict)
16667
bdb7ae65c27c extensions: don't suggest commands from deprecated extensions
Martin Geisler <mg@lazybytes.net>
parents: 16666
diff changeset
   728
            if ext:
bdb7ae65c27c extensions: don't suggest commands from deprecated extensions
Martin Geisler <mg@lazybytes.net>
parents: 16666
diff changeset
   729
                break
38017
5b60f7d652f2 extensions: drop dead code trying to exclude deprecated disabled commands
Yuya Nishihara <yuya@tcha.org>
parents: 38001
diff changeset
   730
    if ext:
16667
bdb7ae65c27c extensions: don't suggest commands from deprecated extensions
Martin Geisler <mg@lazybytes.net>
parents: 16666
diff changeset
   731
        return ext
10364
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   732
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   733
    raise error.UnknownCommand(cmd)
de1e7099d100 dispatch: provide help for disabled extensions and commands
Brodie Rao <me+hg@dackz.net>
parents: 10363
diff changeset
   734
19769
83d79a00cc24 help: use full name of extensions to look up them for keyword search
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 18692
diff changeset
   735
def enabled(shortname=True):
14530
cd31a1cc1521 extensions: update doc of enabled() and disabled() according to d5b525697ddb
Yuya Nishihara <yuya@tcha.org>
parents: 14415
diff changeset
   736
    '''return a dict of {name: desc} of extensions'''
8871
20a25042fadc extensions: move extensions listing functions from mercurial.help
Cédric Duval <cedricduval@free.fr>
parents: 8225
diff changeset
   737
    exts = {}
20a25042fadc extensions: move extensions listing functions from mercurial.help
Cédric Duval <cedricduval@free.fr>
parents: 8225
diff changeset
   738
    for ename, ext in extensions():
20a25042fadc extensions: move extensions listing functions from mercurial.help
Cédric Duval <cedricduval@free.fr>
parents: 8225
diff changeset
   739
        doc = (gettext(ext.__doc__) or _('(no help text available)'))
19769
83d79a00cc24 help: use full name of extensions to look up them for keyword search
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 18692
diff changeset
   740
        if shortname:
83d79a00cc24 help: use full name of extensions to look up them for keyword search
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 18692
diff changeset
   741
            ename = ename.split('.')[-1]
9136
31177742f54a for calls expecting bool args, pass bool instead of int
Nicolas Dumazet <nicdumz.commits@gmail.com>
parents: 9020
diff changeset
   742
        exts[ename] = doc.splitlines()[0].strip()
8871
20a25042fadc extensions: move extensions listing functions from mercurial.help
Cédric Duval <cedricduval@free.fr>
parents: 8225
diff changeset
   743
14316
d5b525697ddb extensions: drop maxlength from enabled and disabled
Matt Mackall <mpm@selenic.com>
parents: 14079
diff changeset
   744
    return exts
21848
ecdbbb6e5d06 version: show enabled extensions (issue4209)
anatoly techtonik <techtonik@gmail.com>
parents: 21795
diff changeset
   745
28155
7f430b2ac7fd extensions: add notloaded method to return extensions failed to load
Jun Wu <quark@fb.com>
parents: 27990
diff changeset
   746
def notloaded():
7f430b2ac7fd extensions: add notloaded method to return extensions failed to load
Jun Wu <quark@fb.com>
parents: 27990
diff changeset
   747
    '''return short names of extensions that failed to load'''
7f430b2ac7fd extensions: add notloaded method to return extensions failed to load
Jun Wu <quark@fb.com>
parents: 27990
diff changeset
   748
    return [name for name, mod in _extensions.iteritems() if mod is None]
7f430b2ac7fd extensions: add notloaded method to return extensions failed to load
Jun Wu <quark@fb.com>
parents: 27990
diff changeset
   749
21848
ecdbbb6e5d06 version: show enabled extensions (issue4209)
anatoly techtonik <techtonik@gmail.com>
parents: 21795
diff changeset
   750
def moduleversion(module):
ecdbbb6e5d06 version: show enabled extensions (issue4209)
anatoly techtonik <techtonik@gmail.com>
parents: 21795
diff changeset
   751
    '''return version information from given module as a string'''
ecdbbb6e5d06 version: show enabled extensions (issue4209)
anatoly techtonik <techtonik@gmail.com>
parents: 21795
diff changeset
   752
    if (util.safehasattr(module, 'getversion')
ecdbbb6e5d06 version: show enabled extensions (issue4209)
anatoly techtonik <techtonik@gmail.com>
parents: 21795
diff changeset
   753
          and callable(module.getversion)):
ecdbbb6e5d06 version: show enabled extensions (issue4209)
anatoly techtonik <techtonik@gmail.com>
parents: 21795
diff changeset
   754
        version = module.getversion()
ecdbbb6e5d06 version: show enabled extensions (issue4209)
anatoly techtonik <techtonik@gmail.com>
parents: 21795
diff changeset
   755
    elif util.safehasattr(module, '__version__'):
ecdbbb6e5d06 version: show enabled extensions (issue4209)
anatoly techtonik <techtonik@gmail.com>
parents: 21795
diff changeset
   756
        version = module.__version__
ecdbbb6e5d06 version: show enabled extensions (issue4209)
anatoly techtonik <techtonik@gmail.com>
parents: 21795
diff changeset
   757
    else:
ecdbbb6e5d06 version: show enabled extensions (issue4209)
anatoly techtonik <techtonik@gmail.com>
parents: 21795
diff changeset
   758
        version = ''
ecdbbb6e5d06 version: show enabled extensions (issue4209)
anatoly techtonik <techtonik@gmail.com>
parents: 21795
diff changeset
   759
    if isinstance(version, (list, tuple)):
38062
9d44c71bd892 py3: use pycompat.bytestr() instead of str() in extensions.py
Pulkit Goyal <7895pulkit@gmail.com>
parents: 38019
diff changeset
   760
        version = '.'.join(pycompat.bytestr(o) for o in version)
21848
ecdbbb6e5d06 version: show enabled extensions (issue4209)
anatoly techtonik <techtonik@gmail.com>
parents: 21795
diff changeset
   761
    return version
27990
96bfd2875213 version: verbose list internal and external extension source (issue4731)
liscju <piotr.listkiewicz@gmail.com>
parents: 27637
diff changeset
   762
96bfd2875213 version: verbose list internal and external extension source (issue4731)
liscju <piotr.listkiewicz@gmail.com>
parents: 27637
diff changeset
   763
def ismoduleinternal(module):
96bfd2875213 version: verbose list internal and external extension source (issue4731)
liscju <piotr.listkiewicz@gmail.com>
parents: 27637
diff changeset
   764
    exttestedwith = getattr(module, 'testedwith', None)
29852
d5883fd055c6 extensions: change magic "shipped with hg" string
Augie Fackler <augie@google.com>
parents: 29777
diff changeset
   765
    return exttestedwith == "ships-with-hg-core"