[PATCH 1 of 2] extensions: permit extension interdependency through load-time hooking
Brodie Rao
dackze at gmail.com
Mon Jun 1 12:42:52 CDT 2009
# HG changeset patch
# User Brodie Rao <me+hg at dackz.net>
# Date 1243877702 14400
# Node ID f9a18bcef2996cf9775b3a27b65e4d674d728fd2
# Parent 68e0a55eee6e97df2bbb4548c6b6dbd2d2b7bb97
extensions: permit extension interdependency through load-time hooking
To let an extension safely use or modify another extension, a new API is
added: extensions.hook(shortname, func). If the extension identified by
shortname is already loaded, func is executed immediately; otherwise, func
is executed immediately after the extension is loaded, before its
uisetup() is called.
For example, the color extension wraps various mq commands. In the past it
has used two different methods of finding mq to wrap it:
1. from hgext import mq
This bypasses the extension machinery, and can potentially load a different
mq than what the user specified in hgrc.
2. extensions.find('mq')
This fails if mq is not yet loaded. Whether it's loaded yet depends on the
order of [extensions] in hgrc.
Using extensions.hook(), the hook function is only executed if the target
extension is loaded, and it doesn't cause the wrong mq to be loaded.
diff --git a/hgext/color.py b/hgext/color.py
--- a/hgext/color.py
+++ b/hgext/color.py
@@ -232,13 +232,11 @@ def uisetup(ui):
_setupcmd(ui, 'outgoing', commands.table, None, _diff_effects)
_setupcmd(ui, 'tip', commands.table, None, _diff_effects)
_setupcmd(ui, 'status', commands.table, colorstatus, _status_effects)
- try:
- mq = extensions.find('mq')
+
+ def setupmq(mq):
_setupcmd(ui, 'qdiff', mq.cmdtable, colordiff, _diff_effects)
_setupcmd(ui, 'qseries', mq.cmdtable, colorqseries, _patch_effects)
- except KeyError:
- # The mq extension is not enabled
- pass
+ extensions.hook('mq', setupmq)
def _setupcmd(ui, cmd, table, func, effectsmap):
'''patch in command to command table and load effect map'''
diff --git a/mercurial/extensions.py b/mercurial/extensions.py
--- a/mercurial/extensions.py
+++ b/mercurial/extensions.py
@@ -10,6 +10,7 @@ import util, cmdutil
from i18n import _
_extensions = {}
+_hooks = {}
_order = []
def extensions():
@@ -66,6 +67,18 @@ def load(ui, name, path):
_extensions[shortname] = mod
_order.append(shortname)
+ for func in _hooks.pop(shortname, []):
+ try:
+ func(mod)
+ except KeyboardInterrupt:
+ raise
+ except Exception, inst:
+ errname = func.__module__.rsplit('.', 1)[1]
+ ui.warn(_('*** extension %s failed to hook extension %s: %s\n')
+ % (errname, name, inst))
+ if ui.traceback():
+ raise
+
uisetup = getattr(mod, 'uisetup', None)
if uisetup:
uisetup(ui)
@@ -90,6 +103,14 @@ def loadall(ui):
if ui.traceback():
return 1
+def hook(shortname, func):
+ if shortname in _extensions:
+ func(_extensions[shortname])
+ elif shortname in _hooks:
+ _hooks[shortname].append(func)
+ else:
+ _hooks[shortname] = [func]
+
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
@@ -102,3 +102,30 @@ echo "hgext/mq=" >> $HGRCPATH
echo % show extensions
hg debugextensions
+echo 'mq = !' >> $HGRCPATH
+echo 'hgext.mq = !' >> $HGRCPATH
+echo 'hgext/mq = !' >> $HGRCPATH
+
+echo % hook extensions
+cat > debughookextension.py <<EOF
+'''hook another extension
+'''
+from mercurial import extensions
+
+def wrap(ext):
+ def wrapper(orig, ui, *args, **kw):
+ ui.write('wrapped\n')
+ extensions.wrapcommand(ext.cmdtable, 'debugextensions', wrapper)
+
+def uisetup(ui):
+ extensions.hook('debugissue811', wrap)
+EOF
+debughookpath=`pwd`/debughookextension.py
+echo "debugissue811 = $debugpath" >> $HGRCPATH
+echo "debughookextension = $debughookpath" >> $HGRCPATH
+hg debugextensions
+echo 'debugissue811 = !' >> $HGRCPATH
+echo 'debughookextension = !' >> $HGRCPATH
+echo "debughookextension = $debughookpath" >> $HGRCPATH
+echo "debugissue811 = $debugpath" >> $HGRCPATH
+hg debugextensions
diff --git a/tests/test-extension.out b/tests/test-extension.out
--- a/tests/test-extension.out
+++ b/tests/test-extension.out
@@ -54,3 +54,6 @@ global options:
% show extensions
debugissue811
mq
+% hook extensions
+wrapped
+wrapped
More information about the Mercurial-devel
mailing list