hgbook

annotate en/hook.tex @ 37:9fd0c59b009a

Add to hook chapter.
Document each macro in 99defs.tex.
author Bryan O'Sullivan <bos@serpentine.com>
date Mon Jul 17 00:01:01 2006 -0700 (2006-07-17)
parents c0979ed1eabd
children b49a7dd4e564
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@37 98 \section{Writing your own hooks}
bos@37 99
bos@37 100 When you are writing a hook, you might find it useful to run Mercurial
bos@37 101 either with the \hggopt{-v} option, or the \rcitem{ui}{verbose} config
bos@37 102 item set to ``true''. When you do so, Mercurial will print a message
bos@37 103 before it calls each hook.
bos@37 104
bos@37 105 \subsection{Choosing how your hook should run}
bos@37 106 \label{sec:hook:lang}
bos@34 107
bos@34 108 You can write a hook either as a normal program---typically a shell
bos@37 109 script---or as a Python function that is executed within the Mercurial
bos@34 110 process.
bos@34 111
bos@34 112 Writing a hook as an external program has the advantage that it
bos@34 113 requires no knowledge of Mercurial's internals. You can call normal
bos@34 114 Mercurial commands to get any added information you need. The
bos@34 115 trade-off is that external hooks are slower than in-process hooks.
bos@34 116
bos@34 117 An in-process Python hook has complete access to the Mercurial API,
bos@34 118 and does not ``shell out'' to another process, so it is inherently
bos@34 119 faster than an external hook. It is also easier to obtain much of the
bos@34 120 information that a hook requires by using the Mercurial API than by
bos@34 121 running Mercurial commands.
bos@34 122
bos@34 123 If you are comfortable with Python, or require high performance,
bos@34 124 writing your hooks in Python may be a good choice. However, when you
bos@34 125 have a straightforward hook to write and you don't need to care about
bos@34 126 performance (probably the majority of hooks), a shell script is
bos@34 127 perfectly fine.
bos@34 128
bos@37 129 \subsection{Hook parameters}
bos@34 130 \label{sec:hook:param}
bos@34 131
bos@34 132 Mercurial calls each hook with a set of well-defined parameters. In
bos@34 133 Python, a parameter is passed as a keyword argument to your hook
bos@34 134 function. For an external program, a parameter is passed as an
bos@34 135 environment variable.
bos@34 136
bos@34 137 Whether your hook is written in Python or as a shell script, the
bos@37 138 hook-specific parameter names and values will be the same. A boolean
bos@37 139 parameter will be represented as a boolean value in Python, but as the
bos@37 140 number 1 (for ``true'') or 0 (for ``false'') as an environment
bos@37 141 variable for an external hook. If a hook parameter is named
bos@37 142 \texttt{foo}, the keyword argument for a Python hook will also be
bos@37 143 named \texttt{foo} Python, while the environment variable for an
bos@37 144 external hook will be named \texttt{HG\_FOO}.
bos@37 145
bos@37 146 \subsection{Hook return values and activity control}
bos@37 147
bos@37 148 A hook that executes successfully must exit with a status of zero if
bos@37 149 external, or return boolean ``false'' if in-process. Failure is
bos@37 150 indicated with a non-zero exit status from an external hook, or an
bos@37 151 in-process hook returning boolean ``true''. If an in-process hook
bos@37 152 raises an exception, the hook is considered to have failed.
bos@37 153
bos@37 154 For a hook that controls whether an activity can proceed, zero/false
bos@37 155 means ``allow'', while non-zero/true/exception means ``deny''.
bos@37 156
bos@37 157 \subsection{Writing an external hook}
bos@37 158
bos@37 159 When you define an external hook in your \hgrc\ and the hook is run,
bos@37 160 its value is passed to your shell, which interprets it. This means
bos@37 161 that you can use normal shell constructs in the body of the hook.
bos@37 162
bos@37 163 An executable hook is always run with its current directory set to a
bos@37 164 repository's root directory.
bos@37 165
bos@37 166 Each hook parameter is passed in as an environment variable; the name
bos@37 167 is upper-cased, and prefixed with the string ``\texttt{HG\_}''.
bos@37 168
bos@37 169 With the exception of hook parameters, Mercurial does not set or
bos@37 170 modify any environment variables when running a hook. This is useful
bos@37 171 to remember if you are writing a site-wide hook that may be run by a
bos@37 172 number of different users with differing environment variables set.
bos@37 173 In multi-user situations, you should not rely on environment variables
bos@37 174 being set to the values you have in your environment when testing the
bos@37 175 hook.
bos@37 176
bos@37 177 \subsection{Telling Mercurial to use an in-process hook}
bos@37 178
bos@37 179 The \hgrc\ syntax for defining an in-process hook is slightly
bos@37 180 different than for an executable hook. The value of the hook must
bos@37 181 start with the text ``\texttt{python:}'', and continue with the
bos@37 182 fully-qualified name of a callable object to use as the hook's value.
bos@37 183
bos@37 184 The module in which a hook lives is automatically imported when a hook
bos@37 185 is run. So long as you have the module name and \envar{PYTHONPATH}
bos@37 186 right, it should ``just work''.
bos@37 187
bos@37 188 The following \hgrc\ example snippet illustrates the syntax and
bos@37 189 meaning of the notions we just described.
bos@37 190 \begin{codesample2}
bos@37 191 [hooks]
bos@37 192 commit.example = python:mymodule.submodule.myhook
bos@37 193 \end{codesample2}
bos@37 194 When Mercurial runs the \texttt{commit.example} hook, it imports
bos@37 195 \texttt{mymodule.submodule}, looks for the callable object named
bos@37 196 \texttt{myhook}, and calls it.
bos@37 197
bos@37 198 \subsection{Writing an in-process hook}
bos@37 199
bos@37 200 The simplest in-process hook does nothing, but illustrates the basic
bos@37 201 shape of the hook API:
bos@37 202 \begin{codesample2}
bos@37 203 def myhook(ui, repo, **kwargs):
bos@37 204 pass
bos@37 205 \end{codesample2}
bos@37 206 The first argument to a Python hook is always a
bos@37 207 \pymodclass{mercurial.ui}{ui} object. The second is a repository object;
bos@37 208 at the moment, it is always an instance of
bos@37 209 \pymodclass{mercurial.localrepo}{localrepository}. Following these two
bos@37 210 arguments are other keyword arguments. Which ones are passed in
bos@37 211 depends on the hook being called, but a hook can ignore arguments it
bos@37 212 doesn't care about by dropping them into a keyword argument dict, as
bos@37 213 with \texttt{**kwargs} above.
bos@34 214
bos@34 215
bos@34 216 %%% Local Variables:
bos@34 217 %%% mode: latex
bos@34 218 %%% TeX-master: "00book"
bos@34 219 %%% End: