mercurial/extensions.py
branchstable
changeset 49366 288de6f5d724
parent 49026 2d519511c5c3
child 49776 9d8757ddd0ab
equal deleted inserted replaced
49364:e8ea403b1c46 49366:288de6f5d724
     3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
     3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
     4 #
     4 #
     5 # This software may be used and distributed according to the terms of the
     5 # This software may be used and distributed according to the terms of the
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 from __future__ import absolute_import
       
     9 
     8 
    10 import ast
     9 import ast
    11 import collections
    10 import collections
    12 import functools
    11 import functools
    13 import imp
    12 import imp
    72     '''return module with given extension name'''
    71     '''return module with given extension name'''
    73     mod = None
    72     mod = None
    74     try:
    73     try:
    75         mod = _extensions[name]
    74         mod = _extensions[name]
    76     except KeyError:
    75     except KeyError:
    77         for k, v in pycompat.iteritems(_extensions):
    76         for k, v in _extensions.items():
    78             if k.endswith(b'.' + name) or k.endswith(b'/' + name):
    77             if k.endswith(b'.' + name) or k.endswith(b'/' + name):
    79                 mod = v
    78                 mod = v
    80                 break
    79                 break
    81     if not mod:
    80     if not mod:
    82         raise KeyError(name)
    81         raise KeyError(name)
   169 _cmdfuncattrs = (b'norepo', b'optionalrepo', b'inferrepo')
   168 _cmdfuncattrs = (b'norepo', b'optionalrepo', b'inferrepo')
   170 
   169 
   171 
   170 
   172 def _validatecmdtable(ui, cmdtable):
   171 def _validatecmdtable(ui, cmdtable):
   173     """Check if extension commands have required attributes"""
   172     """Check if extension commands have required attributes"""
   174     for c, e in pycompat.iteritems(cmdtable):
   173     for c, e in cmdtable.items():
   175         f = e[0]
   174         f = e[0]
   176         missing = [a for a in _cmdfuncattrs if not util.safehasattr(f, a)]
   175         missing = [a for a in _cmdfuncattrs if not util.safehasattr(f, a)]
   177         if not missing:
   176         if not missing:
   178             continue
   177             continue
   179         raise error.ProgrammingError(
   178         raise error.ProgrammingError(
   577       extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
   576       extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
   578                              synopsis, docstring)
   577                              synopsis, docstring)
   579     '''
   578     '''
   580     assert callable(wrapper)
   579     assert callable(wrapper)
   581     aliases, entry = cmdutil.findcmd(command, table)
   580     aliases, entry = cmdutil.findcmd(command, table)
   582     for alias, e in pycompat.iteritems(table):
   581     for alias, e in table.items():
   583         if e is entry:
   582         if e is entry:
   584             key = alias
   583             key = alias
   585             break
   584             break
   586 
   585 
   587     origfn = entry[0]
   586     origfn = entry[0]
   620 
   619 
   621     if currcls is object:
   620     if currcls is object:
   622         raise AttributeError("type '%s' has no property '%s'" % (cls, propname))
   621         raise AttributeError("type '%s' has no property '%s'" % (cls, propname))
   623 
   622 
   624 
   623 
   625 class wrappedfunction(object):
   624 class wrappedfunction:
   626     '''context manager for temporarily wrapping a function'''
   625     '''context manager for temporarily wrapping a function'''
   627 
   626 
   628     def __init__(self, container, funcname, wrapper):
   627     def __init__(self, container, funcname, wrapper):
   629         assert callable(wrapper)
   628         assert callable(wrapper)
   630         self._container = container
   629         self._container = container
   754             if not os.path.exists(path):
   753             if not os.path.exists(path):
   755                 continue
   754                 continue
   756         if name in exts or name in _order or name == b'__init__':
   755         if name in exts or name in _order or name == b'__init__':
   757             continue
   756             continue
   758         exts[name] = path
   757         exts[name] = path
   759     for name, path in pycompat.iteritems(_disabledextensions):
   758     for name, path in _disabledextensions.items():
   760         # If no path was provided for a disabled extension (e.g. "color=!"),
   759         # If no path was provided for a disabled extension (e.g. "color=!"),
   761         # don't replace the path we already found by the scan above.
   760         # don't replace the path we already found by the scan above.
   762         if path:
   761         if path:
   763             exts[name] = path
   762             exts[name] = path
   764     return exts
   763     return exts
   816     try:
   815     try:
   817         from hgext import __index__  # pytype: disable=import-error
   816         from hgext import __index__  # pytype: disable=import-error
   818 
   817 
   819         return {
   818         return {
   820             name: gettext(desc)
   819             name: gettext(desc)
   821             for name, desc in pycompat.iteritems(__index__.docs)
   820             for name, desc in __index__.docs.items()
   822             if name not in _order
   821             if name not in _order
   823         }
   822         }
   824     except (ImportError, AttributeError):
   823     except (ImportError, AttributeError):
   825         pass
   824         pass
   826 
   825 
   827     paths = _disabledpaths()
   826     paths = _disabledpaths()
   828     if not paths:
   827     if not paths:
   829         return {}
   828         return {}
   830 
   829 
   831     exts = {}
   830     exts = {}
   832     for name, path in pycompat.iteritems(paths):
   831     for name, path in paths.items():
   833         doc = _disabledhelp(path)
   832         doc = _disabledhelp(path)
   834         if doc and name != b'__index__':
   833         if doc and name != b'__index__':
   835             exts[name] = doc.splitlines()[0]
   834             exts[name] = stringutil.firstline(doc)
   836 
   835 
   837     return exts
   836     return exts
   838 
   837 
   839 
   838 
   840 def disabled_help(name):
   839 def disabled_help(name):
   874         if not node.args:
   873         if not node.args:
   875             continue
   874             continue
   876         a = node.args[0]
   875         a = node.args[0]
   877         if isinstance(a, ast.Str):
   876         if isinstance(a, ast.Str):
   878             name = pycompat.sysbytes(a.s)
   877             name = pycompat.sysbytes(a.s)
   879         elif pycompat.ispy3 and isinstance(a, ast.Bytes):
   878         elif isinstance(a, ast.Bytes):
   880             name = a.s
   879             name = a.s
   881         else:
   880         else:
   882             continue
   881             continue
   883         cmdtable[name] = (None, [], b'')
   882         cmdtable[name] = (None, [], b'')
   884     return cmdtable
   883     return cmdtable
   916     path = paths.pop(cmd, None)
   915     path = paths.pop(cmd, None)
   917     if path:
   916     if path:
   918         ext = _finddisabledcmd(ui, cmd, cmd, path, strict=strict)
   917         ext = _finddisabledcmd(ui, cmd, cmd, path, strict=strict)
   919     if not ext:
   918     if not ext:
   920         # otherwise, interrogate each extension until there's a match
   919         # otherwise, interrogate each extension until there's a match
   921         for name, path in pycompat.iteritems(paths):
   920         for name, path in paths.items():
   922             ext = _finddisabledcmd(ui, cmd, name, path, strict=strict)
   921             ext = _finddisabledcmd(ui, cmd, name, path, strict=strict)
   923             if ext:
   922             if ext:
   924                 break
   923                 break
   925     if ext:
   924     if ext:
   926         return ext
   925         return ext
   934     for ename, ext in extensions():
   933     for ename, ext in extensions():
   935         doc = gettext(ext.__doc__) or _(b'(no help text available)')
   934         doc = gettext(ext.__doc__) or _(b'(no help text available)')
   936         assert doc is not None  # help pytype
   935         assert doc is not None  # help pytype
   937         if shortname:
   936         if shortname:
   938             ename = ename.split(b'.')[-1]
   937             ename = ename.split(b'.')[-1]
   939         exts[ename] = doc.splitlines()[0].strip()
   938         exts[ename] = stringutil.firstline(doc).strip()
   940 
   939 
   941     return exts
   940     return exts
   942 
   941 
   943 
   942 
   944 def notloaded():
   943 def notloaded():
   945     '''return short names of extensions that failed to load'''
   944     '''return short names of extensions that failed to load'''
   946     return [
   945     return [name for name, mod in _extensions.items() if mod is None]
   947         name for name, mod in pycompat.iteritems(_extensions) if mod is None
       
   948     ]
       
   949 
   946 
   950 
   947 
   951 def moduleversion(module):
   948 def moduleversion(module):
   952     '''return version information from given module as a string'''
   949     '''return version information from given module as a string'''
   953     if util.safehasattr(module, b'getversion') and callable(module.getversion):
   950     if util.safehasattr(module, b'getversion') and callable(module.getversion):