Show More
@@ -124,7 +124,7 b' def _reportimporterror(ui, err, failed, ' | |||||
124 | # note: this ui.debug happens before --debug is processed, |
|
124 | # note: this ui.debug happens before --debug is processed, | |
125 | # Use --config ui.debug=1 to see them. |
|
125 | # Use --config ui.debug=1 to see them. | |
126 | if ui.configbool('devel', 'debug.extensions'): |
|
126 | if ui.configbool('devel', 'debug.extensions'): | |
127 | ui.debug('could not import %s (%s): trying %s\n' |
|
127 | ui.debug('debug.extensions: - could not import %s (%s): trying %s\n' | |
128 | % (failed, stringutil.forcebytestr(err), next)) |
|
128 | % (failed, stringutil.forcebytestr(err), next)) | |
129 | if ui.debugflag: |
|
129 | if ui.debugflag: | |
130 | ui.traceback() |
|
130 | ui.traceback() | |
@@ -166,7 +166,7 b' def _validatetables(ui, mod):' | |||||
166 | _rejectunicode(t, o._table) |
|
166 | _rejectunicode(t, o._table) | |
167 | _validatecmdtable(ui, getattr(mod, 'cmdtable', {})) |
|
167 | _validatecmdtable(ui, getattr(mod, 'cmdtable', {})) | |
168 |
|
168 | |||
169 | def load(ui, name, path): |
|
169 | def load(ui, name, path, log=lambda *a: None): | |
170 | if name.startswith('hgext.') or name.startswith('hgext/'): |
|
170 | if name.startswith('hgext.') or name.startswith('hgext/'): | |
171 | shortname = name[6:] |
|
171 | shortname = name[6:] | |
172 | else: |
|
172 | else: | |
@@ -175,8 +175,11 b' def load(ui, name, path):' | |||||
175 | return None |
|
175 | return None | |
176 | if shortname in _extensions: |
|
176 | if shortname in _extensions: | |
177 | return _extensions[shortname] |
|
177 | return _extensions[shortname] | |
|
178 | log(' - loading extension: %r\n', shortname) | |||
178 | _extensions[shortname] = None |
|
179 | _extensions[shortname] = None | |
|
180 | with util.timedcm() as stats: | |||
179 | mod = _importext(name, path, bind(_reportimporterror, ui)) |
|
181 | mod = _importext(name, path, bind(_reportimporterror, ui)) | |
|
182 | log(' > %r extension loaded in %s\n', shortname, stats) | |||
180 |
|
183 | |||
181 | # Before we do anything with the extension, check against minimum stated |
|
184 | # Before we do anything with the extension, check against minimum stated | |
182 | # compatibility. This gives extension authors a mechanism to have their |
|
185 | # compatibility. This gives extension authors a mechanism to have their | |
@@ -187,12 +190,16 b' def load(ui, name, path):' | |||||
187 | ui.warn(_('(third party extension %s requires version %s or newer ' |
|
190 | ui.warn(_('(third party extension %s requires version %s or newer ' | |
188 | 'of Mercurial; disabling)\n') % (shortname, minver)) |
|
191 | 'of Mercurial; disabling)\n') % (shortname, minver)) | |
189 | return |
|
192 | return | |
|
193 | log(' - validating extension tables: %r\n', shortname) | |||
190 | _validatetables(ui, mod) |
|
194 | _validatetables(ui, mod) | |
191 |
|
195 | |||
192 | _extensions[shortname] = mod |
|
196 | _extensions[shortname] = mod | |
193 | _order.append(shortname) |
|
197 | _order.append(shortname) | |
|
198 | log(' - invoking registered callbacks: %r\n', shortname) | |||
|
199 | with util.timedcm() as stats: | |||
194 | for fn in _aftercallbacks.get(shortname, []): |
|
200 | for fn in _aftercallbacks.get(shortname, []): | |
195 | fn(loaded=True) |
|
201 | fn(loaded=True) | |
|
202 | log(' > callbacks completed in %s\n', stats) | |||
196 | return mod |
|
203 | return mod | |
197 |
|
204 | |||
198 | def _runuisetup(name, ui): |
|
205 | def _runuisetup(name, ui): | |
@@ -225,17 +232,27 b' def _runextsetup(name, ui):' | |||||
225 | return True |
|
232 | return True | |
226 |
|
233 | |||
227 | def loadall(ui, whitelist=None): |
|
234 | def loadall(ui, whitelist=None): | |
|
235 | if ui.configbool('devel', 'debug.extensions'): | |||
|
236 | log = lambda msg, *values: ui.debug('debug.extensions: ', | |||
|
237 | msg % values, label='debug.extensions') | |||
|
238 | else: | |||
|
239 | log = lambda *a, **kw: None | |||
228 | result = ui.configitems("extensions") |
|
240 | result = ui.configitems("extensions") | |
229 | if whitelist is not None: |
|
241 | if whitelist is not None: | |
230 | result = [(k, v) for (k, v) in result if k in whitelist] |
|
242 | result = [(k, v) for (k, v) in result if k in whitelist] | |
231 | newindex = len(_order) |
|
243 | newindex = len(_order) | |
|
244 | log('loading %sextensions\n', 'additional ' if newindex else '') | |||
|
245 | log('- processing %d entries\n', len(result)) | |||
|
246 | with util.timedcm() as stats: | |||
232 | for (name, path) in result: |
|
247 | for (name, path) in result: | |
233 | if path: |
|
248 | if path: | |
234 | if path[0:1] == '!': |
|
249 | if path[0:1] == '!': | |
|
250 | if name not in _disabledextensions: | |||
|
251 | log(' - skipping disabled extension: %r\n', name) | |||
235 | _disabledextensions[name] = path[1:] |
|
252 | _disabledextensions[name] = path[1:] | |
236 | continue |
|
253 | continue | |
237 | try: |
|
254 | try: | |
238 | load(ui, name, path) |
|
255 | load(ui, name, path, log) | |
239 | except Exception as inst: |
|
256 | except Exception as inst: | |
240 | msg = stringutil.forcebytestr(inst) |
|
257 | msg = stringutil.forcebytestr(inst) | |
241 | if path: |
|
258 | if path: | |
@@ -247,6 +264,9 b' def loadall(ui, whitelist=None):' | |||||
247 | if isinstance(inst, error.Hint) and inst.hint: |
|
264 | if isinstance(inst, error.Hint) and inst.hint: | |
248 | ui.warn(_("*** (%s)\n") % inst.hint) |
|
265 | ui.warn(_("*** (%s)\n") % inst.hint) | |
249 | ui.traceback() |
|
266 | ui.traceback() | |
|
267 | ||||
|
268 | log('> loaded %d extensions, total time %s\n', | |||
|
269 | len(_order) - newindex, stats) | |||
250 | # list of (objname, loadermod, loadername) tuple: |
|
270 | # list of (objname, loadermod, loadername) tuple: | |
251 | # - objname is the name of an object in extension module, |
|
271 | # - objname is the name of an object in extension module, | |
252 | # from which extra information is loaded |
|
272 | # from which extra information is loaded | |
@@ -258,29 +278,47 b' def loadall(ui, whitelist=None):' | |||||
258 | earlyextraloaders = [ |
|
278 | earlyextraloaders = [ | |
259 | ('configtable', configitems, 'loadconfigtable'), |
|
279 | ('configtable', configitems, 'loadconfigtable'), | |
260 | ] |
|
280 | ] | |
|
281 | ||||
|
282 | log('- loading configtable attributes\n') | |||
261 | _loadextra(ui, newindex, earlyextraloaders) |
|
283 | _loadextra(ui, newindex, earlyextraloaders) | |
262 |
|
284 | |||
263 | broken = set() |
|
285 | broken = set() | |
|
286 | log('- executing uisetup hooks\n') | |||
264 | for name in _order[newindex:]: |
|
287 | for name in _order[newindex:]: | |
|
288 | log(' - running uisetup for %r\n', name) | |||
|
289 | with util.timedcm() as stats: | |||
265 | if not _runuisetup(name, ui): |
|
290 | if not _runuisetup(name, ui): | |
|
291 | log(' - the %r extension uisetup failed\n', name) | |||
266 | broken.add(name) |
|
292 | broken.add(name) | |
|
293 | log(' > uisetup for %r took %s\n', name, stats) | |||
267 |
|
294 | |||
|
295 | log('- executing extsetup hooks\n') | |||
268 | for name in _order[newindex:]: |
|
296 | for name in _order[newindex:]: | |
269 | if name in broken: |
|
297 | if name in broken: | |
270 | continue |
|
298 | continue | |
|
299 | log(' - running extsetup for %r\n', name) | |||
|
300 | with util.timedcm() as stats: | |||
271 | if not _runextsetup(name, ui): |
|
301 | if not _runextsetup(name, ui): | |
|
302 | log(' - the %r extension extsetup failed\n', name) | |||
272 | broken.add(name) |
|
303 | broken.add(name) | |
|
304 | log(' > extsetup for %r took %s\n', name, stats) | |||
273 |
|
305 | |||
274 | for name in broken: |
|
306 | for name in broken: | |
|
307 | log(' - disabling broken %r extension\n', name) | |||
275 | _extensions[name] = None |
|
308 | _extensions[name] = None | |
276 |
|
309 | |||
277 | # Call aftercallbacks that were never met. |
|
310 | # Call aftercallbacks that were never met. | |
|
311 | log('- executing remaining aftercallbacks\n') | |||
|
312 | with util.timedcm() as stats: | |||
278 | for shortname in _aftercallbacks: |
|
313 | for shortname in _aftercallbacks: | |
279 | if shortname in _extensions: |
|
314 | if shortname in _extensions: | |
280 | continue |
|
315 | continue | |
281 |
|
316 | |||
282 | for fn in _aftercallbacks[shortname]: |
|
317 | for fn in _aftercallbacks[shortname]: | |
|
318 | log(' - extension %r not loaded, notify callbacks\n', | |||
|
319 | shortname) | |||
283 | fn(loaded=False) |
|
320 | fn(loaded=False) | |
|
321 | log('> remaining aftercallbacks completed in %s\n', stats) | |||
284 |
|
322 | |||
285 | # loadall() is called multiple times and lingering _aftercallbacks |
|
323 | # loadall() is called multiple times and lingering _aftercallbacks | |
286 | # entries could result in double execution. See issue4646. |
|
324 | # entries could result in double execution. See issue4646. | |
@@ -304,6 +342,7 b' def loadall(ui, whitelist=None):' | |||||
304 | # - loadermod is the module where loader is placed |
|
342 | # - loadermod is the module where loader is placed | |
305 | # - loadername is the name of the function, |
|
343 | # - loadername is the name of the function, | |
306 | # which takes (ui, extensionname, extraobj) arguments |
|
344 | # which takes (ui, extensionname, extraobj) arguments | |
|
345 | log('- loading extension registration objects\n') | |||
307 | extraloaders = [ |
|
346 | extraloaders = [ | |
308 | ('cmdtable', commands, 'loadcmdtable'), |
|
347 | ('cmdtable', commands, 'loadcmdtable'), | |
309 | ('colortable', color, 'loadcolortable'), |
|
348 | ('colortable', color, 'loadcolortable'), | |
@@ -314,7 +353,10 b' def loadall(ui, whitelist=None):' | |||||
314 | ('templatefunc', templatefuncs, 'loadfunction'), |
|
353 | ('templatefunc', templatefuncs, 'loadfunction'), | |
315 | ('templatekeyword', templatekw, 'loadkeyword'), |
|
354 | ('templatekeyword', templatekw, 'loadkeyword'), | |
316 | ] |
|
355 | ] | |
|
356 | with util.timedcm() as stats: | |||
317 | _loadextra(ui, newindex, extraloaders) |
|
357 | _loadextra(ui, newindex, extraloaders) | |
|
358 | log('> extension registration object loading took %s\n', stats) | |||
|
359 | log('extension loading complete\n') | |||
318 |
|
360 | |||
319 | def _loadextra(ui, newindex, extraloaders): |
|
361 | def _loadextra(ui, newindex, extraloaders): | |
320 | for name in _order[newindex:]: |
|
362 | for name in _order[newindex:]: |
@@ -9,6 +9,7 b'' | |||||
9 | from __future__ import absolute_import |
|
9 | from __future__ import absolute_import | |
10 |
|
10 | |||
11 | import errno |
|
11 | import errno | |
|
12 | import functools | |||
12 | import hashlib |
|
13 | import hashlib | |
13 | import os |
|
14 | import os | |
14 | import shutil |
|
15 | import shutil | |
@@ -162,9 +163,16 b' def _peerorrepo(ui, path, create=False, ' | |||||
162 | """return a repository object for the specified path""" |
|
163 | """return a repository object for the specified path""" | |
163 | obj = _peerlookup(path).instance(ui, path, create, intents=intents) |
|
164 | obj = _peerlookup(path).instance(ui, path, create, intents=intents) | |
164 | ui = getattr(obj, "ui", ui) |
|
165 | ui = getattr(obj, "ui", ui) | |
|
166 | if ui.configbool('devel', 'debug.extensions'): | |||
|
167 | log = functools.partial( | |||
|
168 | ui.debug, 'debug.extensions: ', label='debug.extensions') | |||
|
169 | else: | |||
|
170 | log = lambda *a, **kw: None | |||
165 | for f in presetupfuncs or []: |
|
171 | for f in presetupfuncs or []: | |
166 | f(ui, obj) |
|
172 | f(ui, obj) | |
|
173 | log('- executing reposetup hooks\n') | |||
167 | for name, module in extensions.extensions(ui): |
|
174 | for name, module in extensions.extensions(ui): | |
|
175 | log(' - running reposetup for %s\n' % (name,)) | |||
168 | hook = getattr(module, 'reposetup', None) |
|
176 | hook = getattr(module, 'reposetup', None) | |
169 | if hook: |
|
177 | if hook: | |
170 | hook(ui, obj) |
|
178 | hook(ui, obj) |
@@ -77,18 +77,49 b' show traceback for ImportError of hgext.' | |||||
77 | $ (hg help help --traceback --debug --config devel.debug.extensions=yes 2>&1) \ |
|
77 | $ (hg help help --traceback --debug --config devel.debug.extensions=yes 2>&1) \ | |
78 | > | grep -v '^ ' \ |
|
78 | > | grep -v '^ ' \ | |
79 | > | egrep 'extension..[^p]|^Exception|Traceback|ImportError|not import' |
|
79 | > | egrep 'extension..[^p]|^Exception|Traceback|ImportError|not import' | |
|
80 | debug.extensions: loading extensions | |||
|
81 | debug.extensions: - processing 5 entries | |||
|
82 | debug.extensions: - loading extension: 'gpg' | |||
|
83 | debug.extensions: > 'gpg' extension loaded in * (glob) | |||
|
84 | debug.extensions: - validating extension tables: 'gpg' | |||
|
85 | debug.extensions: - invoking registered callbacks: 'gpg' | |||
|
86 | debug.extensions: > callbacks completed in * (glob) | |||
|
87 | debug.extensions: - loading extension: 'badext' | |||
80 | *** failed to import extension badext from $TESTTMP/badext.py: bit bucket overflow |
|
88 | *** failed to import extension badext from $TESTTMP/badext.py: bit bucket overflow | |
81 | Traceback (most recent call last): |
|
89 | Traceback (most recent call last): | |
82 | Exception: bit bucket overflow |
|
90 | Exception: bit bucket overflow | |
83 | could not import hgext.badext2 (No module named *badext2): trying hgext3rd.badext2 (glob) |
|
91 | debug.extensions: - loading extension: 'baddocext' | |
|
92 | debug.extensions: > 'baddocext' extension loaded in * (glob) | |||
|
93 | debug.extensions: - validating extension tables: 'baddocext' | |||
|
94 | debug.extensions: - invoking registered callbacks: 'baddocext' | |||
|
95 | debug.extensions: > callbacks completed in * (glob) | |||
|
96 | debug.extensions: - loading extension: 'badext2' | |||
|
97 | debug.extensions: - could not import hgext.badext2 (No module named badext2): trying hgext3rd.badext2 | |||
84 | Traceback (most recent call last): |
|
98 | Traceback (most recent call last): | |
85 | ImportError: No module named *badext2 (glob) |
|
99 | ImportError: No module named *badext2 (glob) | |
86 |
could not import hgext3rd.badext2 (No module named |
|
100 | debug.extensions: - could not import hgext3rd.badext2 (No module named badext2): trying badext2 | |
87 | Traceback (most recent call last): |
|
101 | Traceback (most recent call last): | |
88 | ImportError: No module named *badext2 (glob) |
|
102 | ImportError: No module named *badext2 (glob) | |
89 | *** failed to import extension badext2: No module named badext2 |
|
103 | *** failed to import extension badext2: No module named badext2 | |
90 | Traceback (most recent call last): |
|
104 | Traceback (most recent call last): | |
91 | ImportError: No module named badext2 |
|
105 | ImportError: No module named badext2 | |
|
106 | debug.extensions: > loaded 2 extensions, total time * (glob) | |||
|
107 | debug.extensions: - loading configtable attributes | |||
|
108 | debug.extensions: - executing uisetup hooks | |||
|
109 | debug.extensions: - running uisetup for 'gpg' | |||
|
110 | debug.extensions: > uisetup for 'gpg' took * (glob) | |||
|
111 | debug.extensions: - running uisetup for 'baddocext' | |||
|
112 | debug.extensions: > uisetup for 'baddocext' took * (glob) | |||
|
113 | debug.extensions: - executing extsetup hooks | |||
|
114 | debug.extensions: - running extsetup for 'gpg' | |||
|
115 | debug.extensions: > extsetup for 'gpg' took * (glob) | |||
|
116 | debug.extensions: - running extsetup for 'baddocext' | |||
|
117 | debug.extensions: > extsetup for 'baddocext' took * (glob) | |||
|
118 | debug.extensions: - executing remaining aftercallbacks | |||
|
119 | debug.extensions: > remaining aftercallbacks completed in * (glob) | |||
|
120 | debug.extensions: - loading extension registration objects | |||
|
121 | debug.extensions: > extension registration object loading took * (glob) | |||
|
122 | debug.extensions: extension loading complete | |||
92 |
|
123 | |||
93 | confirm that there's no crash when an extension's documentation is bad |
|
124 | confirm that there's no crash when an extension's documentation is bad | |
94 |
|
125 |
General Comments 0
You need to be logged in to leave comments.
Login now