Mercurial > public > mercurial-scm > hg
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 |