Online Book Reader

Home Category

Mercurial_ The Definitive Guide - Bryan O'Sullivan [74]

By Root 952 0
can write a hook either as a normal program—typically a shell script—or as a Python function that is executed within the Mercurial process.

Writing a hook as an external program has the advantage that it requires no knowledge of Mercurial’s internals. You can call normal Mercurial commands to get any added information you need. The trade-off is that external hooks are slower than in-process hooks.

An in-process Python hook has complete access to the Mercurial API, and does not “shell out” to another process, so it is inherently faster than an external hook. It is also easier to obtain much of the information that a hook requires by using the Mercurial API than by running Mercurial commands.

If you are comfortable with Python or require high performance, writing your hooks in Python may be a good choice. However, when you have a straightforward hook to write and you don’t need to care about performance (probably the majority of hooks), a shell script is perfectly fine.

Hook Parameters

Mercurial calls each hook with a set of well-defined parameters. In Python, a parameter is passed as a keyword argument to your hook function. For an external program, a parameter is passed as an environment variable.

Whether your hook is written in Python or as a shell script, the hook-specific parameter names and values will be the same. A boolean parameter will be represented as a boolean value in Python, but as the number 1 (for “true”) or 0 (for “false”) as an environment variable for an external hook. If a hook parameter is named foo, the keyword argument for a Python hook will also be named foo, while the environment variable for an external hook will be named HG_FOO.

Hook Return Values and Activity Control

A hook that executes successfully must exit with a status of zero if external, or return boolean “false” if in-process. Failure is indicated with a non-zero exit status from an external hook, or an in-process hook returning boolean “true.” If an in-process hook raises an exception, the hook is considered to have failed.

For a hook that controls whether an activity can proceed, zero/false means “allow,” while non-zero/true/exception means “deny.”

Writing an External Hook

When you define an external hook in your ~/.hgrc and the hook is run, its value is passed to your shell, which interprets it. This means that you can use normal shell constructs in the body of the hook.

An executable hook is always run with its current directory set to a repository’s root directory.

Each hook parameter is passed in as an environment variable; the name is upper cased, and prefixed with the string HG_.

With the exception of hook parameters, Mercurial does not set or modify any environment variables when running a hook. This is useful to remember if you are writing a site-wide hook that may be run by a number of different users with differing environment variables set. In multi-user situations, you should not rely on environment variables being set to the values you have in your environment when testing the hook.

Telling Mercurial to Use an In-Process Hook

The ~/.hgrc syntax for defining an in-process hook is slightly different than for an executable hook. The value of the hook must start with the text python:, and continue with the fully qualified name of a callable object to use as the hook’s value.

The module in which a hook lives is automatically imported when a hook is run. As long as you have the module name and PYTHONPATH right, it should “just work.”

The following ~/.hgrc example snippet illustrates the syntax and meaning of the notions we just described.

[hooks]

commit.example = python:mymodule.submodule.myhook

When Mercurial runs the commit.example hook, it imports mymodule.submodule, looks for the callable object named myhook, and calls it.

Writing an In-Process Hook

The simplest in-process hook does nothing, but illustrates the basic shape of the hook API:

def myhook(ui, repo, **kwargs):

pass

The first argument to a Python hook is always a ui object. The second is a repository

Return Main Page Previous Page Next Page

®Online Book Reader