/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: Aaron Bentley
  • Date: 2009-03-11 07:29:12 UTC
  • mto: This revision was merged to the branch mainline in revision 4130.
  • Revision ID: aaron@aaronbentley.com-20090311072912-p7kui5njo3av6e49
Add body=None to support old mail clients better.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007, 2008 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
 
 
18
"""Support for plugin hooking logic."""
 
19
from bzrlib.lazy_import import lazy_import
 
20
from bzrlib.symbol_versioning import deprecated_method, one_five
 
21
lazy_import(globals(), """
 
22
import textwrap
 
23
 
 
24
from bzrlib import (
 
25
        _format_version_tuple,
 
26
        errors,
 
27
        )
 
28
""")
 
29
 
 
30
 
 
31
class Hooks(dict):
 
32
    """A dictionary mapping hook name to a list of callables.
 
33
 
 
34
    e.g. ['FOO'] Is the list of items to be called when the
 
35
    FOO hook is triggered.
 
36
    """
 
37
 
 
38
    def __init__(self):
 
39
        dict.__init__(self)
 
40
        self._callable_names = {}
 
41
 
 
42
    def create_hook(self, hook):
 
43
        """Create a hook which can have callbacks registered for it.
 
44
 
 
45
        :param hook: The hook to create. An object meeting the protocol of
 
46
            bzrlib.hooks.HookPoint. It's name is used as the key for future
 
47
            lookups.
 
48
        """
 
49
        if hook.name in self:
 
50
            raise errors.DuplicateKey(hook.name)
 
51
        self[hook.name] = hook
 
52
 
 
53
    def docs(self):
 
54
        """Generate the documentation for this Hooks instance.
 
55
 
 
56
        This introspects all the individual hooks and returns their docs as well.
 
57
        """
 
58
        hook_names = sorted(self.keys())
 
59
        hook_docs = []
 
60
        for hook_name in hook_names:
 
61
            hook = self[hook_name]
 
62
            try:
 
63
                hook_docs.append(hook.docs())
 
64
            except AttributeError:
 
65
                # legacy hook
 
66
                strings = []
 
67
                strings.append(hook_name)
 
68
                strings.append("-" * len(hook_name))
 
69
                strings.append("")
 
70
                strings.append("An old-style hook. For documentation see the __init__ "
 
71
                    "method of '%s'\n" % (self.__class__.__name__,))
 
72
                hook_docs.extend(strings)
 
73
        return "\n".join(hook_docs)
 
74
 
 
75
    def get_hook_name(self, a_callable):
 
76
        """Get the name for a_callable for UI display.
 
77
 
 
78
        If no name has been registered, the string 'No hook name' is returned.
 
79
        We use a fixed string rather than repr or the callables module because
 
80
        the code names are rarely meaningful for end users and this is not
 
81
        intended for debugging.
 
82
        """
 
83
        return self._callable_names.get(a_callable, "No hook name")
 
84
 
 
85
    @deprecated_method(one_five)
 
86
    def install_hook(self, hook_name, a_callable):
 
87
        """Install a_callable in to the hook hook_name.
 
88
 
 
89
        :param hook_name: A hook name. See the __init__ method of BranchHooks
 
90
            for the complete list of hooks.
 
91
        :param a_callable: The callable to be invoked when the hook triggers.
 
92
            The exact signature will depend on the hook - see the __init__
 
93
            method of BranchHooks for details on each hook.
 
94
        """
 
95
        self.install_named_hook(hook_name, a_callable, None)
 
96
 
 
97
    def install_named_hook(self, hook_name, a_callable, name):
 
98
        """Install a_callable in to the hook hook_name, and label it name.
 
99
 
 
100
        :param hook_name: A hook name. See the __init__ method of BranchHooks
 
101
            for the complete list of hooks.
 
102
        :param a_callable: The callable to be invoked when the hook triggers.
 
103
            The exact signature will depend on the hook - see the __init__
 
104
            method of BranchHooks for details on each hook.
 
105
        :param name: A name to associate a_callable with, to show users what is
 
106
            running.
 
107
        """
 
