##// END OF EJS Templates
extensions: obsolete and remove parentrevspec extension...
Kevin Gessner -
r14079:08fde203 default
parent child Browse files
Show More
@@ -1,309 +1,309 b''
1 1 # extensions.py - extension handling for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 import imp, os
9 9 import util, cmdutil, help, error
10 10 from i18n import _, gettext
11 11
12 12 _extensions = {}
13 13 _order = []
14 _ignore = ['hbisect', 'bookmarks']
14 _ignore = ['hbisect', 'bookmarks', 'parentrevspec']
15 15
16 16 def extensions():
17 17 for name in _order:
18 18 module = _extensions[name]
19 19 if module:
20 20 yield name, module
21 21
22 22 def find(name):
23 23 '''return module with given extension name'''
24 24 try:
25 25 return _extensions[name]
26 26 except KeyError:
27 27 for k, v in _extensions.iteritems():
28 28 if k.endswith('.' + name) or k.endswith('/' + name):
29 29 return v
30 30 raise KeyError(name)
31 31
32 32 def loadpath(path, module_name):
33 33 module_name = module_name.replace('.', '_')
34 34 path = util.expandpath(path)
35 35 if os.path.isdir(path):
36 36 # module/__init__.py style
37 37 d, f = os.path.split(path.rstrip('/'))
38 38 fd, fpath, desc = imp.find_module(f, [d])
39 39 return imp.load_module(module_name, fd, fpath, desc)
40 40 else:
41 41 return imp.load_source(module_name, path)
42 42
43 43 def load(ui, name, path):
44 44 # unused ui argument kept for backwards compatibility
45 45 if name.startswith('hgext.') or name.startswith('hgext/'):
46 46 shortname = name[6:]
47 47 else:
48 48 shortname = name
49 49 if shortname in _ignore:
50 50 return None
51 51 if shortname in _extensions:
52 52 return _extensions[shortname]
53 53 _extensions[shortname] = None
54 54 if path:
55 55 # the module will be loaded in sys.modules
56 56 # choose an unique name so that it doesn't
57 57 # conflicts with other modules
58 58 mod = loadpath(path, 'hgext.%s' % name)
59 59 else:
60 60 def importh(name):
61 61 mod = __import__(name)
62 62 components = name.split('.')
63 63 for comp in components[1:]:
64 64 mod = getattr(mod, comp)
65 65 return mod
66 66 try:
67 67 mod = importh("hgext.%s" % name)
68 68 except ImportError:
69 69 mod = importh(name)
70 70 _extensions[shortname] = mod
71 71 _order.append(shortname)
72 72 return mod
73 73
74 74 def loadall(ui):
75 75 result = ui.configitems("extensions")
76 76 newindex = len(_order)
77 77 for (name, path) in result:
78 78 if path:
79 79 if path[0] == '!':
80 80 continue
81 81 try:
82 82 load(ui, name, path)
83 83 except KeyboardInterrupt:
84 84 raise
85 85 except Exception, inst:
86 86 if path:
87 87 ui.warn(_("*** failed to import extension %s from %s: %s\n")
88 88 % (name, path, inst))
89 89 else:
90 90 ui.warn(_("*** failed to import extension %s: %s\n")
91 91 % (name, inst))
92 92 if ui.traceback():
93 93 return 1
94 94
95 95 for name in _order[newindex:]:
96 96 uisetup = getattr(_extensions[name], 'uisetup', None)
97 97 if uisetup:
98 98 uisetup(ui)
99 99
100 100 for name in _order[newindex:]:
101 101 extsetup = getattr(_extensions[name], 'extsetup', None)
102 102 if extsetup:
103 103 try:
104 104 extsetup(ui)
105 105 except TypeError:
106 106 if extsetup.func_code.co_argcount != 0:
107 107 raise
108 108 extsetup() # old extsetup with no ui argument
109 109
110 110 def wrapcommand(table, command, wrapper):
111 111 '''Wrap the command named `command' in table
112 112
113 113 Replace command in the command table with wrapper. The wrapped command will
114 114 be inserted into the command table specified by the table argument.
115 115
116 116 The wrapper will be called like
117 117
118 118 wrapper(orig, *args, **kwargs)
119 119
120 120 where orig is the original (wrapped) function, and *args, **kwargs
121 121 are the arguments passed to it.
122 122 '''
123 123 assert hasattr(wrapper, '__call__')
124 124 aliases, entry = cmdutil.findcmd(command, table)
125 125 for alias, e in table.iteritems():
126 126 if e is entry:
127 127 key = alias
128 128 break
129 129
130 130 origfn = entry[0]
131 131 def wrap(*args, **kwargs):
132 132 return util.checksignature(wrapper)(
133 133 util.checksignature(origfn), *args, **kwargs)
134 134
135 135 wrap.__doc__ = getattr(origfn, '__doc__')
136 136 wrap.__module__ = getattr(origfn, '__module__')
137 137
138 138 newentry = list(entry)
139 139 newentry[0] = wrap
140 140 table[key] = tuple(newentry)
141 141 return entry
142 142
143 143 def wrapfunction(container, funcname, wrapper):
144 144 '''Wrap the function named funcname in container
145 145
146 146 Replace the funcname member in the given container with the specified
147 147 wrapper. The container is typically a module, class, or instance.
148 148
149 149 The wrapper will be called like
150 150
151 151 wrapper(orig, *args, **kwargs)
152 152
153 153 where orig is the original (wrapped) function, and *args, **kwargs
154 154 are the arguments passed to it.
155 155
156 156 Wrapping methods of the repository object is not recommended since
157 157 it conflicts with extensions that extend the repository by
158 158 subclassing. All extensions that need to extend methods of
159 159 localrepository should use this subclassing trick: namely,
160 160 reposetup() should look like
161 161
162 162 def reposetup(ui, repo):
163 163 class myrepo(repo.__class__):
164 164 def whatever(self, *args, **kwargs):
165 165 [...extension stuff...]
166 166 super(myrepo, self).whatever(*args, **kwargs)
167 167 [...extension stuff...]
168 168
169 169 repo.__class__ = myrepo
170 170
171 171 In general, combining wrapfunction() with subclassing does not
172 172 work. Since you cannot control what other extensions are loaded by
173 173 your end users, you should play nicely with others by using the
174 174 subclass trick.
175 175 '''
176 176 assert hasattr(wrapper, '__call__')
177 177 def wrap(*args, **kwargs):
178 178 return wrapper(origfn, *args, **kwargs)
179 179
180 180 origfn = getattr(container, funcname)
181 181 assert hasattr(origfn, '__call__')
182 182 setattr(container, funcname, wrap)
183 183 return origfn
184 184
185 185 def _disabledpaths(strip_init=False):
186 186 '''find paths of disabled extensions. returns a dict of {name: path}
187 187 removes /__init__.py from packages if strip_init is True'''
188 188 import hgext
189 189 extpath = os.path.dirname(os.path.abspath(hgext.__file__))
190 190 try: # might not be a filesystem path
191 191 files = os.listdir(extpath)
192 192 except OSError:
193 193 return {}
194 194
195 195 exts = {}
196 196 for e in files:
197 197 if e.endswith('.py'):
198 198 name = e.rsplit('.', 1)[0]
199 199 path = os.path.join(extpath, e)
200 200 else:
201 201 name = e
202 202 path = os.path.join(extpath, e, '__init__.py')
203 203 if not os.path.exists(path):
204 204 continue
205 205 if strip_init:
206 206 path = os.path.dirname(path)
207 207 if name in exts or name in _order or name == '__init__':
208 208 continue
209 209 exts[name] = path
210 210 return exts
211 211
212 212 def _disabledhelp(path):
213 213 '''retrieve help synopsis of a disabled extension (without importing)'''
214 214 try:
215 215 file = open(path)
216 216 except IOError:
217 217 return
218 218 else:
219 219 doc = help.moduledoc(file)
220 220 file.close()
221 221
222 222 if doc: # extracting localized synopsis
223 223 return gettext(doc).splitlines()[0]
224 224 else:
225 225 return _('(no help text available)')
226 226
227 227 def disabled():
228 228 '''find disabled extensions from hgext
229 229 returns a dict of {name: desc}, and the max name length'''
230 230
231 231 paths = _disabledpaths()
232 232 if not paths:
233 233 return None, 0
234 234
235 235 exts = {}
236 236 maxlength = 0
237 237 for name, path in paths.iteritems():
238 238 doc = _disabledhelp(path)
239 239 if not doc:
240 240 continue
241 241
242 242 exts[name] = doc
243 243 if len(name) > maxlength:
244 244 maxlength = len(name)
245 245
246 246 return exts, maxlength
247 247
248 248 def disabledext(name):
249 249 '''find a specific disabled extension from hgext. returns desc'''
250 250 paths = _disabledpaths()
251 251 if name in paths:
252 252 return _disabledhelp(paths[name])
253 253
254 254 def disabledcmd(ui, cmd, strict=False):
255 255 '''import disabled extensions until cmd is found.
256 256 returns (cmdname, extname, doc)'''
257 257
258 258 paths = _disabledpaths(strip_init=True)
259 259 if not paths:
260 260 raise error.UnknownCommand(cmd)
261 261
262 262 def findcmd(cmd, name, path):
263 263 try:
264 264 mod = loadpath(path, 'hgext.%s' % name)
265 265 except Exception:
266 266 return
267 267 try:
268 268 aliases, entry = cmdutil.findcmd(cmd,
269 269 getattr(mod, 'cmdtable', {}), strict)
270 270 except (error.AmbiguousCommand, error.UnknownCommand):
271 271 return
272 272 except Exception:
273 273 ui.warn(_('warning: error finding commands in %s\n') % path)
274 274 ui.traceback()
275 275 return
276 276 for c in aliases:
277 277 if c.startswith(cmd):
278 278 cmd = c
279 279 break
280 280 else:
281 281 cmd = aliases[0]
282 282 return (cmd, name, mod)
283 283
284 284 # first, search for an extension with the same name as the command
285 285 path = paths.pop(cmd, None)
286 286 if path:
287 287 ext = findcmd(cmd, cmd, path)
288 288 if ext:
289 289 return ext
290 290
291 291 # otherwise, interrogate each extension until there's a match
292 292 for name, path in paths.iteritems():
293 293 ext = findcmd(cmd, name, path)
294 294 if ext:
295 295 return ext
296 296
297 297 raise error.UnknownCommand(cmd)
298 298
299 299 def enabled():
300 300 '''return a dict of {name: desc} of extensions, and the max name length'''
301 301 exts = {}
302 302 maxlength = 0
303 303 for ename, ext in extensions():
304 304 doc = (gettext(ext.__doc__) or _('(no help text available)'))
305 305 ename = ename.split('.')[-1]
306 306 maxlength = max(len(ename), maxlength)
307 307 exts[ename] = doc.splitlines()[0].strip()
308 308
309 309 return exts, maxlength
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now