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.
--- a/mercurial/dispatch.py Fri Aug 28 22:14:04 2009 +0200
+++ b/mercurial/dispatch.py Sat Aug 29 00:29:16 2009 +0200
@@ -349,19 +349,20 @@
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 @@
commands.table.update(cmdtable)
_loaded.add(name)
+ # (reposetup is handled in hg.repository)
+
addaliases(lui, commands.table)
# check for fallback encoding
--- a/mercurial/extensions.py Fri Aug 28 22:14:04 2009 +0200
+++ b/mercurial/extensions.py Sat Aug 29 00:29:16 2009 +0200
@@ -40,6 +40,7 @@
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 @@
_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 @@
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():
--- a/tests/test-extension Fri Aug 28 22:14:04 2009 +0200
+++ b/tests/test-extension Sat Aug 29 00:29:16 2009 +0200
@@ -55,6 +55,29 @@
hg foo
echo 'barfoo = !' >> $HGRCPATH
+# check that extensions are loaded in phases
+cat > foo.py <<EOF
+import os
+name = os.path.basename(__file__).rsplit('.', 1)[0]
+print "1) %s imported" % name
+def uisetup(ui):
+ print "2) %s uisetup" % name
+def extsetup():
+ print "3) %s extsetup" % name
+def reposetup(ui, repo):
+ print "4) %s reposetup" % name
+EOF
+
+cp foo.py bar.py
+echo 'foo = 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 <<EOF
'''empty cmdtable
--- a/tests/test-extension.out Fri Aug 28 22:14:04 2009 +0200
+++ b/tests/test-extension.out Sat Aug 29 00:29:16 2009 +0200
@@ -16,6 +16,14 @@
reposetup called for a
ui == repo.ui
Foo
+1) foo imported
+1) bar imported
+2) foo uisetup
+2) bar uisetup
+3) foo extsetup
+3) bar extsetup
+4) foo reposetup
+4) bar reposetup
empty extension - empty cmdtable
no commands defined