Bazaar

Bazaar

 




Wiki Tools

  • Login
  • Create Profile
  • FindPage
  • RecentChanges
  • Page History
  • Attachments

Creating a Plugin

Plugins allow extending the functionality or altering the behaviour of bzr without modifying the bzr source code. Writing a plugin is the preferred way to create a new command or alter the behaviour of existing commands.

Usually, plugins are installed for a specific user in the ~/.bazaar/plugins/. They may be simple Python modules (e.g. foo.py) or Python packages (directories containing an __init__.py file). Generally, we recommend that they be directories, since then you can version your plugin (using Bazaar, of course):

cd ~/.bazaar
mkdir plugins
bzr init foo
cd foo
touch __init__.py

Defining a New Command

Bzr commands are defined as subclasses of bzrlib.commands.Command, the command name is specified by the name of the subclass, and they must be registered into bzr with the bzrlib.commands.register_command function at module import time.

To define the bzr foo-bar command:

from bzrlib.commands import Command, register_command

class cmd_foo_bar(Command):
  # see bzrlib/builtins.py for information about what to put here
  pass

register_command(cmd_foo_bar)

If the class name starts with cmd, the prefix will get dropped and _ will be replaced by - characters.

Command Class Attributes

Base class for commands. Commands are the heart of the command-line bzr interface.

The command object mostly handles the mapping of command-line parameters into one or more bzrlib operations, and of the results into textual output.

Commands normally don't have any state. All their arguments are passed in to the run method. (Subclasses may take a different policy if the behaviour of the instance needs to depend on e.g. a shell plugin and not just its Python class.)

The docstring for an actual command should give a single-line summary, then a complete description of the command. A grammar description will be inserted.

aliases
Other accepted names for this command.
takes_args

List of argument forms, marked with whether they are optional, repeated, etc.

For example: ['to_location', 'from_branch?', 'file*'] means:

  • 'to_location' is required
  • 'from_branch' is optional
  • 'file' can be specified 0 or more times
takes_options
List of options that may be given for this command. These can be either strings, referring to globally-defined options, or option objects. Retrieve through options().
hidden
If true, this command isn't advertised. This is typically for commands intended for expert users.

Command.run Method

Actually run the command.

This is invoked with the options and arguments bound to keyword parameters.

Return 0 or None if the command was successful, or a non-zero shell error code if not. It's OK for this method to allow an exception to raise up.

register_command Function

Utility function to help register a command.

param cmd
Command subclass to register
param decorate
If true, allow overriding an existing command of the same name; the old command is returned by this function. Otherwise it is an error to try to override an existing command.

Testing plugins

When you run bzr selftest, Bazaar will scan all its plugins to see if they contain a function named test_suite(). For each plugin that does, it calls the function and adds any resulting tests to the master test suite.

Plugins and startup time

When bzr starts up, it imports every plugin, so plugins can degrade performance when they're not being used. However, sub-modules are not loaded, only the main name.

One way you can avoid this slowdown is by putting most of your code in sub-modules, so that the plugin, itself, is small. All you really need in the __init__.py is the plugin's Command classes, the commands to register them, and the optional test_suite().

Another way to reduce your plugin's overhead is to use the bzrlib lazy_import functionality. That looks something like this:

from bzrlib.lazy_import import lazy_import
lazy_import(globals(), """
from bzrlib import (
    branch as _mod_branch,
    option,
    workingtree,
    )
""")

Lazy importing only works for packages and modules, not classes or functions. It defers the import until you actually need it.

Giving Back

Please feel free to contribute your plugin to BzrTools, if you think it would be useful to other people.

Advanced Configuration

The directory where user plugins are looked for (~/.bazaar/plugins, by default) can be overridden by setting the BZR_PLUGIN_PATH environment variable.

Plugins can be installed system wide in bzrlib/plugins directory of the bzr installation.

Invoking plugin functions in callbacks

There are many hooks available from Branch as of bzr 0.15. Adding a new hook is done with:

import bzrlib.branch
bzrlib.branch.Branch.hooks.install_hook(HOOK_NAME, MY_FUNCTION)

Current Hooks

As of bzr 1.3.1, the following hooks are known on Branch:

set_rh
invoked whenever the revision history has been set with set_revision_history. The api signature is (branch, revision_history), and the branch will be write-locked.
post_push
invoked after a push operation completes. the api signature is (push_result) containing the members (source, local, master, old_revno, old_revid, new_revno, new_revid) where local is the local target branch or None, master is the target master branch, and the rest should be self explanatory. The source is read locked and the target branches write locked. Source will be the local low-latency branch.
post_pull
invoked after a pull operation completes. the api signature is (pull_result) containing the members (source, local, master, old_revno, old_revid, new_revno, new_revid) where local is the local branch or None, master is the target master branch, and the rest should be self explanatory. The source is read locked and the target branches write locked. The local branch is the low-latency branch.
pre_commit
invoked before a commit operation takes place. the api signature is (local, master, old_revno, old_revid, future_revno, future_revid, tree_delta, future_tree). old_revid is NULL_REVISION for the first commit to a branch tree_delta is a TreeDelta object describing changes from the basis revision, hooks MUST NOT modify this delta future_tree is an in-memory tree obtained from CommitBuilder.revision_tree() and hooks MUST NOT modify this tree
post_commit
invoked after a commit operation completes. the api signature is (local, master, old_revno, old_revid, new_revno, new_revid) old_revid is NULL_REVISION for the first commit to a branch.
post_uncommit
invoked after a uncommit operation completes. the api signature is (local, master, old_revno, old_revid, new_revno, new_revid) where local is the local branch or None, master is the target branch, and an empty branch recieves new_revno of 0, new_revid of None.

See bzrlib.branch.BranchHooks.__init__ for more complete information about what hooks are available.

Further Info

Integrating_with_Bazaar explains how to do such operations as add, commit, log and more.