hgbook

diff 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
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/en/hook.tex	Sun Jul 16 00:01:43 2006 -0700
     1.3 @@ -0,0 +1,139 @@
     1.4 +\chapter{Handling repository events with hooks}
     1.5 +\label{chap:hook}
     1.6 +
     1.7 +Mercurial offers a powerful mechanism to let you perform automated
     1.8 +actions in response to events that occur in a repository.  In some
     1.9 +cases, you can even control Mercurial's response to those events.
    1.10 +
    1.11 +The name Mercurial uses for one of these actions is a \emph{hook}.
    1.12 +Hooks are called ``triggers'' in some revision control systems, but
    1.13 +the two names refer to the same idea.
    1.14 +
    1.15 +\section{A short tutorial on using hooks}
    1.16 +\label{sec:hook:simple}
    1.17 +
    1.18 +It is easy to write a Mercurial hook.  Let's start with a hook that
    1.19 +runs when you finish a \hgcmd{commit}, and simply prints the hash of
    1.20 +the changeset you just created.  The hook is called \hook{commit}.
    1.21 +
    1.22 +\begin{figure}[ht]
    1.23 +  \interaction{hook.simple.init}
    1.24 +  \caption{A simple hook that runs when a changeset is committed}
    1.25 +  \label{ex:hook:init}
    1.26 +\end{figure}
    1.27 +
    1.28 +All hooks follow the pattern in example~\ref{ex:hook:init}.  You add
    1.29 +an entry to the \rcsection{hooks} section of your \hgrc\.  On the left
    1.30 +is the name of the event to trigger on; on the right is the action to
    1.31 +take.  As you can see, you can run an arbitrary shell command in a
    1.32 +hook.  Mercurial passes extra information to the hook using
    1.33 +environment variables (look for \envar{HG\_NODE} in the example).
    1.34 +
    1.35 +\subsection{Performing multiple actions per event}
    1.36 +
    1.37 +Quite often, you will want to define more than one hook for a
    1.38 +particular kind of event, as shown in example~\ref{ex:hook:ext}.
    1.39 +Mercurial lets you do this by adding an \emph{extension} to the end of
    1.40 +a hook's name.  You extend a hook's name by giving the name of the
    1.41 +hook, followed by a full stop (the ``\texttt{.}'' character), followed
    1.42 +by some more text of your choosing.  For example, Mercurial will run
    1.43 +both \texttt{commit.foo} and \texttt{commit.bar} when the
    1.44 +\texttt{commit} event occurs.
    1.45 +
    1.46 +\begin{figure}[ht]
    1.47 +  \interaction{hook.simple.ext}
    1.48 +  \caption{Defining a second \hook{commit} hook}
    1.49 +  \label{ex:hook:ext}
    1.50 +\end{figure}
    1.51 +
    1.52 +To give a well-defined order of execution when there are multiple
    1.53 +hooks defined for an event, Mercurial sorts hooks by extension, and
    1.54 +executes the hook commands in this sorted order.  In the above
    1.55 +example, it will execute \texttt{commit.bar} before
    1.56 +\texttt{commit.foo}, and \texttt{commit} before both.
    1.57 +
    1.58 +It is a good idea to use a somewhat descriptive extension when you
    1.59 +define a new hook.  This will help you to remember what the hook was
    1.60 +for.  If the hook fails, you'll get an error message that contains the
    1.61 +hook name and extension, so using a descriptive extension could give
    1.62 +you an immediate hint as to why the hook failed (see
    1.63 +section~\ref{sec:hook:perm} for an example).
    1.64 +
    1.65 +\subsection{Controlling whether an activity can proceed}
    1.66 +\label{sec:hook:perm}
    1.67 +
    1.68 +In our earlier examples, we used the \hook{commit} hook, which is
    1.69 +run after a commit has completed.  This is one of several Mercurial
    1.70 +hooks that run after an activity finishes.  Such hooks have no way of
    1.71 +influencing the activity itself.
    1.72 +
    1.73 +Mercurial defines a number of events that occur before an activity
    1.74 +starts; or after it starts, but before it finishes.  Hooks that
    1.75 +trigger on these events have the added ability to choose whether the
    1.76 +activity can continue, or will abort.  
    1.77 +
    1.78 +The \hook{pretxncommit} hook runs after a commit has all but
    1.79 +completed.  In other words, the metadata representing the changeset
    1.80 +has been written out to disk, but the transaction has not yet been
    1.81 +allowed to complete.  The \hook{pretxncommit} hook has the ability to
    1.82 +decide whether the transaction can complete, or must be rolled back.
    1.83 +
    1.84 +If the \hook{pretxncommit} hook exits with a status code of zero, the
    1.85 +transaction is allowed to complete; the commit finishes; and the
    1.86 +\hook{commit} hook is run.  If the \hook{pretxncommit} hook exits with
    1.87 +a non-zero status code, the transaction is rolled back; the metadata
    1.88 +representing the changeset is erased; and the \hook{commit} hook is
    1.89 +not run.
    1.90 +
    1.91 +\begin{figure}[ht]
    1.92 +  \interaction{hook.simple.pretxncommit}
    1.93 +  \caption{Using the \hook{pretxncommit} hook to control commits}
    1.94 +  \label{ex:hook:pretxncommit}
    1.95 +\end{figure}
    1.96 +
    1.97 +The hook in example~\ref{ex:hook:pretxncommit} checks that a commit
    1.98 +comment contains a bug ID.  If it does, the commit can complete.  If
    1.99 +not, the commit is rolled back.
   1.100 +
   1.101 +\section{Choosing how to write a hook}
   1.102 +\label{sec:hook:impl}
   1.103 +
   1.104 +You can write a hook either as a normal program---typically a shell
   1.105 +script---or as a Python function that is called within the Mercurial
   1.106 +process.
   1.107 +
   1.108 +Writing a hook as an external program has the advantage that it
   1.109 +requires no knowledge of Mercurial's internals.  You can call normal
   1.110 +Mercurial commands to get any added information you need.  The
   1.111 +trade-off is that external hooks are slower than in-process hooks.
   1.112 +
   1.113 +An in-process Python hook has complete access to the Mercurial API,
   1.114 +and does not ``shell out'' to another process, so it is inherently
   1.115 +faster than an external hook.  It is also easier to obtain much of the
   1.116 +information that a hook requires by using the Mercurial API than by
   1.117 +running Mercurial commands.
   1.118 +
   1.119 +If you are comfortable with Python, or require high performance,
   1.120 +writing your hooks in Python may be a good choice.  However, when you
   1.121 +have a straightforward hook to write and you don't need to care about
   1.122 +performance (probably the majority of hooks), a shell script is
   1.123 +perfectly fine.
   1.124 +
   1.125 +\section{Hook parameters}
   1.126 +\label{sec:hook:param}
   1.127 +
   1.128 +Mercurial calls each hook with a set of well-defined parameters.  In
   1.129 +Python, a parameter is passed as a keyword argument to your hook
   1.130 +function.  For an external program, a parameter is passed as an
   1.131 +environment variable.
   1.132 +
   1.133 +Whether your hook is written in Python or as a shell script, the
   1.134 +parameter names and values will be the same.  A boolean parameter will
   1.135 +be represented as a boolean value in Python, but as the number 1 (for
   1.136 +``true'') or 0 (for ``false'')
   1.137 +
   1.138 +
   1.139 +%%% Local Variables: 
   1.140 +%%% mode: latex
   1.141 +%%% TeX-master: "00book"
   1.142 +%%% End: