comparison mercurial/extensions.py @ 24065:d8837ad682dd

extensions: support callbacks after another extension loads An upcoming patch will introduce a dependency between the color and pager extensions. To prepare for this, we teach extensions how to register callbacks that can execute when another extension loads. This patch is based on code provided by Matt Mackall. But significant parts have changed (such as the ability to register multiple callbacks and the change in behavior to always call a callback). I believe that always firing the callback is a good practice. I think the common use for this feature will be for extensions to say "run this one-time setup code, after this other extension if possible." Always running the callback will facilitate this.
author Gregory Szorc <gregory.szorc@gmail.com>
date Fri, 06 Feb 2015 12:07:32 -0800
parents af73c05e735a
children 042d95beeee8
comparison
equal deleted inserted replaced
24064:c260887cdbcd 24065:d8837ad682dd
8 import imp, os 8 import imp, os
9 import util, cmdutil, error 9 import util, cmdutil, error
10 from i18n import _, gettext 10 from i18n import _, gettext
11 11
12 _extensions = {} 12 _extensions = {}
13 _aftercallbacks = {}
13 _order = [] 14 _order = []
14 _ignore = ['hbisect', 'bookmarks', 'parentrevspec', 'interhg', 'inotify'] 15 _ignore = ['hbisect', 'bookmarks', 'parentrevspec', 'interhg', 'inotify']
15 16
16 def extensions(ui=None): 17 def extensions(ui=None):
17 if ui: 18 if ui:
85 ui.debug('could not import hgext.%s (%s): trying %s\n' 86 ui.debug('could not import hgext.%s (%s): trying %s\n'
86 % (name, err, name)) 87 % (name, err, name))
87 mod = importh(name) 88 mod = importh(name)
88 _extensions[shortname] = mod 89 _extensions[shortname] = mod
89 _order.append(shortname) 90 _order.append(shortname)
91 for fn in _aftercallbacks.get(shortname, []):
92 fn(loaded=True)
90 return mod 93 return mod
91 94
92 def loadall(ui): 95 def loadall(ui):
93 result = ui.configitems("extensions") 96 result = ui.configitems("extensions")
94 newindex = len(_order) 97 newindex = len(_order)
120 extsetup(ui) 123 extsetup(ui)
121 except TypeError: 124 except TypeError:
122 if extsetup.func_code.co_argcount != 0: 125 if extsetup.func_code.co_argcount != 0:
123 raise 126 raise
124 extsetup() # old extsetup with no ui argument 127 extsetup() # old extsetup with no ui argument
128
129 # Call aftercallbacks that were never met.
130 for shortname in _aftercallbacks:
131 if shortname in _extensions:
132 continue
133
134 for fn in _aftercallbacks[shortname]:
135 fn(loaded=False)
136
137 def afterloaded(extension, callback):
138 '''Run the specified function after a named extension is loaded.
139
140 If the named extension is already loaded, the callback will be called
141 immediately.
142
143 If the named extension never loads, the callback will be called after
144 all extensions have been loaded.
145
146 The callback receives the named argument ``loaded``, which is a boolean
147 indicating whether the dependent extension actually loaded.
148 '''
149
150 if extension in _extensions:
151 callback(loaded=False)
152 else:
153 _aftercallbacks.setdefault(extension, []).append(callback)
125 154
126 def wrapcommand(table, command, wrapper): 155 def wrapcommand(table, command, wrapper):
127 '''Wrap the command named `command' in table 156 '''Wrap the command named `command' in table
128 157
129 Replace command in the command table with wrapper. The wrapped command will 158 Replace command in the command table with wrapper. The wrapped command will