##// END OF EJS Templates
rollback: fix up tests
rollback: fix up tests

File last commit:

r10364:de1e7099 default
r11175:39e7f14a default
Show More
extensions.py
254 lines | 7.3 KiB | text/x-python | PythonLexer
Matt Mackall
Create a separate module for managing extensions
r4544 # extensions.py - extension handling for mercurial
#
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
Matt Mackall
Create a separate module for managing extensions
r4544 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Matt Mackall
Create a separate module for managing extensions
r4544
Cédric Duval
extensions: remove import rendered unnecessary by e4e22a310b62
r8896 import imp, os
Brodie Rao
dispatch: provide help for disabled extensions and commands...
r10364 import util, cmdutil, help, error
Cédric Duval
extensions: move extensions listing functions from mercurial.help...
r8871 from i18n import _, gettext
Matt Mackall
Create a separate module for managing extensions
r4544
_extensions = {}
Alexis S. L. Carvalho
Move cmdtable and reposetup handling out of extensions.py...
r5192 _order = []
def extensions():
for name in _order:
module = _extensions[name]
if module:
yield name, module
Matt Mackall
Create a separate module for managing extensions
r4544
def find(name):
'''return module with given extension name'''
try:
return _extensions[name]
except KeyError:
for k, v in _extensions.iteritems():
Matt Mackall
extensions: fix lookup of hgext.foo modules
r4560 if k.endswith('.' + name) or k.endswith('/' + name):
return v
Matt Mackall
Create a separate module for managing extensions
r4544 raise KeyError(name)
Alexander Solovyov
ability to load hooks from arbitrary python module
r7916 def loadpath(path, module_name):
module_name = module_name.replace('.', '_')
Alexander Solovyov
make path expanding more consistent...
r9610 path = util.expandpath(path)
Alexander Solovyov
ability to load hooks from arbitrary python module
r7916 if os.path.isdir(path):
# module/__init__.py style
Alexander Solovyov
extensions loading: don't fail if path to extension ends with a '/'
r7960 d, f = os.path.split(path.rstrip('/'))
Alexander Solovyov
ability to load hooks from arbitrary python module
r7916 fd, fpath, desc = imp.find_module(f, [d])
return imp.load_module(module_name, fd, fpath, desc)
else:
return imp.load_source(module_name, path)
Matt Mackall
Create a separate module for managing extensions
r4544 def load(ui, name, path):
Martin Geisler
extensions: load and configure extensions in well-defined phases...
r9410 # unused ui argument kept for backwards compatibility
Benoit Boissinot
Do not try to load extensions twice (issue811)
r7011 if name.startswith('hgext.') or name.startswith('hgext/'):
Bryan O'Sullivan
extensions: don't get confused by aliasing between "foo" and "hgext.foo"
r5031 shortname = name[6:]
else:
shortname = name
if shortname in _extensions:
Matt Mackall
Create a separate module for managing extensions
r4544 return
Brendan Cully
Cache extension load failures....
r5087 _extensions[shortname] = None
Matt Mackall
Create a separate module for managing extensions
r4544 if path:
# the module will be loaded in sys.modules
# choose an unique name so that it doesn't
# conflicts with other modules
Alexander Solovyov
ability to load hooks from arbitrary python module
r7916 mod = loadpath(path, 'hgext.%s' % name)
Matt Mackall
Create a separate module for managing extensions
r4544 else:
def importh(name):
mod = __import__(name)
components = name.split('.')
for comp in components[1:]:
mod = getattr(mod, comp)
return mod
try:
mod = importh("hgext.%s" % name)
except ImportError:
mod = importh(name)
Bryan O'Sullivan
extensions: don't get confused by aliasing between "foo" and "hgext.foo"
r5031 _extensions[shortname] = mod
Alexis S. L. Carvalho
Move cmdtable and reposetup handling out of extensions.py...
r5192 _order.append(shortname)
Matt Mackall
Create a separate module for managing extensions
r4544
def loadall(ui):
Matt Mackall
extensions: pull extension-aware bits out of ui
r4617 result = ui.configitems("extensions")
Martin Geisler
extensions: load and configure extensions in well-defined phases...
r9410 newindex = len(_order)
Peter Arrenbrecht
cleanup: drop enumerate() when index is not used
r7876 for (name, path) in result:
Matt Mackall
extensions: pull extension-aware bits out of ui
r4617 if path:
Steve Borho
Allow explicit disabling of extensions...
r5469 if path[0] == '!':
continue
Matt Mackall
Create a separate module for managing extensions
r4544 try:
load(ui, name, path)
Matt Mackall
error: move SignalInterrupt...
r7644 except KeyboardInterrupt:
Matt Mackall
Create a separate module for managing extensions
r4544 raise
except Exception, inst:
Jesse Glick
When failing to load an extension, show where Hg tried to load it from.
r6204 if path:
ui.warn(_("*** failed to import extension %s from %s: %s\n")
% (name, path, inst))
else:
ui.warn(_("*** failed to import extension %s: %s\n")
% (name, inst))
Matt Mackall
ui: print_exc() -> traceback()
r8206 if ui.traceback():
Matt Mackall
Create a separate module for managing extensions
r4544 return 1
Martin Geisler
extensions: load and configure extensions in well-defined phases...
r9410 for name in _order[newindex:]:
uisetup = getattr(_extensions[name], 'uisetup', None)
if uisetup:
uisetup(ui)
Yuya Nishihara
extensions: changed to call extsetup() from extensions.loadall()...
r9660 for name in _order[newindex:]:
extsetup = getattr(_extensions[name], 'extsetup', None)
if extsetup:
try:
extsetup(ui)
except TypeError:
if extsetup.func_code.co_argcount != 0:
raise
extsetup() # old extsetup with no ui argument
Matt Mackall
extensions: add wrapping functions
r7215 def wrapcommand(table, command, wrapper):
aliases, entry = cmdutil.findcmd(command, table)
for alias, e in table.iteritems():
if e is entry:
key = alias
break
origfn = entry[0]
def wrap(*args, **kwargs):
Matt Mackall
dispatch: generalize signature checking for extension command wrapping
r7388 return util.checksignature(wrapper)(
util.checksignature(origfn), *args, **kwargs)
Matt Mackall
extensions: add wrapping functions
r7215
wrap.__doc__ = getattr(origfn, '__doc__')
Dirkjan Ochtman
extensions: copy __module__ for wrapped commands
r7373 wrap.__module__ = getattr(origfn, '__module__')
Matt Mackall
extensions: add wrapping functions
r7215
newentry = list(entry)
newentry[0] = wrap
table[key] = tuple(newentry)
return entry
def wrapfunction(container, funcname, wrapper):
def wrap(*args, **kwargs):
return wrapper(origfn, *args, **kwargs)
origfn = getattr(container, funcname)
setattr(container, funcname, wrap)
return origfn
Cédric Duval
extensions: move extensions listing functions from mercurial.help...
r8871
Brodie Rao
dispatch: provide help for disabled extensions and commands...
r10364 def _disabledpaths(strip_init=False):
'''find paths of disabled extensions. returns a dict of {name: path}
removes /__init__.py from packages if strip_init is True'''
Dirkjan Ochtman
extensions: simplify by selecting primary hgext
r8872 import hgext
extpath = os.path.dirname(os.path.abspath(hgext.__file__))
Cédric Duval
extensions: catch OSError when hgext is not accessible (issue1708)...
r8964 try: # might not be a filesystem path
files = os.listdir(extpath)
except OSError:
Brodie Rao
extensions: refactor disabled()
r10363 return {}
Cédric Duval
extensions: catch OSError when hgext is not accessible (issue1708)...
r8964
Cédric Duval
extensions: move extensions listing functions from mercurial.help...
r8871 exts = {}
Cédric Duval
extensions: catch OSError when hgext is not accessible (issue1708)...
r8964 for e in files:
Dirkjan Ochtman
extensions: simplify by selecting primary hgext
r8872 if e.endswith('.py'):
name = e.rsplit('.', 1)[0]
path = os.path.join(extpath, e)
else:
name = e
path = os.path.join(extpath, e, '__init__.py')
Cédric Duval
extensions: check for path existence only when necessary
r8877 if not os.path.exists(path):
continue
Brodie Rao
dispatch: provide help for disabled extensions and commands...
r10364 if strip_init:
path = os.path.dirname(path)
Brodie Rao
extensions: refactor disabled()
r10363 if name in exts or name in _order or name == '__init__':
continue
exts[name] = path
return exts
Dirkjan Ochtman
extensions: simplify by selecting primary hgext
r8872
Brodie Rao
extensions: refactor disabled()
r10363 def _disabledhelp(path):
'''retrieve help synopsis of a disabled extension (without importing)'''
try:
file = open(path)
except IOError:
return
else:
doc = help.moduledoc(file)
file.close()
if doc: # extracting localized synopsis
return gettext(doc).splitlines()[0]
else:
return _('(no help text available)')
def disabled():
'''find disabled extensions from hgext
returns a dict of {name: desc}, and the max name length'''
paths = _disabledpaths()
if not paths:
return None, 0
exts = {}
maxlength = 0
for name, path in paths.iteritems():
doc = _disabledhelp(path)
if not doc:
Dirkjan Ochtman
extensions: simplify by selecting primary hgext
r8872 continue
Cédric Duval
extensions: move extensions listing functions from mercurial.help...
r8871
Brodie Rao
extensions: refactor disabled()
r10363 exts[name] = doc
Dirkjan Ochtman
extensions: simplify by selecting primary hgext
r8872 if len(name) > maxlength:
maxlength = len(name)
Cédric Duval
extensions: move extensions listing functions from mercurial.help...
r8871
return exts, maxlength
Brodie Rao
dispatch: provide help for disabled extensions and commands...
r10364 def disabledext(name):
'''find a specific disabled extension from hgext. returns desc'''
paths = _disabledpaths()
if name in paths:
return _disabledhelp(paths[name])
def disabledcmd(cmd, strict=False):
'''import disabled extensions until cmd is found.
returns (cmdname, extname, doc)'''
paths = _disabledpaths(strip_init=True)
if not paths:
raise error.UnknownCommand(cmd)
def findcmd(cmd, name, path):
try:
mod = loadpath(path, 'hgext.%s' % name)
except Exception:
return
try:
aliases, entry = cmdutil.findcmd(cmd,
getattr(mod, 'cmdtable', {}), strict)
except (error.AmbiguousCommand, error.UnknownCommand):
return
for c in aliases:
if c.startswith(cmd):
cmd = c
break
else:
cmd = aliases[0]
return (cmd, name, mod)
# first, search for an extension with the same name as the command
path = paths.pop(cmd, None)
if path:
ext = findcmd(cmd, cmd, path)
if ext:
return ext
# otherwise, interrogate each extension until there's a match
for name, path in paths.iteritems():
ext = findcmd(cmd, name, path)
if ext:
return ext
raise error.UnknownCommand(cmd)
Cédric Duval
extensions: move extensions listing functions from mercurial.help...
r8871 def enabled():
'''return a dict of {name: desc} of extensions, and the max name length'''
exts = {}
maxlength = 0
for ename, ext in extensions():
doc = (gettext(ext.__doc__) or _('(no help text available)'))
ename = ename.split('.')[-1]
maxlength = max(len(ename), maxlength)
Nicolas Dumazet
for calls expecting bool args, pass bool instead of int...
r9136 exts[ename] = doc.splitlines()[0].strip()
Cédric Duval
extensions: move extensions listing functions from mercurial.help...
r8871
return exts, maxlength