~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Martin Pool
  • Date: 2009-07-10 07:14:02 UTC
  • mto: (4525.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4526.
  • Revision ID: mbp@sourcefrog.net-20090710071402-dga5lhvdup5jeere
Rename remaining *_implementations tests

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
 
 
113
Control Formats
 
114
---------------
 
115
 
 
116
Because disk format detection for formats that bzr does not understand at
 
117
all can be useful, we allow a declarative description of the shape of a
 
118
control directory. Each description has a name for showing to users, and a
 
119
dictonary of relative paths, and the content needed at each path. Paths
 
120
that end in '/' are required to be directories and the value for that key
 
121
is ignored. Other paths are required to be regular files, and the value
 
122
for that key is either None, in which case the file is statted but the
 
123
content is ignored, or a literal string which is compared against for
 
124
the content of the file. Thus::
 
125
 
 
126
  # (look for a .hg directory)
 
127
  bzr_control_formats = {"Mercurial":{'.hg/': None}}
 
128
  
 
129
  # (look for a file called .svn/format with contents 4\n).
 
130
  bzr_control_formats = {"Subversion":{'.svn/format': '4\n'}}
 
131
 
 
132
 
 
133
Example
 
134
-------
 
135
 
 
136
An example setup.py follows::
 
137
  
 
138
  #!/usr/bin/env python2.4
 
139
  from distutils.core import setup
 
140
  
 
141
  bzr_plugin_name = 'demo'
 
142
  bzr_commands = [
 
143
      'new-command',
 
144
      ]
 
145
  
 
146
  bzr_branch_formats = {
 
147
      "Branch label on disk\n":"demo branch",
 
148
      }
 
149
 
 
150
  bzr_control_formats = {"Subversion":{'.svn/format': '4\n'}}
 
151
  
 
152
  bzr_plugin_version = (1, 3, 0, 'dev', 0)
 
153
  bzr_minimum_version = (1, 0, 0)
 
154
  
 
155
  if __name__ == 'main':
 
156
      setup(name="Demo",
 
157
            version="1.3.0dev0",
 
158
            description="Demo plugin for plugin metadata.",
 
159
            author="Canonical Ltd",
 
160
            author_email="bazaar@lists.canonical.com",
 
161
            license = "GNU GPL v2",
 
162
            url="https://launchpad.net/bzr-demo",
 
163
            packages=['bzrlib.plugins.demo',
 
164
                      'bzrlib.plugins.demo.tests',
 
165
                      ],
 
166
            package_dir={'bzrlib.plugins.demo': '.'})
 
167
 
 
168
 
 
169
Plugin metadata after installation
 
170
==================================
 
171
 
 
172
After a plugin has been installed, metadata can be more easily obtained by
 
173
looking inside the module object -- in other words, for variables defined
 
174
in the plugin's ``__init__.py``.
 
175
 
 
176
Help and documentation
 
177
----------------------
 
178
 
 
179
The module docstring is used as the plugin description shown by ``bzr
 
180
plugins``.  As with all Python docstrings, the first line should be a
 
181
short complete sentence summarizing the plugin.  The full docstring is
 
182
shown by ``bzr help PLUGIN_NAME``.
 
183
 
 
184
Remember that to be effective, the module docstring must be the first
 
185
statement in the file.  It may come after comments but it must be before
 
186
any import statements.
 
187
 
 
188
API version
 
189
-----------
 
190
 
 
191
Plugins can and should declare that they depend on a particular version of
 
192
bzrlib like so::
 
193
 
 
194
    from bzrlib.api import require_api
 
195
 
 
196
    require_api(bzrlib, (1, 11, 0))
 
197
 
 
198
Please see `API versioning <api-versioning.html>`_ for more details on the API
 
199
metadata protocol used by bzrlib.
 
200
 
 
201
Plugin version
 
202
--------------
 
203
 
 
204
The plugin should expose a version tuple to describe its own version.
 
205
Some plugins use a version number that corresponds to the version of bzr
 
206
they're released against, but you can use whatever you want.  For example::
 
207
 
 
208
    version_info = (1, 10, 0)
 
209
 
 
210
 
 
211
Detecting whether code's being loaded as a plugin
 
212
-------------------------------------------------
 
213
 
 
214
You may have a Python module that can be used as a bzr plugin and also in
 
215
other places.  To detect whether the module is being loaded by bzr, use
 
216
something like this::
 
217
 
 
218
    if __name__ == 'bzrlib.plugins.loggerhead':
 
219
        # register with bzrlib...
 
220
 
 
221
 
 
222
Plugin performance
 
223
==================
 
224
 
 
225
Plugins should avoid doing work or loading code from the plugin or
 
226
external libraries, if they're just installed but not actually active,
 
227
because this slows down every invocation of bzr.  The bzrlib APIs
 
228
generally allow the plugin to 'lazily' register methods to invoke if a
 
229
particular disk format or seen or a particular command is run.
 
230
 
 
231
 
 
232
Plugin registrations
 
233
====================
 
234
 
 
235
The plugin ``__init__.py`` runs when the plugin is loaded during bzr
 
236
startup.  Generally the plugin won't want to actually do anything at this
 
237
time other than register or override functions to be called later.
 
238
 
 
239
The plugin can import bzrlib and call any function.
 
240
Some interesting APIs are described in <http://bazaar-vcs.org/WritingPlugins>
 
241
 
 
242
 
 
243
Publishing your plugin
 
244
======================
 
245
 
 
246
When your plugin is basically working you might like to share it with
 
247
other people.  Here are some steps to consider:
 
248
 
 
249
 * make a project on Launchpad.net like
 
250
   <https://launchpad.net/bzr-fastimport>
 
251
   and publish the branches or tarballs there
 
252
 
 
253
 * include the plugin in <http://bazaar-vcs.org/BzrPlugins>
 
254
 
 
255
 * post about it to the ``bazaar-announce`` list at ``lists.canonical.com``
 
256
 
 
257
..
 
258
   vim: ft=rst tw=74 ai shiftwidth=4