Bryan O'Sullivan committed c0979ed

Get started on hook chapter.

Comments (0)

Files changed (5)

 \newcommand{\cmdopt}[2]{\index{\texttt{#1} command!\texttt{#2} option}\texttt{#2}}
 \newcommand{\package}[1]{\index{\texttt{#1} package}\texttt{#1}}
+\newcommand{\rcsection}[1]{\index{\texttt{hgrc} file!\texttt{#1} section}\texttt{[#1]}}
+\newcommand{\rcitem}[2]{\index{\texttt{hgrc} file!\texttt{#1}
+    section!\texttt{#2} entry}\texttt{#1.#2}}
+\newcommand{\hgrc}{\index{\texttt{hgrc} file}\texttt{hgrc}}
+\newcommand{\hook}[1]{\index{\texttt{#1} hook}\index{hooks!\texttt{#1}}\texttt{#1}}
+\newcommand{\envar}[1]{\index{\texttt{#1} environment
+    variable}\index{environment variables!\texttt{#1}}\texttt{#1}}
 	00book.tex \
 	99book.bib \
 	99defs.tex \
-	preface.tex \
+	build_id.tex \
+	hook.tex \
 	intro.tex \
 	mq.tex \
-	build_id.tex
+	preface.tex
 image-sources := \
 example-sources := \
 	examples/run-example \
+	examples/hook.simple \
 	examples/mq.qinit-help \
 	examples/mq.diff \
 	examples/mq.tarball \


+#$ name: init
+hg init hook-test
+cd hook-test
+echo '[hooks]' >> .hg/hgrc
+echo 'commit = echo committed $HG_NODE' >> .hg/hgrc
+cat .hg/hgrc
+echo a > a
+hg add a
+hg commit -m 'testing commit hook'
+#$ name: ext
+echo 'commit.when = echo "date of commit:"; date' >> .hg/hgrc
+echo a >> a
+hg commit -m 'i have two hooks'
+#$ name:
+echo '#!/bin/sh' >> check_bug_id
+echo '# check that a commit comment mentions a numeric bug id' >> check_bug_id
+echo 'hg log -r $1 --template {desc} | grep -q "\<bug *[0-9]"' >> check_bug_id
+chmod +x check_bug_id
+#$ name: pretxncommit
+cat check_bug_id
+echo 'pretxncommit.bug_id_required = ./check_bug_id $HG_NODE' >> .hg/hgrc
+echo a >> a
+hg commit -m 'i am not mentioning a bug id'
+hg commit -m 'i refer you to bug 666'
+\chapter{Handling repository events with hooks}
+Mercurial offers a powerful mechanism to let you perform automated
+actions in response to events that occur in a repository.  In some
+cases, you can even control Mercurial's response to those events.
+The name Mercurial uses for one of these actions is a \emph{hook}.
+Hooks are called ``triggers'' in some revision control systems, but
+the two names refer to the same idea.
+\section{A short tutorial on using hooks}
+It is easy to write a Mercurial hook.  Let's start with a hook that
+runs when you finish a \hgcmd{commit}, and simply prints the hash of
+the changeset you just created.  The hook is called \hook{commit}.
+  \interaction{hook.simple.init}
+  \caption{A simple hook that runs when a changeset is committed}
+  \label{ex:hook:init}
+All hooks follow the pattern in example~\ref{ex:hook:init}.  You add
+an entry to the \rcsection{hooks} section of your \hgrc\.  On the left
+is the name of the event to trigger on; on the right is the action to
+take.  As you can see, you can run an arbitrary shell command in a
+hook.  Mercurial passes extra information to the hook using
+environment variables (look for \envar{HG\_NODE} in the example).
+\subsection{Performing multiple actions per event}
+Quite often, you will want to define more than one hook for a
+particular kind of event, as shown in example~\ref{ex:hook:ext}.
+Mercurial lets you do this by adding an \emph{extension} to the end of
+a hook's name.  You extend a hook's name by giving the name of the
+hook, followed by a full stop (the ``\texttt{.}'' character), followed
+by some more text of your choosing.  For example, Mercurial will run
+both \texttt{} and \texttt{} when the
+\texttt{commit} event occurs.
+  \interaction{hook.simple.ext}
+  \caption{Defining a second \hook{commit} hook}
+  \label{ex:hook:ext}
+To give a well-defined order of execution when there are multiple
+hooks defined for an event, Mercurial sorts hooks by extension, and
+executes the hook commands in this sorted order.  In the above
+example, it will execute \texttt{} before
+\texttt{}, and \texttt{commit} before both.
+It is a good idea to use a somewhat descriptive extension when you
+define a new hook.  This will help you to remember what the hook was
+for.  If the hook fails, you'll get an error message that contains the
+hook name and extension, so using a descriptive extension could give
+you an immediate hint as to why the hook failed (see
+section~\ref{sec:hook:perm} for an example).
+\subsection{Controlling whether an activity can proceed}
+In our earlier examples, we used the \hook{commit} hook, which is
+run after a commit has completed.  This is one of several Mercurial
+hooks that run after an activity finishes.  Such hooks have no way of
+influencing the activity itself.
+Mercurial defines a number of events that occur before an activity
+starts; or after it starts, but before it finishes.  Hooks that
+trigger on these events have the added ability to choose whether the
+activity can continue, or will abort.  
+The \hook{pretxncommit} hook runs after a commit has all but
+completed.  In other words, the metadata representing the changeset
+has been written out to disk, but the transaction has not yet been
+allowed to complete.  The \hook{pretxncommit} hook has the ability to
+decide whether the transaction can complete, or must be rolled back.
+If the \hook{pretxncommit} hook exits with a status code of zero, the
+transaction is allowed to complete; the commit finishes; and the
+\hook{commit} hook is run.  If the \hook{pretxncommit} hook exits with
+a non-zero status code, the transaction is rolled back; the metadata
+representing the changeset is erased; and the \hook{commit} hook is
+not run.
+  \interaction{hook.simple.pretxncommit}
+  \caption{Using the \hook{pretxncommit} hook to control commits}
+  \label{ex:hook:pretxncommit}
+The hook in example~\ref{ex:hook:pretxncommit} checks that a commit
+comment contains a bug ID.  If it does, the commit can complete.  If
+not, the commit is rolled back.
+\section{Choosing how to write a hook}
+You can write a hook either as a normal program---typically a shell
+script---or as a Python function that is called within the Mercurial
+Writing a hook as an external program has the advantage that it
+requires no knowledge of Mercurial's internals.  You can call normal
+Mercurial commands to get any added information you need.  The
+trade-off is that external hooks are slower than in-process hooks.
+An in-process Python hook has complete access to the Mercurial API,
+and does not ``shell out'' to another process, so it is inherently
+faster than an external hook.  It is also easier to obtain much of the
+information that a hook requires by using the Mercurial API than by
+running Mercurial commands.
+If you are comfortable with Python, or require high performance,
+writing your hooks in Python may be a good choice.  However, when you
+have a straightforward hook to write and you don't need to care about
+performance (probably the majority of hooks), a shell script is
+perfectly fine.
+\section{Hook parameters}
+Mercurial calls each hook with a set of well-defined parameters.  In
+Python, a parameter is passed as a keyword argument to your hook
+function.  For an external program, a parameter is passed as an
+environment variable.
+Whether your hook is written in Python or as a shell script, the
+parameter names and values will be the same.  A boolean parameter will
+be represented as a boolean value in Python, but as the number 1 (for
+``true'') or 0 (for ``false'')
+%%% Local Variables: 
+%%% mode: latex
+%%% TeX-master: "00book"
+%%% End: