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