hgbook

annotate en/hook.tex @ 34:c0979ed1eabd

Get started on hook chapter.
author Bryan O'Sullivan <bos@serpentine.com>
date Sun Jul 16 00:01:43 2006 -0700 (2006-07-16)
parents
children 9fd0c59b009a
rev   line source
bos@34 1 \chapter{Handling repository events with hooks}
bos@34 2 \label{chap:hook}
bos@34 3
bos@34 4 Mercurial offers a powerful mechanism to let you perform automated
bos@34 5 actions in response to events that occur in a repository. In some
bos@34 6 cases, you can even control Mercurial's response to those events.
bos@34 7
bos@34 8 The name Mercurial uses for one of these actions is a \emph{hook}.
bos@34 9 Hooks are called ``triggers'' in some revision control systems, but
bos@34 10 the two names refer to the same idea.
bos@34 11
bos@34 12 \section{A short tutorial on using hooks}
bos@34 13 \label{sec:hook:simple}
bos@34 14
bos@34 15 It is easy to write a Mercurial hook. Let's start with a hook that
bos@34 16 runs when you finish a \hgcmd{commit}, and simply prints the hash of
bos@34 17 the changeset you just created. The hook is called \hook{commit}.
bos@34 18
bos@34 19 \begin{figure}[ht]
bos@34 20 \interaction{hook.simple.init}
bos@34 21 \caption{A simple hook that runs when a changeset is committed}
bos@34 22 \label{ex:hook:init}
bos@34 23 \end{figure}
bos@34 24
bos@34 25 All hooks follow the pattern in example~\ref{ex:hook:init}. You add
bos@34 26 an entry to the \rcsection{hooks} section of your \hgrc\. On the left
bos@34 27 is the name of the event to trigger on; on the right is the action to
bos@34 28 take. As you can see, you can run an arbitrary shell command in a
bos@34 29 hook. Mercurial passes extra information to the hook using
bos@34 30 environment variables (look for \envar{HG\_NODE} in the example).
bos@34 31
bos@34 32 \subsection{Performing multiple actions per event}
bos@34 33
bos@34 34 Quite often, you will want to define more than one hook for a
bos@34 35 particular kind of event, as shown in example~\ref{ex:hook:ext}.
bos@34 36 Mercurial lets you do this by adding an \emph{extension} to the end of
bos@34 37 a hook's name. You extend a hook's name by giving the name of the
bos@34 38 hook, followed by a full stop (the ``\texttt{.}'' character), followed
bos@34 39 by some more text of your choosing. For example, Mercurial will run
bos@34 40 both \texttt{commit.foo} and \texttt{commit.bar} when the
bos@34 41 \texttt{commit} event occurs.
bos@34 42
bos@34 43 \begin{figure}[ht]
bos@34 44 \interaction{hook.simple.ext}
bos@34 45 \caption{Defining a second \hook{commit} hook}
bos@34 46 \label{ex:hook:ext}
bos@34 47 \end{figure}
bos@34 48
bos@34 49 To give a well-defined order of execution when there are multiple
bos@34 50 hooks defined for an event, Mercurial sorts hooks by extension, and
bos@34 51 executes the hook commands in this sorted order. In the above
bos@34 52 example, it will execute \texttt{commit.bar} before
bos@34 53 \texttt{commit.foo}, and \texttt{commit} before both.
bos@34 54
bos@34 55 It is a good idea to use a somewhat descriptive extension when you
bos@34 56 define a new hook. This will help you to remember what the hook was
bos@34 57 for. If the hook fails, you'll get an error message that contains the
bos@34 58 hook name and extension, so using a descriptive extension could give
bos@34 59 you an immediate hint as to why the hook failed (see
bos@34 60 section~\ref{sec:hook:perm} for an example).
bos@34 61
bos@34 62 \subsection{Controlling whether an activity can proceed}
bos@34 63 \label{sec:hook:perm}
bos@34 64
bos@34 65 In our earlier examples, we used the \hook{commit} hook, which is
bos@34 66 run after a commit has completed. This is one of several Mercurial
bos@34 67 hooks that run after an activity finishes. Such hooks have no way of
bos@34 68 influencing the activity itself.
bos@34 69
bos@34 70 Mercurial defines a number of events that occur before an activity
bos@34 71 starts; or after it starts, but before it finishes. Hooks that
bos@34 72 trigger on these events have the added ability to choose whether the
bos@34 73 activity can continue, or will abort.
bos@34 74
bos@34 75 The \hook{pretxncommit} hook runs after a commit has all but
bos@34 76 completed. In other words, the metadata representing the changeset
bos@34 77 has been written out to disk, but the transaction has not yet been
bos@34 78 allowed to complete. The \hook{pretxncommit} hook has the ability to
bos@34 79 decide whether the transaction can complete, or must be rolled back.
bos@34 80
bos@34 81 If the \hook{pretxncommit} hook exits with a status code of zero, the
bos@34 82 transaction is allowed to complete; the commit finishes; and the
bos@34 83 \hook{commit} hook is run. If the \hook{pretxncommit} hook exits with
bos@34 84 a non-zero status code, the transaction is rolled back; the metadata
bos@34 85 representing the changeset is erased; and the \hook{commit} hook is
bos@34 86 not run.
bos@34 87
bos@34 88 \begin{figure}[ht]
bos@34 89 \interaction{hook.simple.pretxncommit}
bos@34 90 \caption{Using the \hook{pretxncommit} hook to control commits}
bos@34 91 \label{ex:hook:pretxncommit}
bos@34 92 \end{figure}
bos@34 93
bos@34 94 The hook in example~\ref{ex:hook:pretxncommit} checks that a commit
bos@34 95 comment contains a bug ID. If it does, the commit can complete. If
bos@34 96 not, the commit is rolled back.
bos@34 97
bos@34 98 \section{Choosing how to write a hook}
bos@34 99 \label{sec:hook:impl}
bos@34 100
bos@34 101 You can write a hook either as a normal program---typically a shell
bos@34 102 script---or as a Python function that is called within the Mercurial
bos@34 103 process.
bos@34 104
bos@34 105 Writing a hook as an external program has the advantage that it
bos@34 106 requires no knowledge of Mercurial's internals. You can call normal
bos@34 107 Mercurial commands to get any added information you need. The
bos@34 108 trade-off is that external hooks are slower than in-process hooks.
bos@34 109
bos@34 110 An in-process Python hook has complete access to the Mercurial API,
bos@34 111 and does not ``shell out'' to another process, so it is inherently
bos@34 112 faster than an external hook. It is also easier to obtain much of the
bos@34 113 information that a hook requires by using the Mercurial API than by
bos@34 114 running Mercurial commands.
bos@34 115
bos@34 116 If you are comfortable with Python, or require high performance,
bos@34 117 writing your hooks in Python may be a good choice. However, when you
bos@34 118 have a straightforward hook to write and you don't need to care about
bos@34 119 performance (probably the majority of hooks), a shell script is
bos@34 120 perfectly fine.
bos@34 121
bos@34 122 \section{Hook parameters}
bos@34 123 \label{sec:hook:param}
bos@34 124
bos@34 125 Mercurial calls each hook with a set of well-defined parameters. In
bos@34 126 Python, a parameter is passed as a keyword argument to your hook
bos@34 127 function. For an external program, a parameter is passed as an
bos@34 128 environment variable.
bos@34 129
bos@34 130 Whether your hook is written in Python or as a shell script, the
bos@34 131 parameter names and values will be the same. A boolean parameter will
bos@34 132 be represented as a boolean value in Python, but as the number 1 (for
bos@34 133 ``true'') or 0 (for ``false'')
bos@34 134
bos@34 135
bos@34 136 %%% Local Variables:
bos@34 137 %%% mode: latex
bos@34 138 %%% TeX-master: "00book"
bos@34 139 %%% End: