~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/hooks.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-03-10 06:07:38 UTC
  • mfrom: (4098.2.3 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20090310060738-6js2ofvx7q1gfg63
(robertc) Allow Hooks to be self documenting. (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
from bzrlib.lazy_import import lazy_import
20
20
from bzrlib.symbol_versioning import deprecated_method, one_five
21
21
lazy_import(globals(), """
 
22
import textwrap
 
23
 
22
24
from bzrlib import (
 
25
        _format_version_tuple,
23
26
        errors,
24
27
        )
25
28
""")
36
39
        dict.__init__(self)
37
40
        self._callable_names = {}
38
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
 
39
75
    def get_hook_name(self, a_callable):
40
76
        """Get the name for a_callable for UI display.
41
77
 
70
106
            running.
71
107
        """
72
108
        try:
73
 
            self[hook_name].append(a_callable)
 
109
            hook = self[hook_name]
74
110
        except KeyError:
75
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)
76
117
        if name is not None:
77
118
            self.name_hook(a_callable, name)
78
119
 
79
120
    def name_hook(self, a_callable, name):
80
121
        """Associate name with a_callable to show users what is running."""
81
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)