108
        try:
 
109
            hook = self[hook_name]
 
110
        except KeyError:
 
111
            raise errors.UnknownHook(self.__class__.__name__, hook_name)
 
112
        try:
 
113
            # list hooks, old-style, not yet deprecated but less useful.
 
114
            hook.append(a_callable)
 
115
        except AttributeError:
 
116
            hook.hook(a_callable, name)
 
117
        if name is not None:
 
118
            self.name_hook(a_callable, name)
 
119
 
 
120
    def name_hook(self, a_callable, name):
 
121
        """Associate name with a_callable to show users what is running."""
 
122
        self._callable_names[a_callable] = name
 
123
 
 
124
 
 
125
class HookPoint(object):
 
126
    """A single hook that clients can register to be called back when it fires.
 
127
 
 
128
    :ivar name: The name of the hook.
 
129
    :ivar introduced: A version tuple specifying what version the hook was
 
130
        introduced in. None indicates an unknown version.
 
131
    :ivar deprecated: A version tuple specifying what version the hook was
 
132
        deprecated or superceded in. None indicates that the hook is not
 
133
        superceded or deprecated. If the hook is superceded then the doc
 
134
        should describe the recommended replacement hook to register for.
 
135
    :ivar doc: The docs for using the hook.
 
136
    """
 
137
 
 
138
    def __init__(self, name, doc, introduced, deprecated):
 
139
        """Create a HookPoint.
 
140
 
 
141
        :param name: The name of the hook, for clients to use when registering.
 
142
        :param doc: The docs for the hook.
 
143
        :param introduced: When the hook was introduced (e.g. (0, 15)).
 
144
        :param deprecated: When the hook was deprecated, None for
 
145
            not-deprecated.
 
146
        """
 
147
        self.name = name
 
148
        self.__doc__ = doc
 
149
        self.introduced = introduced
 
150
        self.deprecated = deprecated
 
151
        self._callbacks = []
 
152
        self._callback_names = {}
 
153
 
 
154
    def docs(self):
 
155
        """Generate the documentation for this HookPoint.
 
156
 
 
157
        :return: A string terminated in \n.
 
158
        """
 
159
        strings = []
 
160
        strings.append(self.name)
 
161
        strings.append('-'*len(self.name))
 
162
        strings.append('')
 
163
        if self.introduced:
 
164
            introduced_string = _format_version_tuple(self.introduced)
 
165
        else:
 
166
            introduced_string = 'unknown'
 
167
        strings.append('Introduced in: %s' % introduced_string)
 
168
        if self.deprecated:
 
169
            deprecated_string = _format_version_tuple(self.deprecated)
 
170
        else:
 
171
            deprecated_string = 'Not deprecated'
 
172
        strings.append('Deprecated in: %s' % deprecated_string)
 
173
        strings.append('')
 
174
        strings.extend(textwrap.wrap(self.__doc__))
 
175
        strings.append('')
 
176
        return '\n'.join(strings)
 
177
 
 
178
    def hook(self, callback, callback_label):
 
179
        """Register a callback to be called when this HookPoint fires.
 
180
 
 
181
        :param callback: The callable to use when this HookPoint fires.
 
182
        :param callback_label: A label to show in the UI while this callback is
 
183
            processing.
 
184
        """
 
185
        self._callbacks.append(callback)
 
186
        self._callback_names[callback] = callback_label
 
187
 
 
188
    def __iter__(self):
 
189
        return iter(self._callbacks)
 
190
 
 
191
    def __repr__(self):
 
192
        strings = []
 
193
        strings.append("<%s(" % type(self).__name__)
 
194
        strings.append(self.name)
 
195
        strings.append("), callbacks=[")
 
196
        for callback in self._callbacks:
 
197
            strings.append(repr(callback))
 
198
            strings.append("(")
 
199
            strings.append(self._callback_names[callback])
 
200
            strings.append("),")
 
201
        if len(self._callbacks) == 1:
 
202
            strings[-1] = ")"
 
203
        strings.append("]>")
 
204
        return ''.join(strings)