hgbook
diff en/hook.tex @ 56:b8539d91c84d
Begining of concepts chapter
author | Josef "Jeff" Sipek <jeffpc@josefsipek.net> |
---|---|
date | Mon Jul 24 23:57:52 2006 -0400 (2006-07-24) |
parents | |
children | 9fd0c59b009a |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/en/hook.tex Mon Jul 24 23:57:52 2006 -0400 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: