135
|
1 # extensions.py - extension handling for mercurial
|
|
2 #
|
|
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
|
|
4 #
|
|
5 # This software may be used and distributed according to the terms of the
|
|
6 # GNU General Public License version 2, incorporated herein by reference.
|
|
7
|
|
8 import imp, os
|
|
9 import util, cmdutil, help
|
|
10 from i18n import _, gettext
|
|
11
|
|
12 _extensions = {}
|
|
13 _order = []
|
|
14
|
|
15 def extensions():
|
|
16 for name in _order:
|
|
17 module = _extensions[name]
|
|
18 if module:
|
|
19 yield name, module
|
|
20
|
|
21 def find(name):
|
|
22 '''return module with given extension name'''
|
|
23 try:
|
|
24 return _extensions[name]
|
|
25 except KeyError:
|
|
26 for k, v in _extensions.iteritems():
|
|
27 if k.endswith('.' + name) or k.endswith('/' + name):
|
|
28 return v
|
|
29 raise KeyError(name)
|
|
30
|
|
31 def loadpath(path, module_name):
|
|
32 module_name = module_name.replace('.', '_')
|
|
33 path = os.path.expanduser(path)
|
|
34 if os.path.isdir(path):
|
|
35 # module/__init__.py style
|
|
36 d, f = os.path.split(path.rstrip('/'))
|
|
37 fd, fpath, desc = imp.find_module(f, [d])
|
|
38 return imp.load_module(module_name, fd, fpath, desc)
|
|
39 else:
|
|
40 return imp.load_source(module_name, path)
|
|
41
|
|
42 def load(ui, name, path):
|
|
43 if name.startswith('hgext.') or name.startswith('hgext/'):
|
|
44 shortname = name[6:]
|
|
45 else:
|
|
46 shortname = name
|
|
47 if shortname in _extensions:
|
|
48 return
|
|
49 _extensions[shortname] = None
|
|
50 if path:
|
|
51 # the module will be loaded in sys.modules
|
|
52 # choose an unique name so that it doesn't
|
|
53 # conflicts with other modules
|
|
54 mod = loadpath(path, 'hgext.%s' % name)
|
|
55 else:
|
|
56 def importh(name):
|
|
57 mod = __import__(name)
|
|
58 components = name.split('.')
|
|
59 for comp in components[1:]:
|
|
60 mod = getattr(mod, comp)
|
|
61 return mod
|
|
62 try:
|
|
63 mod = importh("hgext.%s" % name)
|
|
64 except ImportError:
|
|
65 mod = importh(name)
|
|
66 _extensions[shortname] = mod
|
|
67 _order.append(shortname)
|
|
68
|
|
69 uisetup = getattr(mod, 'uisetup', None)
|
|
70 if uisetup:
|
|
71 uisetup(ui)
|
|
72
|
|
73 def loadall(ui):
|
|
74 result = ui.configitems("extensions")
|
|
75 for (name, path) in result:
|
|
76 if path:
|
|
77 if path[0] == '!':
|
|
78 continue
|
|
79 try:
|
|
80 load(ui, name, path)
|
|
81 except KeyboardInterrupt:
|
|
82 raise
|
|
83 except Exception, inst:
|
|
84 if path:
|
|
85 ui.warn(_("*** failed to import extension %s from %s: %s\n")
|
|
86 % (name, path, inst))
|
|
87 else:
|
|
88 ui.warn(_("*** failed to import extension %s: %s\n")
|
|
89 % (name, inst))
|
|
90 if ui.traceback():
|
|
91 return 1
|
|
92
|
|
93 def wrapcommand(table, command, wrapper):
|
|
94 aliases, entry = cmdutil.findcmd(command, table)
|
|
95 for alias, e in table.iteritems():
|
|
96 if e is entry:
|
|
97 key = alias
|
|
98 break
|
|
99
|
|
100 origfn = entry[0]
|
|
101 def wrap(*args, **kwargs):
|
|
102 return util.checksignature(wrapper)(
|
|
103 util.checksignature(origfn), *args, **kwargs)
|
|
104
|
|
105 wrap.__doc__ = getattr(origfn, '__doc__')
|
|
106 wrap.__module__ = getattr(origfn, '__module__')
|
|
107
|
|
108 newentry = list(entry)
|
|
109 newentry[0] = wrap
|
|
110 table[key] = tuple(newentry)
|
|
111 return entry
|
|
112
|
|
113 def wrapfunction(container, funcname, wrapper):
|
|
114 def wrap(*args, **kwargs):
|
|
115 return wrapper(origfn, *args, **kwargs)
|
|
116
|
|
117 origfn = getattr(container, funcname)
|
|
118 setattr(container, funcname, wrap)
|
|
119 return origfn
|
|
120
|
|
121 def disabled():
|
|
122 '''find disabled extensions from hgext
|
|
123 returns a dict of {name: desc}, and the max name length'''
|
|
124
|
|
125 import hgext
|
|
126 extpath = os.path.dirname(os.path.abspath(hgext.__file__))
|
|
127
|
|
128 try: # might not be a filesystem path
|
|
129 files = os.listdir(extpath)
|
|
130 except OSError:
|
|
131 return None, 0
|
|
132
|
|
133 exts = {}
|
|
134 maxlength = 0
|
|
135 for e in files:
|
|
136
|
|
137 if e.endswith('.py'):
|
|
138 name = e.rsplit('.', 1)[0]
|
|
139 path = os.path.join(extpath, e)
|
|
140 else:
|
|
141 name = e
|
|
142 path = os.path.join(extpath, e, '__init__.py')
|
|
143 if not os.path.exists(path):
|
|
144 continue
|
|
145
|
|
146 if name in exts or name in _order or name == '__init__':
|
|
147 continue
|
|
148
|
|
149 try:
|
|
150 file = open(path)
|
|
151 except IOError:
|
|
152 continue
|
|
153 else:
|
|
154 doc = help.moduledoc(file)
|
|
155 file.close()
|
|
156
|
|
157 if doc: # extracting localized synopsis
|
|
158 exts[name] = gettext(doc).splitlines()[0]
|
|
159 else:
|
|
160 exts[name] = _('(no help text available)')
|
|
161
|
|
162 if len(name) > maxlength:
|
|
163 maxlength = len(name)
|
|
164
|
|
165 return exts, maxlength
|
|
166
|
|
167 def enabled():
|
|
168 '''return a dict of {name: desc} of extensions, and the max name length'''
|
|
169
|
|
170 if not enabled:
|
|
171 return {}, 0
|
|
172
|
|
173 exts = {}
|
|
174 maxlength = 0
|
|
175 exthelps = []
|
|
176 for ename, ext in extensions():
|
|
177 doc = (gettext(ext.__doc__) or _('(no help text available)'))
|
|
178 ename = ename.split('.')[-1]
|
|
179 maxlength = max(len(ename), maxlength)
|
|
180 exts[ename] = doc.splitlines(0)[0].strip()
|
|
181
|
|
182 return exts, maxlength
|