hgbook
changeset 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 | a17b0f38286d |
children | e68f4a96c16e b8539d91c84d |
files | en/00book.tex en/99defs.tex en/Makefile en/examples/hook.simple en/hook.tex |
line diff
1.1 --- a/en/00book.tex Sun Jul 16 00:01:21 2006 -0700 1.2 +++ b/en/00book.tex Sun Jul 16 00:01:43 2006 -0700 1.3 @@ -37,6 +37,7 @@ 1.4 1.5 \include{preface} 1.6 \include{intro} 1.7 +\include{hook} 1.8 \include{mq} 1.9 1.10 \appendix
2.1 --- a/en/99defs.tex Sun Jul 16 00:01:21 2006 -0700 2.2 +++ b/en/99defs.tex Sun Jul 16 00:01:43 2006 -0700 2.3 @@ -13,6 +13,13 @@ 2.4 \newcommand{\cmdopt}[2]{\index{\texttt{#1} command!\texttt{#2} option}\texttt{#2}} 2.5 \newcommand{\option}[1]{\texttt{#1}} 2.6 \newcommand{\package}[1]{\index{\texttt{#1} package}\texttt{#1}} 2.7 +\newcommand{\rcsection}[1]{\index{\texttt{hgrc} file!\texttt{#1} section}\texttt{[#1]}} 2.8 +\newcommand{\rcitem}[2]{\index{\texttt{hgrc} file!\texttt{#1} 2.9 + section!\texttt{#2} entry}\texttt{#1.#2}} 2.10 +\newcommand{\hgrc}{\index{\texttt{hgrc} file}\texttt{hgrc}} 2.11 +\newcommand{\hook}[1]{\index{\texttt{#1} hook}\index{hooks!\texttt{#1}}\texttt{#1}} 2.12 +\newcommand{\envar}[1]{\index{\texttt{#1} environment 2.13 + variable}\index{environment variables!\texttt{#1}}\texttt{#1}} 2.14 2.15 \newsavebox{\notebox} 2.16 \newenvironment{note}%
3.1 --- a/en/Makefile Sun Jul 16 00:01:21 2006 -0700 3.2 +++ b/en/Makefile Sun Jul 16 00:01:43 2006 -0700 3.3 @@ -6,16 +6,18 @@ 3.4 00book.tex \ 3.5 99book.bib \ 3.6 99defs.tex \ 3.7 - preface.tex \ 3.8 + build_id.tex \ 3.9 + hook.tex \ 3.10 intro.tex \ 3.11 mq.tex \ 3.12 - build_id.tex 3.13 + preface.tex 3.14 3.15 image-sources := \ 3.16 mq-stack.svg 3.17 3.18 example-sources := \ 3.19 examples/run-example \ 3.20 + examples/hook.simple \ 3.21 examples/mq.qinit-help \ 3.22 examples/mq.diff \ 3.23 examples/mq.tarball \
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/en/examples/hook.simple Sun Jul 16 00:01:43 2006 -0700 4.3 @@ -0,0 +1,34 @@ 4.4 +#$ name: init 4.5 + 4.6 +hg init hook-test 4.7 +cd hook-test 4.8 +echo '[hooks]' >> .hg/hgrc 4.9 +echo 'commit = echo committed $HG_NODE' >> .hg/hgrc 4.10 +cat .hg/hgrc 4.11 +echo a > a 4.12 +hg add a 4.13 +hg commit -m 'testing commit hook' 4.14 + 4.15 +#$ name: ext 4.16 + 4.17 +echo 'commit.when = echo "date of commit:"; date' >> .hg/hgrc 4.18 +echo a >> a 4.19 +hg commit -m 'i have two hooks' 4.20 + 4.21 +#$ name: 4.22 + 4.23 +echo '#!/bin/sh' >> check_bug_id 4.24 +echo '# check that a commit comment mentions a numeric bug id' >> check_bug_id 4.25 +echo 'hg log -r $1 --template {desc} | grep -q "\<bug *[0-9]"' >> check_bug_id 4.26 +chmod +x check_bug_id 4.27 + 4.28 +#$ name: pretxncommit 4.29 + 4.30 +cat check_bug_id 4.31 + 4.32 +echo 'pretxncommit.bug_id_required = ./check_bug_id $HG_NODE' >> .hg/hgrc 4.33 + 4.34 +echo a >> a 4.35 +hg commit -m 'i am not mentioning a bug id' 4.36 + 4.37 +hg commit -m 'i refer you to bug 666'
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/en/hook.tex Sun Jul 16 00:01:43 2006 -0700 5.3 @@ -0,0 +1,139 @@ 5.4 +\chapter{Handling repository events with hooks} 5.5 +\label{chap:hook} 5.6 + 5.7 +Mercurial offers a powerful mechanism to let you perform automated 5.8 +actions in response to events that occur in a repository. In some 5.9 +cases, you can even control Mercurial's response to those events. 5.10 + 5.11 +The name Mercurial uses for one of these actions is a \emph{hook}. 5.12 +Hooks are called ``triggers'' in some revision control systems, but 5.13 +the two names refer to the same idea. 5.14 + 5.15 +\section{A short tutorial on using hooks} 5.16 +\label{sec:hook:simple} 5.17 + 5.18 +It is easy to write a Mercurial hook. Let's start with a hook that 5.19 +runs when you finish a \hgcmd{commit}, and simply prints the hash of 5.20 +the changeset you just created. The hook is called \hook{commit}. 5.21 + 5.22 +\begin{figure}[ht] 5.23 + \interaction{hook.simple.init} 5.24 + \caption{A simple hook that runs when a changeset is committed} 5.25 + \label{ex:hook:init} 5.26 +\end{figure} 5.27 + 5.28 +All hooks follow the pattern in example~\ref{ex:hook:init}. You add 5.29 +an entry to the \rcsection{hooks} section of your \hgrc\. On the left 5.30 +is the name of the event to trigger on; on the right is the action to 5.31 +take. As you can see, you can run an arbitrary shell command in a 5.32 +hook. Mercurial passes extra information to the hook using 5.33 +environment variables (look for \envar{HG\_NODE} in the example). 5.34 + 5.35 +\subsection{Performing multiple actions per event} 5.36 + 5.37 +Quite often, you will want to define more than one hook for a 5.38 +particular kind of event, as shown in example~\ref{ex:hook:ext}. 5.39 +Mercurial lets you do this by adding an \emph{extension} to the end of 5.40 +a hook's name. You extend a hook's name by giving the name of the 5.41 +hook, followed by a full stop (the ``\texttt{.}'' character), followed 5.42 +by some more text of your choosing. For example, Mercurial will run 5.43 +both \texttt{commit.foo} and \texttt{commit.bar} when the 5.44 +\texttt{commit} event occurs. 5.45 + 5.46 +\begin{figure}[ht] 5.47 + \interaction{hook.simple.ext} 5.48 + \caption{Defining a second \hook{commit} hook} 5.49 + \label{ex:hook:ext} 5.50 +\end{figure} 5.51 + 5.52 +To give a well-defined order of execution when there are multiple 5.53 +hooks defined for an event, Mercurial sorts hooks by extension, and 5.54 +executes the hook commands in this sorted order. In the above 5.55 +example, it will execute \texttt{commit.bar} before 5.56 +\texttt{commit.foo}, and \texttt{commit} before both. 5.57 + 5.58 +It is a good idea to use a somewhat descriptive extension when you 5.59 +define a new hook. This will help you to remember what the hook was 5.60 +for. If the hook fails, you'll get an error message that contains the 5.61 +hook name and extension, so using a descriptive extension could give 5.62 +you an immediate hint as to why the hook failed (see 5.63 +section~\ref{sec:hook:perm} for an example). 5.64 + 5.65 +\subsection{Controlling whether an activity can proceed} 5.66 +\label{sec:hook:perm} 5.67 + 5.68 +In our earlier examples, we used the \hook{commit} hook, which is 5.69 +run after a commit has completed. This is one of several Mercurial 5.70 +hooks that run after an activity finishes. Such hooks have no way of 5.71 +influencing the activity itself. 5.72 + 5.73 +Mercurial defines a number of events that occur before an activity 5.74 +starts; or after it starts, but before it finishes. Hooks that 5.75 +trigger on these events have the added ability to choose whether the 5.76 +activity can continue, or will abort. 5.77 + 5.78 +The \hook{pretxncommit} hook runs after a commit has all but 5.79 +completed. In other words, the metadata representing the changeset 5.80 +has been written out to disk, but the transaction has not yet been 5.81 +allowed to complete. The \hook{pretxncommit} hook has the ability to 5.82 +decide whether the transaction can complete, or must be rolled back. 5.83 + 5.84 +If the \hook{pretxncommit} hook exits with a status code of zero, the 5.85 +transaction is allowed to complete; the commit finishes; and the 5.86 +\hook{commit} hook is run. If the \hook{pretxncommit} hook exits with 5.87 +a non-zero status code, the transaction is rolled back; the metadata 5.88 +representing the changeset is erased; and the \hook{commit} hook is 5.89 +not run. 5.90 + 5.91 +\begin{figure}[ht] 5.92 + \interaction{hook.simple.pretxncommit} 5.93 + \caption{Using the \hook{pretxncommit} hook to control commits} 5.94 + \label{ex:hook:pretxncommit} 5.95 +\end{figure} 5.96 + 5.97 +The hook in example~\ref{ex:hook:pretxncommit} checks that a commit 5.98 +comment contains a bug ID. If it does, the commit can complete. If 5.99 +not, the commit is rolled back. 5.100 + 5.101 +\section{Choosing how to write a hook} 5.102 +\label{sec:hook:impl} 5.103 + 5.104 +You can write a hook either as a normal program---typically a shell 5.105 +script---or as a Python function that is called within the Mercurial 5.106 +process. 5.107 + 5.108 +Writing a hook as an external program has the advantage that it 5.109 +requires no knowledge of Mercurial's internals. You can call normal 5.110 +Mercurial commands to get any added information you need. The 5.111 +trade-off is that external hooks are slower than in-process hooks. 5.112 + 5.113 +An in-process Python hook has complete access to the Mercurial API, 5.114 +and does not ``shell out'' to another process, so it is inherently 5.115 +faster than an external hook. It is also easier to obtain much of the 5.116 +information that a hook requires by using the Mercurial API than by 5.117 +running Mercurial commands. 5.118 + 5.119 +If you are comfortable with Python, or require high performance, 5.120 +writing your hooks in Python may be a good choice. However, when you 5.121 +have a straightforward hook to write and you don't need to care about 5.122 +performance (probably the majority of hooks), a shell script is 5.123 +perfectly fine. 5.124 + 5.125 +\section{Hook parameters} 5.126 +\label{sec:hook:param} 5.127 + 5.128 +Mercurial calls each hook with a set of well-defined parameters. In 5.129 +Python, a parameter is passed as a keyword argument to your hook 5.130 +function. For an external program, a parameter is passed as an 5.131 +environment variable. 5.132 + 5.133 +Whether your hook is written in Python or as a shell script, the 5.134 +parameter names and values will be the same. A boolean parameter will 5.135 +be represented as a boolean value in Python, but as the number 1 (for 5.136 +``true'') or 0 (for ``false'') 5.137 + 5.138 + 5.139 +%%% Local Variables: 5.140 +%%% mode: latex 5.141 +%%% TeX-master: "00book" 5.142 +%%% End: