~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to doc/developers/plugin-api.txt

Merge the 0.17 fixes back into bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
==========
2
 
Plugin API
3
 
==========
4
 
 
5
 
 
6
 
 
7
 
:Date: 2009-01-23
8
 
 
9
 
.. contents::
10
 
 
11
 
Introduction
12
 
============
13
 
 
14
 
bzrlib has a very flexible internal structure allowing plugins for many
15
 
operations. Plugins can add commands, new storage formats, diff and merge
16
 
features and more. This document provides an overview of the API and
17
 
conventions for plugin authors.
18
 
 
19
 
If you're writing a plugin and have questions not addressed by this
20
 
document, please ask us.
21
 
 
22
 
See also
23
 
--------
24
 
 
25
 
 * `Bazaar Developer Documentation Catalog <index.html>`_.
26
 
 * <http://bazaar-vcs.org/WritingPlugins> wiki page with many more
27
 
   suggestions about particular APIs
28
 
 
29
 
 
30
 
Structure of a plugin
31
 
=====================
32
 
 
33
 
Plugins are Python modules under ``bzrlib.plugins``. They can be installed
34
 
either into the PYTHONPATH in that location, or in ~/.bazaar/plugins.
35
 
 
36
 
Plugins should have a setup.py.
37
 
 
38
 
As for other Python modules, the name of the directory must match the
39
 
expected name of the plugin.
40
 
 
41
 
 
42
 
Plugin metadata before installation
43
 
===================================
44
 
 
45
 
Plugins can export a summary of what they provide, and what versions of bzrlib
46
 
they are compatible with. This allows tools to be written to work with plugins,
47
 
such as to generate a directory of plugins, or install them via a
48
 
symlink/checkout to ~/.bazaar/plugins.
49
 
 
50
 
This interface allows bzr to interrogate a plugin without actually loading
51
 
it. This is useful because loading a plugin may have side effects such
52
 
as registering or overriding commands, or the plugin may raise an error,
53
 
if for example a prerequisite is not present.
54
 
 
55
 
 
56
 
Metadata protocol
57
 
-----------------
58
 
 
59
 
A plugin that supports the bzr plugin metadata protocol will do two
60
 
things. Firstly, the ``setup.py`` for the plugin will guard the call to
61
 
``setup()``::
62
 
 
63
 
  if __name__ == 'main':
64
 
      setup(...)
65
 
 
66
 
Secondly, the setup module will have one or more of the following variables
67
 
present at module scope. Any variables that are missing will be given the
68
 
defaults from the table. An example of every variable is provided after
69
 
the full list.
70
 
 
71
 
+------------------------+---------+----------------------------------------+
72
 
| Variable               | Default | Definition                             |
73
 
+========================+=========+========================================+
74
 
| bzr_plugin_name        | None    | The name the plugin package should be  |
75
 
|                        |         | given on disk. The plugin is then      |
76
 
|                        |         | available to python at                 |
77
 
|                        |         | bzrlib.plugins.NAME                    |
78
 
+------------------------+---------+----------------------------------------+
79
 
| bzr_commands           | []      | A list of the commands that the plugin |
80
 
|                        |         | provides. Commands that already exist  |
81
 
|                        |         | in bzr and are decorated by the plugin |
82
 
|                        |         | do not need to be listed (but it is not|
83
 
|                        |         | harmful if you do list them).          |
84
 
+------------------------+---------+----------------------------------------+
85
 
| bzr_plugin_version     | None    | A version_info 5-tuple with the plugins|
86
 
|                        |         | version.                               |
87
 
+------------------------+---------+----------------------------------------+
88
 
| bzr_minimum_version    | None    | A version_info 3-tuple for comparison  |
89
 
|                        |         | with the bzrlib minimum and current    |
90
 
|                        |         | version, for determining likely        |
91
 
|                        |         | compatibility.                         |
92
 
+------------------------+---------+----------------------------------------+
93
 
| bzr_maximum_version    | None    | A version_info 3-tuple like            |
94
 
|                        |         | bzr_minimum_version but checking the   |
95
 
|                        |         | upper limits supported.                |
96
 
+------------------------+---------+----------------------------------------+
97
 
| bzr_control_formats    | {}      | A dictionary of descriptions of version|
98
 
|                        |         | control directories. See               |
99
 
|                        |         | `Control Formats` below.               |
100
 
+------------------------+---------+----------------------------------------+
101
 
| bzr_checkout_formats   | {}      | A dictionary of tree_format_string ->  |
102
 
|                        |         | human description strings, for tree    |
103
 
|                        |         | formats that drop into the             |
104
 
|                        |         | ``.bzr/checkout`` metadir system.      |
105
 
+------------------------+---------+----------------------------------------+
106
 
| bzr_branch_formats     | {}      | As bzr_checkout_formats but for        |
107
 
|                        |         | branches.                              |
108
 
+------------------------+---------+----------------------------------------+
109
 
| bzr_repository_formats | {}      | As bzr_checkout_formats but for        |
110
 
|                        |         | repositories.                          |
111
 
+------------------------+---------+----------------------------------------+
112
 
| bzr_transports         | []      | URL prefixes for which this plugin     |
113
 
|                        |         | will register transports.              |
114
 
+------------------------+---------+----------------------------------------+
115
 
 
116
 
Control Formats
117
 
---------------
118
 
 
119
 
Because disk format detection for formats that bzr does not understand at
120
 
all can be useful, we allow a declarative description of the shape of a
121
 
control directory. Each description has a name for showing to users, and a
122
 
dictonary of relative paths, and the content needed at each path. Paths
123
 
that end in '/' are required to be directories and the value for that key
124
 
is ignored. Other paths are required to be regular files, and the value
125
 
for that key is either None, in which case the file is statted but the
126
 
content is ignored, or a literal string which is compared against for
127
 
the content of the file. Thus::
128
 
 
129
 
  # (look for a .hg directory)
130
 
  bzr_control_formats = {"Mercurial":{'.hg/': None}}
131
 
 
132
 
  # (look for a file called .svn/format with contents 4\n).
133
 
  bzr_control_formats = {"Subversion":{'.svn/format': '4\n'}}
134
 
 
135
 
 
136
 
Example
137
 
-------
138
 
 
139
 
An example setup.py follows::
140
 
 
141
 
  #!/usr/bin/env python2.4
142
 
  from distutils.core import setup
143
 
 
144
 
  bzr_plugin_name = 'demo'
145
 
  bzr_commands = [
146
 
      'new-command',
147
 
      ]
148
 
 
149
 
  bzr_branch_formats = {
150
 
      "Branch label on disk\n":"demo branch",
151
 
      }
152
 
 
153
 
  bzr_control_formats = {"Subversion":{'.svn/format': '4\n'}}
154
 
 
155
 
  bzr_transports = ["hg+ssh://"]
156
 
 
157
 
  bzr_plugin_version = (1, 3, 0, 'dev', 0)
158
 
  bzr_minimum_version = (1, 0, 0)
159
 
 
160
 
  if __name__ == 'main':
161
 
      setup(name="Demo",
162
 
            version="1.3.0dev0",
163
 
            description="Demo plugin for plugin metadata.",
164
 
            author="Canonical Ltd",
165
 
            author_email="bazaar@lists.canonical.com",
166
 
            license = "GNU GPL v2",
167
 
            url="https://launchpad.net/bzr-demo",
168
 
            packages=['bzrlib.plugins.demo',
169
 
                      'bzrlib.plugins.demo.tests',
170
 
                      ],
171
 
            package_dir={'bzrlib.plugins.demo': '.'})
172
 
 
173
 
 
174
 
Plugin metadata after installation
175
 
==================================
176
 
 
177
 
After a plugin has been installed, metadata can be more easily obtained by
178
 
looking inside the module object -- in other words, for variables defined
179
 
in the plugin's ``__init__.py``.
180
 
 
181
 
Help and documentation
182
 
----------------------
183
 
 
184
 
The module docstring is used as the plugin description shown by ``bzr
185
 
plugins``.  As with all Python docstrings, the first line should be a
186
 
short complete sentence summarizing the plugin.  The full docstring is
187
 
shown by ``bzr help PLUGIN_NAME``.
188
 
 
189
 
Remember that to be effective, the module docstring must be the first
190
 
statement in the file.  It may come after comments but it must be before
191
 
any import statements.
192
 
 
193
 
API version
194
 
-----------
195
 
 
196
 
Plugins can and should declare that they depend on a particular version of
197
 
bzrlib like so::
198
 
 
199
 
    from bzrlib.api import require_api
200
 
 
201
 
    require_api(bzrlib, (1, 11, 0))
202
 
 
203
 
Please see `API versioning <api-versioning.html>`_ for more details on the API
204
 
metadata protocol used by bzrlib.
205
 
 
206
 
Plugin version
207
 
--------------
208
 
 
209
 
The plugin should expose a version tuple to describe its own version.
210
 
Some plugins use a version number that corresponds to the version of bzr
211
 
they're released against, but you can use whatever you want.  For example::
212
 
 
213
 
    version_info = (1, 10, 0)
214
 
 
215
 
 
216
 
Detecting whether code's being loaded as a plugin
217
 
-------------------------------------------------
218
 
 
219
 
You may have a Python module that can be used as a bzr plugin and also in
220
 
other places.  To detect whether the module is being loaded by bzr, use
221
 
something like this::
222
 
 
223
 
    if __name__ == 'bzrlib.plugins.loggerhead':
224
 
        # register with bzrlib...
225
 
 
226
 
 
227
 
Plugin performance
228
 
==================
229
 
 
230
 
Plugins should avoid doing work or loading code from the plugin or
231
 
external libraries, if they're just installed but not actually active,
232
 
because this slows down every invocation of bzr.  The bzrlib APIs
233
 
generally allow the plugin to 'lazily' register methods to invoke if a
234
 
particular disk format or seen or a particular command is run.
235
 
 
236
 
 
237
 
Plugin registrations
238
 
====================
239
 
 
240
 
The plugin ``__init__.py`` runs when the plugin is loaded during bzr
241
 
startup.  Generally the plugin won't want to actually do anything at this
242
 
time other than register or override functions to be called later.
243
 
 
244
 
The plugin can import bzrlib and call any function.
245
 
Some interesting APIs are described in <http://bazaar-vcs.org/WritingPlugins>
246
 
 
247
 
 
248
 
Publishing your plugin
249
 
======================
250
 
 
251
 
When your plugin is basically working you might like to share it with
252
 
other people.  Here are some steps to consider:
253
 
 
254
 
 * make a project on Launchpad.net like
255
 
   <https://launchpad.net/bzr-fastimport>
256
 
   and publish the branches or tarballs there
257
 
 
258
 
 * include the plugin in <http://bazaar-vcs.org/BzrPlugins>
259
 
 
260
 
 * post about it to the ``bazaar-announce`` list at ``lists.canonical.com``
261
 
 
262
 
..
263
 
   vim: ft=rst tw=74 ai shiftwidth=4