/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/hooks.py

  • Committer: Vincent Ladeuil
  • Date: 2011-07-06 09:22:00 UTC
  • mfrom: (6008 +trunk)
  • mto: (6012.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6013.
  • Revision ID: v.ladeuil+lp@free.fr-20110706092200-7iai2mwzc0sqdsvf
MergingĀ inĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2010 Canonical Ltd
 
1
# Copyright (C) 2007-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
16
16
 
17
17
 
18
18
"""Support for plugin hooking logic."""
 
19
 
19
20
from bzrlib import (
20
 
    pyutils,
21
21
    registry,
22
22
    symbol_versioning,
23
23
    )
26
26
import textwrap
27
27
 
28
28
from bzrlib import (
29
 
        _format_version_tuple,
30
 
        errors,
31
 
        )
32
 
from bzrlib.help_topics import help_as_plain_text
 
29
    _format_version_tuple,
 
30
    errors,
 
31
    pyutils,
 
32
    )
33
33
""")
34
34
 
35
35
 
72
72
    ('bzrlib.branch', 'Branch.hooks', 'BranchHooks'),
73
73
    ('bzrlib.bzrdir', 'BzrDir.hooks', 'BzrDirHooks'),
74
74
    ('bzrlib.commands', 'Command.hooks', 'CommandHooks'),
 
75
    ('bzrlib.config', 'ConfigHooks', '_ConfigHooks'),
75
76
    ('bzrlib.info', 'hooks', 'InfoHooks'),
76
77
    ('bzrlib.lock', 'Lock.hooks', 'LockHooks'),
77
78
    ('bzrlib.merge', 'Merger.hooks', 'MergeHooks'),
115
116
    FOO hook is triggered.
116
117
    """
117
118
 
118
 
    def __init__(self):
 
119
    def __init__(self, module=None, member_name=None):
 
120
        """Create a new hooks dictionary.
 
121
 
 
122
        :param module: The module from which this hooks dictionary should be loaded
 
123
            (used for lazy hooks)
 
124
        :param member_name: Name under which this hooks dictionary should be loaded.
 
125
            (used for lazy hooks)
 
126
        """
119
127
        dict.__init__(self)
120
128
        self._callable_names = {}
121
 
 
 
129
        self._module = module
 
130
        self._member_name = member_name
 
131
 
 
132
    def add_hook(self, name, doc, introduced, deprecated=None):
 
133
        """Add a hook point to this dictionary.
 
134
 
 
135
        :param name: The name of the hook, for clients to use when registering.
 
136
        :param doc: The docs for the hook.
 
137
        :param introduced: When the hook was introduced (e.g. (0, 15)).
 
138
        :param deprecated: When the hook was deprecated, None for
 
139
            not-deprecated.
 
140
        """
 
141
        if name in self:
 
142
            raise errors.DuplicateKey(name)
 
143
        if self._module:
 
144
            callbacks = _lazy_hooks.setdefault(
 
145
                (self._module, self._member_name, name), [])
 
146
        else:
 
147
            callbacks = None
 
148
        hookpoint = HookPoint(name=name, doc=doc, introduced=introduced,
 
149
                              deprecated=deprecated, callbacks=callbacks)
 
150
        self[name] = hookpoint
 
151
 
 
152
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
122
153
    def create_hook(self, hook):
123
154
        """Create a hook which can have callbacks registered for it.
124
155
 
166
197
        """
167
198
        return self._callable_names.get(a_callable, "No hook name")
168
199
 
 
200
    def install_named_hook_lazy(self, hook_name, callable_module,
 
201
        callable_member, name):
 
202
        """Install a_callable in to the hook hook_name lazily, and label it.
 
203
 
 
204
        :param hook_name: A hook name. See the __init__ method for the complete
 
205
            list of hooks.
 
206
        :param callable_module: Name of the module in which the callable is
 
207
            present.
 
208
        :param callable_member: Member name of the callable.
 
209
        :param name: A name to associate the callable with, to show users what
 
210
            is running.
 
211
        """
 
212
        try:
 
213
            hook = self[hook_name]
 
214
        except KeyError:
 
215
            raise errors.UnknownHook(self.__class__.__name__, hook_name)
 
216
        try:
 
217
            hook_lazy = getattr(hook, "hook_lazy")
 
218
        except AttributeError:
 
219
            raise errors.UnsupportedOperation(self.install_named_hook_lazy,
 
220
                self)
 
221
        else:
 
222
            hook_lazy(callable_module, callable_member, name)
 
223
 
169
224
    def install_named_hook(self, hook_name, a_callable, name):
170
225
        """Install a_callable in to the hook hook_name, and label it name.
171
226
 
172
 
        :param hook_name: A hook name. See the __init__ method of BranchHooks
173
 
            for the complete list of hooks.
 
227
        :param hook_name: A hook name. See the __init__ method for the complete
 
228
            list of hooks.
174
229
        :param a_callable: The callable to be invoked when the hook triggers.
175
230
            The exact signature will depend on the hook - see the __init__
176
 
            method of BranchHooks for details on each hook.
 
231
            method for details on each hook.
177
232
        :param name: A name to associate a_callable with, to show users what is
178
233
            running.
179
234
        """
189
244
        if name is not None:
190
245
            self.name_hook(a_callable, name)
191
246
 
 
247
    def uninstall_named_hook(self, hook_name, label):
 
248
        """Uninstall named hooks.
 
249
 
 
250
        :param hook_name: Hook point name
 
251
        :param label: Label of the callable to uninstall
 
252
        """
 
