Bryan O'Sullivan committed 9fd0c59

Add to hook chapter.
Document each macro in 99defs.tex.

Comments (0)

Files changed (2)

+% Bug ID.
 \newcommand{\bug}[1]{\index{Mercurial issue!no.~#1}\href{}{Mercurial issue no.~#1}}
+% File name in the user's home directory.
+% File name.
+% Directory name.
+% File name, with index entry.
+% The ``s'' prefix comes from ``special''.
 \newcommand{\sfilename}[1]{\index{\texttt{#1} file}\texttt{#1}}
+% Directory name, with index entry.
 \newcommand{\sdirname}[1]{\index{\texttt{#1} directory}\texttt{#1}}
+% Mercurial extension.
 \newcommand{\hgext}[1]{\index{\texttt{#1} extension}\texttt{#1}}
+% Mercurial command.
 \newcommand{\hgcmd}[1]{\index{\texttt{#1} command}``\texttt{hg #1}''}
+% Mercurial command, with arguments.
+\newcommand{\hgcmdargs}[2]{\index{\texttt{#1} command}``\texttt{hg #1 #2}''}
+% Shell/system command.
 \newcommand{\command}[1]{\index{\texttt{#1} command}\texttt{#1}}
+% Shell/system command, with arguments.
 \newcommand{\cmdargs}[2]{\index{\texttt{#1} command}``\texttt{#1 #2}''}
-\newcommand{\hgcmdargs}[2]{\index{\texttt{#1} command}``\texttt{hg #1 #2}''}
+% Mercurial command option.
 \newcommand{\hgopt}[2]{\index{\texttt{#1} command!\texttt{#2} option}\texttt{#2}}
+% Mercurial global option.
+\newcommand{\hggopt}[1]{\index{global options!\texttt{#1} option}\texttt{#1}}
+% Shell/system command option.
 \newcommand{\cmdopt}[2]{\index{\texttt{#1} command!\texttt{#2} option}\texttt{#2}}
+% Command option.
+% Software package.
 \newcommand{\package}[1]{\index{\texttt{#1} package}\texttt{#1}}
+% Section name from a hgrc file.
 \newcommand{\rcsection}[1]{\index{\texttt{hgrc} file!\texttt{#1} section}\texttt{[#1]}}
+% Named item in a hgrc file section.
 \newcommand{\rcitem}[2]{\index{\texttt{hgrc} file!\texttt{#1}
     section!\texttt{#2} entry}\texttt{#1.#2}}
+% hgrc file.
 \newcommand{\hgrc}{\index{\texttt{hgrc} file}\texttt{hgrc}}
+% Hook name.
 \newcommand{\hook}[1]{\index{\texttt{#1} hook}\index{hooks!\texttt{#1}}\texttt{#1}}
+% Environment variable.
 \newcommand{\envar}[1]{\index{\texttt{#1} environment
     variable}\index{environment variables!\texttt{#1}}\texttt{#1}}
+% Python module.
+\newcommand{\pymod}[1]{\index{\texttt{#1} module}\texttt{#1}}
+% Python class in a module.
+\newcommand{\pymodclass}[2]{\index{\texttt{#1} module!\texttt{#2}
+    class}\texttt{#1.#2}}
+% Note: blah blah.
+% Code sample, eating 4 characters of leading space.
+% Code sample, eating 2 characters of leading space.
+% Interaction from the examples directory.
+% Graphics inclusion.
 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}
+\section{Writing your own hooks}
+When you are writing a hook, you might find it useful to run Mercurial
+either with the \hggopt{-v} option, or the \rcitem{ui}{verbose} config
+item set to ``true''.  When you do so, Mercurial will print a message
+before it calls each hook.
+\subsection{Choosing how your hook should run}
 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
+script---or as a Python function that is executed within the Mercurial
 Writing a hook as an external program has the advantage that it
 performance (probably the majority of hooks), a shell script is
 perfectly fine.
-\section{Hook parameters}
+\subsection{Hook parameters}
 Mercurial calls each hook with a set of well-defined parameters.  In
 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'')
+hook-specific 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'') as an environment
+variable for an external hook.  If a hook parameter is named
+\texttt{foo}, the keyword argument for a Python hook will also be
+named \texttt{foo} Python, while the environment variable for an
+external hook will be named \texttt{HG\_FOO}.
+\subsection{Hook return values and activity control}
+A hook that executes successfully must exit with a status of zero if
+external, or return boolean ``false'' if in-process.  Failure is
+indicated with a non-zero exit status from an external hook, or an
+in-process hook returning boolean ``true''.  If an in-process hook
+raises an exception, the hook is considered to have failed.
+For a hook that controls whether an activity can proceed, zero/false
+means ``allow'', while non-zero/true/exception means ``deny''.
+\subsection{Writing an external hook}
+When you define an external hook in your \hgrc\ and the hook is run,
+its value is passed to your shell, which interprets it.  This means
+that you can use normal shell constructs in the body of the hook.
+An executable hook is always run with its current directory set to a
+repository's root directory.
+Each hook parameter is passed in as an environment variable; the name
+is upper-cased, and prefixed with the string ``\texttt{HG\_}''.
+With the exception of hook parameters, Mercurial does not set or
+modify any environment variables when running a hook.  This is useful
+to remember if you are writing a site-wide hook that may be run by a
+number of different users with differing environment variables set.
+In multi-user situations, you should not rely on environment variables
+being set to the values you have in your environment when testing the
+\subsection{Telling Mercurial to use an in-process hook}
+The \hgrc\ syntax for defining an in-process hook is slightly
+different than for an executable hook.  The value of the hook must
+start with the text ``\texttt{python:}'', and continue with the
+fully-qualified name of a callable object to use as the hook's value.
+The module in which a hook lives is automatically imported when a hook
+is run.  So long as you have the module name and \envar{PYTHONPATH}
+right, it should ``just work''.
+The following \hgrc\ example snippet illustrates the syntax and
+meaning of the notions we just described.
+  [hooks]
+  commit.example = python:mymodule.submodule.myhook
+When Mercurial runs the \texttt{commit.example} hook, it imports
+\texttt{mymodule.submodule}, looks for the callable object named
+\texttt{myhook}, and calls it.
+\subsection{Writing an in-process hook}
+The simplest in-process hook does nothing, but illustrates the basic
+shape of the hook API:
+  def myhook(ui, repo, **kwargs):
+      pass
+The first argument to a Python hook is always a
+\pymodclass{mercurial.ui}{ui} object.  The second is a repository object;
+at the moment, it is always an instance of
+\pymodclass{mercurial.localrepo}{localrepository}.  Following these two
+arguments are other keyword arguments.  Which ones are passed in
+depends on the hook being called, but a hook can ignore arguments it
+doesn't care about by dropping them into a keyword argument dict, as
+with \texttt{**kwargs} above.
 %%% Local Variables: