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