# HG changeset patch # User Bryan O'Sullivan # Date 1153119661 25200 # Node ID 9fd0c59b009af860585a846fd935d51b7cdd8bb7 # Parent 5cee64874312f4f85d45f4ebe2b0de8ea9550a43 Add to hook chapter. Document each macro in 99defs.tex. diff -r 5cee64874312 -r 9fd0c59b009a en/99defs.tex --- a/en/99defs.tex Mon Jul 17 00:00:12 2006 -0700 +++ b/en/99defs.tex Mon Jul 17 00:01:01 2006 -0700 @@ -1,34 +1,92 @@ +% Bug ID. \newcommand{\bug}[1]{\index{Mercurial issue!no.~#1}\href{http://www.selenic.com/mercurial/bts/issue#1}{Mercurial issue no.~#1}} + +% File name in the user's home directory. \newcommand{\tildefile}[1]{\texttt{\~{}/#1}} + +% File name. \newcommand{\filename}[1]{\texttt{#1}} + +% Directory name. \newcommand{\dirname}[1]{\texttt{#1}} + +% 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. \newcommand{\option}[1]{\texttt{#1}} + +% 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. \newsavebox{\notebox} \newenvironment{note}% {\begin{lrbox}{\notebox}\begin{minipage}{0.7\textwidth}\textbf{Note:}\space}% {\end{minipage}\end{lrbox}\fbox{\usebox{\notebox}}} +% Code sample, eating 4 characters of leading space. \DefineVerbatimEnvironment{codesample4}{Verbatim}{frame=single,gobble=4,numbers=left,commandchars=\\\{\}} + +% Code sample, eating 2 characters of leading space. +\DefineVerbatimEnvironment{codesample2}{Verbatim}{frame=single,gobble=2,numbers=left,commandchars=\\\{\}} + +% Interaction from the examples directory. \newcommand{\interaction}[1]{\VerbatimInput[frame=single,numbers=left,commandchars=\\\{\}]{examples/#1.out}} +% Graphics inclusion. \ifpdf \newcommand{\grafix}[1]{\includegraphics{#1}} \else diff -r 5cee64874312 -r 9fd0c59b009a en/hook.tex --- a/en/hook.tex Mon Jul 17 00:00:12 2006 -0700 +++ b/en/hook.tex Mon Jul 17 00:01:01 2006 -0700 @@ -95,11 +95,18 @@ 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} -\label{sec:hook:impl} +\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} +\label{sec:hook:lang} 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 process. Writing a hook as an external program has the advantage that it @@ -119,7 +126,7 @@ performance (probably the majority of hooks), a shell script is perfectly fine. -\section{Hook parameters} +\subsection{Hook parameters} \label{sec:hook:param} Mercurial calls each hook with a set of well-defined parameters. In @@ -128,9 +135,82 @@ 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 +hook. + +\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. +\begin{codesample2} + [hooks] + commit.example = python:mymodule.submodule.myhook +\end{codesample2} +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: +\begin{codesample2} + def myhook(ui, repo, **kwargs): + pass +\end{codesample2} +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: