# HG changeset patch # User Martin Geisler # Date 2009-08-28 22:29:16 # Node ID 1c83938b6a8e083228d7dbfed681dd91d3952a5e # Parent 57157a224037523a6928e2c6456db8268518bf59 extensions: load and configure extensions in well-defined phases Extensions are now loaded with a call-graph like this: dispatch._dispatch extensions.loadall extensions.load # add foo module to extensions._extensions extensions.load # add bar module to extensions._extensions foo.uisetup(ui) bar.uisetup(ui) foo.extsetup() bar.extsetup() commands.table.update(foo.cmdtable) commands.table.update(bar.cmdtable) hg.repository foo.reposetup(ui, repo) bar.reposetup(ui, repo) The uisetup calls could easily be moved out to dispatch._dispatch, but have been kept in extensions.loadall since at least TortoiseHg calls extensions.loadall and expects it to call uisetup. The extensions.load function called uisetup. It now has an unused ui argument which has been kept for backwards compatibility. diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py --- a/mercurial/dispatch.py +++ b/mercurial/dispatch.py @@ -349,19 +349,20 @@ def _dispatch(ui, args): lui = ui.copy() lui.readconfig(os.path.join(path, ".hg", "hgrc")) + # Configure extensions in phases: uisetup, extsetup, cmdtable, and + # reposetup. Programs like TortoiseHg will call _dispatch several + # times so we keep track of configured extensions in _loaded. extensions.loadall(lui) - for name, module in extensions.extensions(): - if name in _loaded: - continue + exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded] - # setup extensions - # TODO this should be generalized to scheme, where extensions can - # redepend on other extensions. then we should toposort them, and - # do initialization in correct order + # (uisetup is handled in extensions.loadall) + + for name, module in exts: extsetup = getattr(module, 'extsetup', None) if extsetup: extsetup() + for name, module in exts: cmdtable = getattr(module, 'cmdtable', {}) overrides = [cmd for cmd in cmdtable if cmd in commands.table] if overrides: @@ -370,6 +371,8 @@ def _dispatch(ui, args): commands.table.update(cmdtable) _loaded.add(name) + # (reposetup is handled in hg.repository) + addaliases(lui, commands.table) # check for fallback encoding diff --git a/mercurial/extensions.py b/mercurial/extensions.py --- a/mercurial/extensions.py +++ b/mercurial/extensions.py @@ -40,6 +40,7 @@ def loadpath(path, module_name): return imp.load_source(module_name, path) def load(ui, name, path): + # unused ui argument kept for backwards compatibility if name.startswith('hgext.') or name.startswith('hgext/'): shortname = name[6:] else: @@ -66,12 +67,9 @@ def load(ui, name, path): _extensions[shortname] = mod _order.append(shortname) - uisetup = getattr(mod, 'uisetup', None) - if uisetup: - uisetup(ui) - def loadall(ui): result = ui.configitems("extensions") + newindex = len(_order) for (name, path) in result: if path: if path[0] == '!': @@ -90,6 +88,11 @@ def loadall(ui): if ui.traceback(): return 1 + for name in _order[newindex:]: + uisetup = getattr(_extensions[name], 'uisetup', None) + if uisetup: + uisetup(ui) + def wrapcommand(table, command, wrapper): aliases, entry = cmdutil.findcmd(command, table) for alias, e in table.iteritems(): diff --git a/tests/test-extension b/tests/test-extension --- a/tests/test-extension +++ b/tests/test-extension @@ -55,6 +55,29 @@ cd a hg foo echo 'barfoo = !' >> $HGRCPATH +# check that extensions are loaded in phases +cat > foo.py <> $HGRCPATH +echo 'bar = bar.py' >> $HGRCPATH + +# command with no output, we just want to see the extensions loaded +hg paths + +echo 'foo = !' >> $HGRCPATH +echo 'bar = !' >> $HGRCPATH + cd .. cat > empty.py <