253
        try:
 
254
            hook = self[hook_name]
 
255
        except KeyError:
 
256
            raise errors.UnknownHook(self.__class__.__name__, hook_name)
 
257
        try:
 
258
            uninstall = getattr(hook, "uninstall")
 
259
        except AttributeError:
 
260
            raise errors.UnsupportedOperation(self.uninstall_named_hook, self)
 
261
        else:
 
262
            uninstall(label)
 
263
 
192
264
    def name_hook(self, a_callable, name):
193
265
        """Associate name with a_callable to show users what is running."""
194
266
        self._callable_names[a_callable] = name
207
279
        should describe the recommended replacement hook to register for.
208
280
    """
209
281
 
210
 
    def __init__(self, name, doc, introduced, deprecated):
 
282
    def __init__(self, name, doc, introduced, deprecated=None, callbacks=None):
211
283
        """Create a HookPoint.
212
284
 
213
285
        :param name: The name of the hook, for clients to use when registering.
220
292
        self.__doc__ = doc
221
293
        self.introduced = introduced
222
294
        self.deprecated = deprecated
223
 
        self._callbacks = []
224
 
        self._callback_names = {}
 
295
        if callbacks is None:
 
296
            self._callbacks = []
 
297
        else:
 
298
            self._callbacks = callbacks
225
299
 
226
300
    def docs(self):
227
301
        """Generate the documentation for this HookPoint.
247
321
        return '\n'.join(strings)
248
322
 
249
323
    def __eq__(self, other):
250
 
        return (type(other) == type(self) and 
251
 
            other.__dict__ == self.__dict__)
 
324
        return (type(other) == type(self) and other.__dict__ == self.__dict__)
 
325
 
 
326
    def hook_lazy(self, callback_module, callback_member, callback_label):
 
327
        """Lazily register a callback to be called when this HookPoint fires.
 
328
 
 
329
        :param callback_module: Module of the callable to use when this
 
330
            HookPoint fires.
 
331
        :param callback_member: Member name of the callback.
 
332
        :param callback_label: A label to show in the UI while this callback is
 
333
            processing.
 
334
        """
 
335
        obj_getter = registry._LazyObjectGetter(callback_module,
 
336
            callback_member)
 
337
        self._callbacks.append((obj_getter, callback_label))
252
338
 
253
339
    def hook(self, callback, callback_label):
254
340
        """Register a callback to be called when this HookPoint fires.
257
343
        :param callback_label: A label to show in the UI while this callback is
258
344
            processing.
259
345
        """
260
 
        self._callbacks.append(callback)
261
 
        if callback_label is not None:
262
 
            self._callback_names[callback] = callback_label
 
346
        obj_getter = registry._ObjectGetter(callback)
 
347
        self._callbacks.append((obj_getter, callback_label))
 
348
 
 
349
    def uninstall(self, label):
 
350
        """Uninstall the callback with the specified label.
 
351
 
 
352
        :param label: Label of the entry to uninstall
 
353
        """
 
354
        entries_to_remove = []
 
355
        for entry in self._callbacks:
 
356
            (entry_callback, entry_label) = entry
 
357
            if entry_label == label:
 
358
                entries_to_remove.append(entry)
 
359
        if entries_to_remove == []:
 
360
            raise KeyError("No entry with label %r" % label)
 
361
        for entry in entries_to_remove:
 
362
            self._callbacks.remove(entry)
263
363
 
264
364
    def __iter__(self):
265
 
        return iter(self._callbacks)
 
365
        return (callback.get_obj() for callback, name in self._callbacks)
266
366
 
267
367
    def __len__(self):
268
368
        return len(self._callbacks)
272
372
        strings.append("<%s(" % type(self).__name__)
273
373
        strings.append(self.name)
274
374
        strings.append("), callbacks=[")
275
 
        for callback in self._callbacks:
276
 
            strings.append(repr(callback))
 
375
        callbacks = self._callbacks
 
376
        for (callback, callback_name) in callbacks:
 
377
            strings.append(repr(callback.get_obj()))
277
378
            strings.append("(")
278
 
            strings.append(self._callback_names[callback])
 
379
            strings.append(callback_name)
279
380
            strings.append("),")
280
 
        if len(self._callbacks) == 1:
 
381
        if len(callbacks) == 1:
281
382
            strings[-1] = ")"
282
383
        strings.append("]>")
283
384
        return ''.join(strings)
322
423
        hooks = known_hooks_key_to_object(hook_key)
323
424
        segments.append(hooks.docs())
324
425
    return '\n'.join(segments)
 
426
 
 
427
 
 
428
# Lazily registered hooks. Maps (module, name, hook_name) tuples
 
429
# to lists of tuples with objectgetters and names
 
430
_lazy_hooks = {}
 
431
 
 
432
 
 
433
def install_lazy_named_hook(hookpoints_module, hookpoints_name, hook_name,
 
434
    a_callable, name):
 
435
    """Install a callable in to a hook lazily, and label it name.
 
436
 
 
437
    :param hookpoints_module: Module name of the hook points.
 
438
    :param hookpoints_name: Name of the hook points.
 
439
    :param hook_name: A hook name.
 
440
    :param callable: a callable to call for the hook.
 
441
    :param name: A name to associate a_callable with, to show users what is
 
442
        running.
 
443
    """
 
444
    key = (hookpoints_module, hookpoints_name, hook_name)
 
445
    obj_getter = registry._ObjectGetter(a_callable)
 
446
    _lazy_hooks.setdefault(key, []).append((obj_getter, name))