##// END OF EJS Templates
extensions: add detailed loading information...
Martijn Pieters -
r38834:d5895867 default
parent child Browse files
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
179 mod = _importext(name, path, bind(_reportimporterror, ui))
180 with util.timedcm() as stats:
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)
194 for fn in _aftercallbacks.get(shortname, []):
198 log(' - invoking registered callbacks: %r\n', shortname)
195 fn(loaded=True)
199 with util.timedcm() as stats:
200 for fn in _aftercallbacks.get(shortname, []):
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,28 +232,41 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)
232 for (name, path) in result:
244 log('loading %sextensions\n', 'additional ' if newindex else '')
233 if path:
245 log('- processing %d entries\n', len(result))
234 if path[0:1] == '!':
246 with util.timedcm() as stats:
235 _disabledextensions[name] = path[1:]
247 for (name, path) in result:
236 continue
237 try:
238 load(ui, name, path)
239 except Exception as inst:
240 msg = stringutil.forcebytestr(inst)
241 if path:
248 if path:
242 ui.warn(_("*** failed to import extension %s from %s: %s\n")
249 if path[0:1] == '!':
243 % (name, path, msg))
250 if name not in _disabledextensions:
244 else:
251 log(' - skipping disabled extension: %r\n', name)
245 ui.warn(_("*** failed to import extension %s: %s\n")
252 _disabledextensions[name] = path[1:]
246 % (name, msg))
253 continue
247 if isinstance(inst, error.Hint) and inst.hint:
254 try:
248 ui.warn(_("*** (%s)\n") % inst.hint)
255 load(ui, name, path, log)
249 ui.traceback()
256 except Exception as inst:
257 msg = stringutil.forcebytestr(inst)
258 if path:
259 ui.warn(_("*** failed to import extension %s from %s: %s\n")
260 % (name, path, msg))
261 else:
262 ui.warn(_("*** failed to import extension %s: %s\n")
263 % (name, msg))
264 if isinstance(inst, error.Hint) and inst.hint:
265 ui.warn(_("*** (%s)\n") % inst.hint)
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:]:
265 if not _runuisetup(name, ui):
288 log(' - running uisetup for %r\n', name)
266 broken.add(name)
289 with util.timedcm() as stats:
290 if not _runuisetup(name, ui):
291 log(' - the %r extension uisetup failed\n', 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
271 if not _runextsetup(name, ui):
299 log(' - running extsetup for %r\n', name)
272 broken.add(name)
300 with util.timedcm() as stats:
301 if not _runextsetup(name, ui):
302 log(' - the %r extension extsetup failed\n', 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.
278 for shortname in _aftercallbacks:
311 log('- executing remaining aftercallbacks\n')
279 if shortname in _extensions:
312 with util.timedcm() as stats:
280 continue
313 for shortname in _aftercallbacks:
314 if shortname in _extensions:
315 continue
281
316
282 for fn in _aftercallbacks[shortname]:
317 for fn in _aftercallbacks[shortname]:
283 fn(loaded=False)
318 log(' - extension %r not loaded, notify callbacks\n',
319 shortname)
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 ]
317 _loadextra(ui, newindex, extraloaders)
356 with util.timedcm() as stats:
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 *badext2): trying badext2 (glob)
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