view es/hook.tex @ 565:e0da346e4681

translated up to the "integration with bugzilla" section
author Javier Rojas <jerojasro@devnull.li>
date Wed, 24 Dec 2008 12:40:20 -0500
parents aa6036a9688e
children 616656741ba7
line wrap: on
line source

\chapter{Manejo de eventos en repositorios mediante ganchos}
\label{chap:hook}

Mercurial ofrece un poderoso mecanismo para permitirle a usted
automatizar la ejecución de acciones en respuesta a eventos que
ocurran en un repositorio. En algunos casos, usted puede controlar
incluso la respuesta de Mercurial a dichos eventos.

Mercurial usa el término \emph{gancho} para identificar estas
acciones. Los ganchos son conocidos como ``disparadores'' en algunos
sistemas de control de revisiones, pero los dos nombres se refieren al
mismo concepto.

\section{Vistazo general de ganchos en Mercurial}

A continuación se encuentra una breve lista de los ganchos que
Mercurial soporta. Volveremos a cada uno de estos ganchos con más
detalle después, en la sección~\ref{sec:hook:ref}.

\begin{itemize}
\item[\small\hook{changegroup}] Es ejecutado luego de que un grupo de
    conjuntos de cambios ha sido traído al repositorio desde algún
    otro sitio.
\item[\small\hook{commit}] Es ejecutado después de la creación de
    un conjunto de cambios en el repositorio local.
\item[\small\hook{incoming}] Es ejecutado una vez por cada conjunto de
    cambios traído al repositorio desde otra ubicación. Note la
    diferencia respecto al gancho \hook{changegroup}, que es ejecutado
    una vez por cada \emph{grupo} de conjuntos de cambios que se
    traiga.
\item[\small\hook{outgoing}] Es ejecutado luego de que un grupo de
    conjuntos de cambios ha sido transmitido desde el repositorio.
\item[\small\hook{prechangegroup}] Es ejecutado antes de iniciar la
    recepción de un grupo de conjuntos de cambios en el repositorio.
\item[\small\hook{precommit}] De control. Es ejecutado antes de
    iniciar una consignación.
\item[\small\hook{preoutgoing}] De control. Es ejecutado antes de
    iniciar la transmisión de un grupo de conjuntos de cambios desde
    el repositorio.
\item[\small\hook{pretag}] De control. Es ejecutado antes de crear una
    etiqueta.
\item[\small\hook{pretxnchangegroup}] De control. Es ejecutado después
    de haber recibido un grupo de conjuntos de cambios en el
    repositorio local, pero antes de que la transacción se complete y
    los cambios sean permanentes dentro del repositorio.
\item[\small\hook{pretxncommit}] De control. Es ejecutado luego de la
    creación de un conjunto de cambios en el repositorio local, pero
    antes de que la transacción que hace permanente el cambio sea
    completada.
\item[\small\hook{preupdate}] De control. Es ejecutado antes de
    iniciar una actualización o fusión en el directorio de trabajo.
\item[\small\hook{tag}] Es ejecutado después de la creación de una
    etiqueta.
\item[\small\hook{update}] Es ejecutado después de que termina una
    actualización o una fusión.
\end{itemize}
Cada uno de los ganchos cuya descripción empieza con la frase
``de control'' tiene la facultad de determinar si una actividad puede
continuar. Si el gancho se ejecuta con éxito, la actividad puede
continuar; si falla, o bien la actividad no es permitida, o se
deshacen los cambios que se puedan haber llevado a cabo, dependiendo
del gancho involucrado.

\section{Ganchos y seguridad}

\subsection{Los ganchos se ejecutan con sus privilegios de usuario}

Cuando usted ejecuta un comando de Mercurial en un repositorio, y el
comando causa la ejecución de un gancho, dicho gancho se ejecuta en
\emph{su} sistema, en \emph{su} cuenta de usuario, con \emph{sus}
privilegios. Ya que los ganchos son elementos arbitrarios de código
ejecutable, usted debería tratarlos con un nivel adecuado de
desconfianza. No instale un gancho a menos en que confíe en quien lo
creó y en lo que el gancho hace.

En algunos casos, usted puede estar expuesto a ganchos que usted no
%TODO acá introduzco algo de texto por mi cuenta, por claridad
instaló. Si usted usa Mercurial en un sistema extraño, tenga en cuenta
que Mercurial ejecutará los ganchos definidos en el fichero \hgrc.

Si está trabajando con un repositorio propiedad de otro usuario,
Mercurial podrá ejecutar los ganchos definidos en el repositorio de
dicho usuario, pero los ejecutará como ``usted''. Por ejemplo, si
usted jala (\hgcmd{pull}) desde ese repositorio, y el
\sfilename{.hg/hgrc} define un gancho saliente (\hook{outgoing}),
dicho gancho se ejecuta bajo su cuenta de usuario, aun cuando usted no
es el propietario del repositorio.

\begin{note}
  Esto sólo aplica si usted está jalando desde un repositorio en un
  sistema de ficheros local o de red. Si está jalando a través de http
  o ssh, cualquier gancho saliente (\hook{outgoing}) se ejecutará bajo
  la cuenta que está ejecutando el proceso servidor, en el servidor.
\end{note}

XXX Para ver qué ganchos han sido definidos en un repositorio, use el
comando \hgcmdargs{config}{hooks}. Si usted está trabajando en un
repositorio, pero comunicándose con otro que no le pertenece
(por ejemplo, usando \hgcmd{pull} o \hgcmd{incoming}), recuerde que
los ganchos que debe considerar son los del otro repositorio, no los
del suyo.

\subsection{Los ganchos no se propagan}

En Mercurial, no se hace control de revisiones de los ganchos, y no se
propagan cuando usted clona, o jala de, un repositorio. El motivo para
esto es simple: un gancho es código ejecutable arbitrario. Se ejecuta
bajo su identidad, con su nivel de privilegios, en su máquina.

Sería extremadamente descuidado de parte de cualquier sistema
distribuido de control de revisiones el implementar control de
revisiones para ganchos, ya que esto ofrecería maneras fácilmente
%TODO subvertir
aprovechables de subvertir las cuentas de los usuarios del sistema de
control de revisiones.

Ya que Mercurial no propaga los ganchos, si usted está colaborando con
otras personas en un proyecto común, no debería asumir que ellos están
usando los mismos ganchos para Mercurial que usted usa, o que los de
ellos están configurado correctamente. Usted debería documentar los
ganchos que usted espera que la gente use.

En una intranet corporativa, esto es algo más fácil de manejar, ya que
usted puede, por ejemplo, proveer una instalación ``estándar'' de
Mercurial en un sistema de ficheros NFS, y usar un fichero \hgrc\
global para definir los ganchos que verán todos los usuarios. Sin
embargo, este enfoque tiene sus límites; vea más abajo.

\subsection{Es posible hacer caso omiso de los ganchos}

Mercurial le permite hacer caso omiso de la deficinión de un gancho,
a través de la redefinición del mismo. Usted puede deshabilitar el
gancho fijando su valor como una cadena vacía, o cambiar su
comportamiento como desee.

Si usted instala un fichero \hgrc\ a nivel de sistema o sitio completo
que define algunos ganchos, debe entender que sus usuarios pueden
deshabilitar o hacer caso omiso de los mismos.

\subsection{Asegurarse de que ganchos críticos sean ejecutados}

Algunas veces usted puede querer hacer respetar una política, y no
permitir que los demás sean capaces de evitarla. Por ejemplo, usted
puede tener como requerimiento que cada conjunto de cambios debe pasar
un riguroso conjunto de pruebas. Definir este requerimientos a través
de un gancho en un fichero \hgrc\ global no servirá con usuarios
remotos en computadoras portátiles, y por supuesto que los usuarios
locales pueden evitar esto a voluntad haciendo caso omiso del gancho.

En vez de eso, usted puede definir las políticas para usar Mercurial
de tal forma que se espere que los usuarios propaguen los cambios a
través de un servidor ``canónico'' bien conocido que usted ha
asegurado y configurado apropiadamente.

Una manera de hacer esto es a través de una combinación de ingeniería
socual y tecnología. Cree una cuenta de acceso restringido; los
usuarios pueden empujar cambios a través de la red a los repositorios
administrados por esta cuenta, pero no podrán ingresar a dicha cuenta
para ejecutar órdenes en el intérprete de comandos. En este escenario,
un usuario puede enviar un conjunto de cambios que contenga la
porquería que él desee.

Cuando alguien empuja un conjunto de cambios al servidor del que todos
jalan, el servidor probará el conjunto de cambios antes de aceptarlo
como permanente, y lo rechazará si no logra pasar el conjunto de
pruebas. Si la gente sólo jala cambios desde este servidor de filtro,
servirá para asegurarse de que todos los cambios que la gente jala han
sido examinados automáticamente

\section{Precauciones con ganchos \texttt{pretxn} en un repositorio de
acceso compartido}

Si usted desea usar ganchos para llevar a cabo automáticamente algún
trabajo en un repositorio al que varias personas tienen acceso
compartido, debe tener cuidado con la forma de hacerlo.

Mercurial sólo bloquea un repositorio cuando está escribiendo al
mismo, y sólo las partes de Mercurial que escriben al repositorio le
prestan atención a los bloqueos. Los bloqueos de escritura son
necesarios para evitar que múltiples escritores simultáneos
interfieran entre sí, corrompiendo el repositorio.

Ya que Mercurial tiene cuidado con el orden en que lee y escribe
datos, no necesita adquirir un bloqueo cuando desea leer datos del
repositorio. Las partes de Mercurial que leen del repositorio nunca le
prestan atención a los bloqueos. Este esquema de lectura libre de
bloqueos incremententa en gran medida el desempeño y la concurrencia.

Sin embargo, para tener un gran desempeño es necesario hacer
sacrificios, uno de los cuales tiene el potencial de causarle
problemas a menos de que usted esté consciente de él. Describirlo
requiere algo de detalle respecto a cómo Mercurial añade conjuntos de
cambios al repositorio y cómo lee esos cambios de vuelta.

Cuando Mercurial \emph{escribe} metadatos, los escribe directamente en
el fichero de destino. Primero escribe los datos del fichero, luego
los datos del manifiesto (que contienen punteros a los nuevos datos
del fichero), luego datos de la bitácora de cambios (que contienen
punteros a los nuevos datos del manifiesto). Antes de la primera
escritura a cada fichero, se guarda un registro de dónde estaba el
final de fichero en su registro de transacciones. Si la transacción
debe ser deshecha, Mercurial simplemente trunca cada fichero de vuelta
al tamaño que tenía antes de que empezara la transacción.

Cuando Mercurial \emph{lee} metadatos, lee la bitácora de cambios
primero, y luego todo lo demás. Como un lector sólo accederá a las
partes del manifiesto o de los metadatos de fichero que él puede ver
en la bitácora de cambios, nunca puede ver datos parcialmente
escritos.

Algunos ganchos de control (\hook{pretxncommit} y
\hook{pretxnchangegroup}) se ejecutan cuando una transacción está casi
completa. Todos los metadatos han sido escritos, pero Mercurial aún
puede deshacer la transacción y hacer que los datos recién escritos
desaparezcan.

Si alguno de estos ganchos permanece en ejecución por mucho tiempo,
abre una ventana de tiempo en la que un lector puede ver los metadatos
de conjuntos de cambios que aún no son permanentes y que no debería
considerarse que estén ``realmante ahí''. Entre más tiempo tome la
ejecución del gancho, más tiempo estará abierta esta ventana.

\subsection{Ilustración del problema}

En principio, un buen uso del gancho \hook{pretxnchangegroup} sería
ensamblar y probar automáticamente todos los cambios entrantes antes
de que sean aceptados en un repositorio central. Esto le permitiría a
usted garantizar que nadie pueda empujar cambios que ``rompan el
ensamblaje''. Pero si un cliente puede jalar cambios mientras están
siendo probados, la utilidad de esta prueba es nula; alguien confiado
puede jalar cambios sin probar, lo que potencialmente podría romper su
proceso de ensamblaje.

La respuesta técnica más segura frente a este retos es montar dicho
repositorio ``guardián'' como \emph{unidireccional}. Permita que
reciba cambios desde el exterior, pero no permita que nadie jale
cambios de él (use el gancho \hook{preoutgoing} para bloquear esto).
Configure un gancho \hook{changegroup} para que si el ensamblaje o
prueba tiene éxito, el gancho empuje los nuevos cambios a otro
repositorio del que la gente \emph{pueda} jalar.

En la práctica, montar un cuello de botella centralizado como éste a
menudo no es una buena idea, y la visibilidad de las transacciones no
tiene nada que ver con el problema. A medida que el tamaño de un
proyecto---y el tiempo que toma ensamblarlo y probarlo---crece, usted
se acerca rápidamente a un límite con este enfoque ``pruebe antes de
comprar'', en el que tiene más conjuntos de cambios a probar que
tiempo para ocuparse de ellos. El resultado inevitable es frustración
para todos los que estén involucrados.

Una aproximación que permite manejar mejor el crecimiento es hacer que
la gente ensamble y pruebe antes de empujar, y ejecutar el ensamble y
pruebas automáticas centralmente \emph{después} de empujar, para
asegurarse de que todo esté bien. La ventaja de este enfoque es que no
impone un límite a la rata en la que un repositorio puede aceptar
cambios.

\section{Tutorial corto de uso de ganchos}
\label{sec:hook:simple}

Escribir un gancho para Mercurial es fácil. Empecemos con un gancho
que se ejecute cuando usted termine un \hgcmd{commit}, y simplemente
muestre el hash del conjunto de cambios que usted acaba de crear. El
gancho se llamará \hook{commit}.

\begin{figure}[ht]
  \interaction{hook.simple.init}
  \caption{Un gancho simple que se ejecuta al hacer la consignación de
  un conjunto de cambios}
  \label{ex:hook:init}
\end{figure}

Todos los ganchos siguen el patrón del ejemplo~\ref{ex:hook:init}.
Usted puede añadir una entrada a la sección \rcsection{hooks} de su
fichero \hgrc.  A la izquierda está el nombre del evento respecto al
cual dispararse; a la derecha está la acción a llevar a cabo. Como
puede ver, es posible ejecutar cualquier orden de la línea de comandos
en un gancho. Mercurial le pasa información extra al gancho usando
variables de entorno (busque \envar{HG\_NODE} en el ejemplo).

\subsection{Llevar a cabo varias acciones por evento}

A menudo, usted querrá definir más de un gancho para un tipo de evento
particular, como se muestra en el ejemplo~\ref{ex:hook:ext}. 
Mercurial le permite hacer esto añadiendo una \emph{extensión} al
final del nombre de un gancho. Usted extiende el nombre del gancho
%TODO Yuk, no me gusta ese "parada completa"
poniendo el nombre del gancho, seguido por una parada completa (el
caracter ``\texttt{.}''), seguido de algo más de texto de su elección.
Por ejemplo, Mercurial ejecutará tanto \texttt{commit.foo} como
\texttt{commit.bar} cuando ocurra el evento \texttt{commit}.

\begin{figure}[ht]
  \interaction{hook.simple.ext}
  \caption{Definición de un segundo gancho \hook{commit}}
  \label{ex:hook:ext}
\end{figure}

Para dar un orden bien definido de ejecución cuando hay múltiples
ganchos definidos para un evento, Mercurial ordena los ganchos de
acuerdo a su extensión, y los ejecuta en dicho orden. En el ejemplo de
arribam \texttt{commit.bar} se ejecutará antes que
\texttt{commit.foo}, y \texttt{commit} se ejecutará antes de ambos.

Es una buena idea usar una extensión descriptiva cuando usted define
un gancho. Esto le ayudará a recordar para qué se usa el gancho. Si el
gancho falla, usted recibirá un mensaje de error que contiene el
nombre y la extensión del gancho, así que usar una extensión
descriptiva le dará una pista inmediata de porqué el gancho falló (vea
un ejemplo en la sección~\ref{sec:hook:perm}).

\subsection{Controlar cuándo puede llevarse a cabo una actividad}
\label{sec:hook:perm}

En los ejemplos anteriores, usamos el gancho \hook{commit}, que es
ejecutado después de que se ha completado una consignación. Este es
uno de los varios ganchos que Mercurial ejecuta luego de que una
actividad termina. Tales ganchos no tienen forma de influenciar la
actividad como tal.

Mercurial define un número de eventos que ocurren antes de que una
actividad empiece; o luego de que empiece, pero antes de que termine.
Los ganchos que se disparan con estos eventos tienen la capacidad
adicional de elegir si la actividad puede continuar, o si su ejecución
es abortada.

El gancho \hook{pretxncommit} se ejecuta justo antes de que una
consignación se ejecute. En otras palabras, los metadatos que
representan el conjunto de cambios han sido escritos al disco, pero no
se ha terminado la transacción. El gancho \hook{pretxncommit} tiene la
capacidad de decidir si una transacción se completa, o debe
deshacerse.

Si el gancho \hook{pretxncommit} termina con un código de salida de
cero, se permite que la transacción se complete; la consignación
termina; y el gancho \hook{commit} es ejecutado. Si el gancho
\hook{pretxncommit} termina con un código de salida diferente de cero,
la transacción es revertida; los metadatos representando el conjunto
de cambios son borrados; y el gancho \hook{commit} no es ejecutado.

\begin{figure}[ht]
  \interaction{hook.simple.pretxncommit}
  \caption{Uso del gancho \hook{pretxncommit} hook to control commits}
  \label{ex:hook:pretxncommit}
\end{figure}

El gancho en el ejemplo~\ref{ex:hook:pretxncommit} revisa si el
mensaje de consignación contiene el ID de algún fallo. Si lo contiene,
la consignación puede continuar. Si no, la consignación es cancelada.

\section{Escribir sus propios ganchos}

Cuando usted escriba un gancho, puede encontrar útil el ejecutar
Mercurial o bien pasándole la opción \hggopt{-v}, o con el valor de
configuración \rcitem{ui}{verbose} fijado en ``true'' (verdadero).
Cuando lo haga, Mercurial imprimirá un mensaje antes de llamar cada
gancho.

\subsection{Escoger cómo debe ejecutarse su gancho}
\label{sec:hook:lang}

Usted puede escribir un gancho que funcione como un programa normal
---típicamente un guión de línea de comandos---o como una función de
Python que se ejecuta dentro del proceso Mercurial.

Escribir un gancho como un programa externo tiene la ventaja de que no
requiere ningún conocimiento del funcionamiento interno de Mercurial.
Usted puede ejecutar comandos Mercurial normales para obtener la
informción extra que pueda necesitar. La contraparte de esto es que
los ganchos externos son más lentos que los ganchos internos
ejecutados dentro del proceso.

Un gancho Python interno tiene acceso completo a la API de Mercurial,
y no se ``externaliza'' a otro proceso, así que es inherentemente más
rápido que un gancho externo. Adicionalmente es más fácil obtener la
mayoría de la información que un gancho requiere a través de llamadas
directas a la API de Mercurial que hacerlo ejecutando comandos
Mercurial.

Si se siente a gusto con Python, o requiere un alto desempeño,
escribir sus ganchos en Python puede ser una buena elección. Sin
embargo, cuando usted tiene un gancho bastante directo por escribir y
no le importa el desempeño (el caso de la mayoría de los ganchos), es
perfectamente admisible un guión de línea de comandos.

\subsection{Parámetros para ganchos}
\label{sec:hook:param}

Mercurial llama cada gancho con un conjunto de paŕametros bien
definidos. En Python, un parámetro se pasa como argumento de palabra
clave a su función de gancho. Para un programa externo, los parámetros
son pasados como variables de entornos.

Sin importar si su gancho está escrito en Python o como guión de línea
de comandos, los nombres y valores de los parámetros específicos de
los ganchos serán los mismos. Un parámetro booleano será representado
como un valor booleano en Python, pero como el número 1 (para
``verdadero'') o 0 (para falso) en una variable de entorno para un
gancho externo. Si un parámetro se llama \texttt{foo}, el argumento de
palabra clave para un gancho en Python también se llamará
\texttt{foo}, mientras que la variable de entorno para un gancho
externo se llamará \texttt{HG\_FOO}.

\subsection{Valores de retorno de ganchos y control de actividades}

Un gancho que se ejecuta exitosamente debe terminar con un código de
salida de cero, si es externo, o retornar el valor booleano
``falso'', si es interno. Un fallo se indica con un código de salida
diferente de cero desde un gancho externo, o un valor de retorno
booleano ``verdadero''. Si un gancho interno genera una excepción, se
considera que el gancho ha fallado.

Para los ganchos que controlan si una actividad puede continuar o no,
cero/falso quiere decir ``permitir'', mientras que
% TODO me suena mejor "no permitir" que "denegar"
no-cero/verdadero/excepción quiere decir ``no permitir''.

\subsection{Escribir un gancho externo}

Cuando usted define un gancho externo en su fichero \hgrc\ y el mismo
es ejecutado, dicha definición pasa a su intérprete de comandos, que
hace la interpretación correspondiente. Esto significa que usted puede
usar elementos normales del intérprete en el cuerpo del gancho.

Un gancho ejecutable siempre es ejecutado con su directorio actual
fijado al directorio raíz del repositorio.

Cada parámetro para el gancho es pasado como una variable de entorno;
el nombre está en mayúsculas, y tiene como prefijo la cadena
``\texttt{HG\_}''.

Con la excepción de los parámetros para los ganchos, Mercurial no
define o modifica ninguna variable de entorno al ejecutar un gancho.
Es útil recordar esto al escribir un gancho global que podría ser
ejecutado por varios usuarios con distintas variables de entorno
fijadas. En situaciones con múltiples usuarios, usted no debería
asumir la existencia de ninguna variable de entorno, ni que sus
valores sean los mismos que tenían cuando usted probó el gancho en su
ambiente de trabajo.

\subsection{Indicar a Mercurial que use un gancho interno}

La sintaxis para definir un gancho interno en el fichero \hgrc\ es
ligeramente diferente de la usada para un gancho externo. El valor del
gancho debe comenzar con el texto ``\texttt{python:}'', y continuar
con el nombre completamente cualificado de un objeto invocable que se
usará como el valor del gancho.

El módulo en que vive un gancho es importado automáticamente cuando se
ejecuta un gancho. Siempre que usted tenga el nombre del módulo y la
variable de entorno \envar{PYTHONPATH} ajustada adecuadamente, todo
debería funcionar sin problemas.

El siguiente fragmento de ejemplo de un fichero \hgrc\ ilustra la
sintaxis y significado de los conceptos que acabamos de describir.
\begin{codesample2}
  [hooks]
  commit.example = python:mymodule.submodule.myhook
\end{codesample2}
Cuando Mercurial ejecuta el gancho \texttt{commit.example}, importa 
\texttt{mymodule.submodule}, busca el objeto invocable llamado
\texttt{myhook}, y lo invoca (llama).

\subsection{Escribir un gancho interno}

El gancho interno más sencillo no hace nada, pero ilustra la
estructura básica de la API\footnote{\emph{Application Progamming
Interface}, Interfaz para Programación de Aplicaciones} para ganchos:
\begin{codesample2}
  def myhook(ui, repo, **kwargs):
      pass
\end{codesample2}
El primer argumento para un gancho Python siempre es un objeto
\pymodclass{mercurial.ui}{ui}.  El segundo es un objeto repositorio;
de momento, siempre es una instancia de 
\pymodclass{mercurial.localrepo}{localrepository}.  Después de estos
dos argumentos están los argumentos de palabra clave. Los argumentos
que se pasen dependerán del tipo de gancho que se esté llamando, pero
un gancho siempre puede ignorar los argumentos que no le interesen,
relegándolos a un diccionario de argumentos por palabras clave, como se
hizo arriba con \texttt{**kwargs}.

\section{Ejemplos de ganchos}

\subsection{Escribir mensajes de consignación significativos}

Es difícil de imaginar un mensaje de consignación útil y al mismo
tiempo muy corto. El simple gancho \hook{pretxncommit} de la
figura~\ref{ex:hook:msglen.go} evitará que usted consigne un conjunto
de cambios con un mensaje de menos de 10 bytes de longitud.

\begin{figure}[ht]
  \interaction{hook.msglen.go}
  \caption{Un gancho que prohíbe mensajes de consignación demasiado
  cortos}
  \label{ex:hook:msglen.go}
\end{figure}

\subsection{Comprobar espacios en blanco finales}

Un uso interesante para ganchos relacionados con consignaciones es
ayudarle a escribir código más limpio. Un ejemplo simple de
%TODO dictum => regla
``código más limpio'' es la regla de que un cambio no debe añadir
líneas de texto que contengan ``espacios en blanco finales''. El
espacio en blanco final es una serie de caracteres de espacio y
tabulación que se encuentran al final de una línea de texto. En la
mayoría de los casos, el espacio en blanco final es innecesario, ruido
invisible, pero ocasionalmente es problemático, y la gente en general
prefiere deshacerse de él.

Usted puede usar cualquiera de los ganchos \hook{precommit} o
\hook{pretxncommit} para revisar si tiene el problema de los espacios
en blanco finales. Si usa el gancho \hook{precommit}, el gancho no
sabrá qué ficheros se están consignando, por lo que se tendrá que
revisar cada fichero modificado en el repositorio para ver si tiene
espacios en blanco finales. Si usted sólo quiere consignar un cambio
al fichero \filename{foo}, y el fichero \filename{bar} contiene
espacios en blanco finales, hacer la revisión en el gancho
\hook{precommit} evitará que usted haga la consignación de
\filename{foo} debido al problem en \filename{bar}.  Este no parece el
enfoque adeucado.

Si usted escogiera el gancho \hook{pretxncommit}, la revisión no
ocurriría sino hasta justo antes de que la transacción para la
consignación se complete. Esto le permitirá comprobar por posibles
problemas sólo en los ficheros que serán consignados. Sin embargo, si
usted ingresó el mensaje de consignación de manera interactiva y el
%TODO roll-back
gancho falla, la transacción será deshecha; usted tendrá que
reingresar el mensaje de consignación luego de que corrija el problema
con los espacios en blanco finales y ejecute \hgcmd{commit} de nuevo.

\begin{figure}[ht]
  \interaction{hook.ws.simple}
  \caption{Un gancho simple que revisa si hay espacios en blanco
  finales}
  \label{ex:hook:ws.simple}
\end{figure}

La figura~\ref{ex:hook:ws.simple} presenta un gancho
\hook{pretxncommit} simple que comprueba la existencia de espacios en
blanco finales. Este gancho es corto, pero no brinda mucha ayuda.
Termina con un código de salida de error si un cambio añade una línea
con espacio en blanco final a cualquier fichero, pero no muestra
ninguna información que pueda ser útil para identificar el fichero o
la línea de texto origen del problema. También tiene la agradable
propiedad de no prestar atención a las líneas que no sufrieron
modificaciones; sólo las líneas que introducen nuevos espacios en
blanco finales causan problemas.

\begin{figure}[ht]
  \interaction{hook.ws.better}
  \caption{A better trailing whitespace hook}
  \label{ex:hook:ws.better}
\end{figure}

El ejemplo de la figura~\ref{ex:hook:ws.better} es mucho más complejo,
pero también más útil. El gancho procesa un diff unificado para
revisar si alguna línea añade espacios en blanco finales, e imprime el
nombre del fichero y el número de línea de cada ocurrencia. Aún mejor,
si el cambio añade espacios en blanco finales, este gancho guarda el
mensaje de consignación e imprime el nombre del fichero en el que el
mensaje fue guardado, antes de terminar e indicarle a Mercurial que
deshaga la transacción, para que uste pueda usar
\hgcmdargs{commit}{\hgopt{commit}{-l}~\emph{nombre\_fichero}} para
reutilizar el mensaje de consignación guardado anteriormente, una vez
usted haya corregido el problema.

Como anotación final, note en la figura~\ref{ex:hook:ws.better} el
%TODO on-site => in-situ ?
uso de la característica de edición \emph{in-situ} de \command{perl}
para eliminar los espacios en blanco finales en un fichero. Esto es
lo suficientemente conciso y poderoso para que lo presente aquí.
% TODO corregí el backslash, y comprobé por mi cuenta un archivo
% aparte, y el comando hace lo que debe hacer. Favor copiar del pdf el
% comando perl y comprobar con un archivo con espacios en blanco
% finales, y si todo está bien (que debería), borrar esta nota
\begin{codesample2}
    perl -pi -e 's,\textbackslash{}s+\$,,' nombre\_fichero
\end{codesample2}

%TODO bundled
\section{Ganchos bundled}

Mercurial se instala con varios ganchos bundled. Usted puede
encontrarlos en el directorio \dirname{hgext} del árbol de ficheros
fuente de Mercurial. Si usted está usando un paquete binario de
Mercurial, los ganchos estarán ubicados en el directorio
\dirname{hgext} en donde su instalador de paquetes haya puesto a
Mercurial.

\subsection{\hgext{acl}---control de acceso a partes de un repositorio}

La extensión \hgext{acl} le permite controlar a qué usuarios remotos
les está permitido empujar conjuntos de cambios a un servidor en red.
Usted puede proteger cualquier porción de un repositorio (incluyendo
el repositorio completo), de tal manera que un usuario remoto
específico pueda empujar cambios que no afecten la porción protegida.

Esta extensión implementa control de acceso basado en la identidad del
usuario que empuja los conjuntos de cambios, \emph{no} en la identidad
de quien hizo la consignación de los mismos. Usar este gancho tiene
sentido sólo si se tiene un servidor adecuadamente asegurado que
autentique a los usuarios remotos, y si usted desea segurarse de que
sólo se le permita a ciertos usuarios empujar cambios a dicho
servidor.

\subsubsection{Configurar el gancho \hook{acl}}

Para administrar los conjuntos de cambios entrantes, se debe usar el
gancho \hgext{acl} como un gancho de tipo \hook{pretxnchangegroup}.
Esto le permite ver qué ficheros son modificados por cada conjunto de
%TODO rollback => "deshacer el efecto"
cambios entrante, y deshacer el efecto de un grupo de conjuntos de
cambios si alguno de ellos modifica algún fichero ``prohibido''.
Ejemplo:
\begin{codesample2}
  [hooks]
  pretxnchangegroup.acl = python:hgext.acl.hook
\end{codesample2}

La extensión \hgext{acl} es configurada mediante tres secciones.

La sección \rcsection{acl} sólo tiene una entrada,
\rcitem{acl}{sources}\footnote{Fuentes.}, que lista las fuentes de los
conjuntos de cambios entrantes a las que el gancho debe prestar
atención. Usualmente usted no necesita configurar esta sección.
\begin{itemize}
  \item[\rcitem{acl}{serve}] Controlar conjuntos de
    cambios entrantes que están llegando desde un repositorio a
    través de http o ssh. Este es el valor por defecto de
  \rcitem{acl}{sources}, y usualmente es el único valor de
  configuración que necesitará para este ítem.
\item[\rcitem{acl}{pull}] Controlar conjuntos de cambios entrantes que
  lleguen vía un pull (jalado) desde un repositorio local.
\item[\rcitem{acl}{push}] Controlar conjuntos de cambios entrantes que
  lleguen vía un push (empuje) desde un repositorio local.
\item[\rcitem{acl}{bundle}] Controlar conjuntos de cambios entrantes
    %TODO bundle
  que lleguen desde otro repositorio a través de un bundle.
\end{itemize}

La sección \rcsection{acl.allow} controla los usuarios a los que les
está permitido añadir conjuntos de cambios al repositorio. Si esta
sección no está presente, se le permite acceso a todos los usuarios
excepto  a los que se les haya negado explícitamente el acceso. Si
esta sección no está presente, se niega el acceso a todos los usuarios
excepto a todos a los que se les haya permitido de manera explícita
(así que una sección vacía implica que se niega el acceso a todos los
usuarios).

La sección \rcsection{acl.deny} determina a qué usuarios no se les
permite añadir conjuntos de cambios al repositorio. Si esta sección no
está presente o está vacía, no se niega el acceso a ningún usuario.

La sintaxis para los ficheros \rcsection{acl.allow} y
\rcsection{acl.deny} es idéntica. A la izquierda de cada entrada se
encuentra un patrón glob que asocia ficheros o directorios, respecto a
la raíz del repositorio; a la derecha, un nombre usuario.

En el siguiente ejemplo, el usuario \texttt{escritordoc} sólo puede
empujar cambios al directorio \dirname{docs} del repositorio, mientras
que \texttt{practicante} puede enviar cambios a cualquier fichero o
directorio excepto \dirname{fuentes/sensitivo}.
\begin{codesample2}
  [acl.allow]
  docs/** = escritordoc

  [acl.deny]
  fuentes/sensitivo/** = practicante
\end{codesample2}

\subsubsection{Pruebas y resolución de problemas}

Si usted desea probar el gancho \hgext{acl}, ejecútelo habilitando la
opción de salida de depuración habilitada. Ya que usted probablemente
lo estará ejecutando en un servidor donde no es conveniente (o incluso
posible) pasar la opción \hggopt{--debug}, no olvide que usted puede
habilitar la salida de depuración en su \hgrc:
\begin{codesample2}
  [ui]
  debug = true
\end{codesample2}
Con esto habilitado, el gancho \hgext{acl} imprimirá suficiente
información para permitirle saber porqué está permitiendo o denegando
la operación de empujar a usuarios específicos.

\subsection{\hgext{bugzilla}---integración con Bugzilla}

La extensión \hgext{bugzilla} añade un comentario a un fallo Bugzilla
siempre que encuentre una referencia al ID de dicho fallo en un
mensaje de consignación. Usted puede instalar este gancho en un
servidor compartido, para que cada vez que un usuario remoto empuje
cambios al servidor, el gancho sea ejecutado.

Se añade un comentario al fallo que se ve así (usted puede configurar
los contenidos del comentario---vea más abajo):
%TODO traducir?
\begin{codesample2}
  Changeset aad8b264143a, made by Joe User <joe.user@domain.com> in
  the frobnitz repository, refers to this bug.

  For complete details, see
  http://hg.domain.com/frobnitz?cmd=changeset;node=aad8b264143a

  Changeset description:
        Fix bug 10483 by guarding against some NULL pointers
\end{codesample2}
El valor de este gancho se encuentra en que automatiza el proceso de
actualizar un fallo cuando un conjunto de cambios se refiera a él. Si
usted configura este gancho adecuadamente, hará fácil para la gente
navegar directamente desde un fallo Bugzilla a un conjunto de cambios
que se refiere a ese fallo.

Usted puede usar el código de este gancho como un punto de partida
para otras recetas de integración con Bugzilla aún más exóticas. Acá
hay algunas posibilidades:
\begin{itemize}
\item Requerir que cada conjunto de cambios tenga un ID de fallo en su
  mensaje de consignación. En este caso, usted querrá configurar el
  gancho como uno de tipo \hook{pretxncommit}.  Esto le permitirá al
  gancho rechazar cambios que no contiene IDs de fallos.
\item Permitir a los conjuntos de cambios entrantes modificar
  automáticamente el \emph{estado} de un fallo, así como simplemente
  añadir un comentario. Por ejemplo, el gancho podría reconocer la
  cadena ``corregido fallo 31337'' como la señal de que debería
  actualizar el estado del fallo 31337 a ``requiere pruebas''.
\end{itemize}

\subsubsection{Configuración del gancho \hook{bugzilla}}
\label{sec:hook:bugzilla:config}

Usted debería configurar este gancho en el \hgrc\ de su servidor como
un gancho \hook{incoming}\footnote{Entrante.}, por ejemplo como sigue:
\begin{codesample2}
  [hooks]
  incoming.bugzilla = python:hgext.bugzilla.hook
\end{codesample2}

Debido a la naturaleza especializada de este gancho, y porque Bugzilla
no fue escrito con este tipo de integración en mente, configurar este
% TODO involved => complejo ? no intarwebs here :(
gancho es un proceso algo complejo.

Antes de empezar, usted debe instalar la interfaz de Python para MySQL
en los sistemas en los que se vaya a ejecutar el gancho. Si no está
disponible como paquete binario para su sistema, usted puede descargar
el paquete desde~\cite{web:mysql-python}.

La información para configurar este gancho se ubica en la sección 
\rcsection{bugzilla} de su \hgrc.
\begin{itemize}
\item[\rcitem{bugzilla}{version}] La versión de Bugzilla instalada en
  el servidor. El esquema de base de datos que Bugzilla usa cambia
  ocasionalmente, así que este gancho debe saber exactamente qué
  esquema usar. A la fecha, la única versión soportada es la
  \texttt{2.16}.
\item[\rcitem{bugzilla}{host}] El nombre de máquina (\emph{hostname})
  del servidor MySQL que almacena sus datos Bugzilla. La base de datos
  debe ser configurada para permitir conexiones desde las máquinas en
  las que usted ejecute el gancho \hook{bugzilla}.
\item[\rcitem{bugzilla}{user}] El nombre de usuario que se usará para
  conectarse al servidor MySQL. La base de datos debe ser configurada
  para permitir a dicho usuario conectarse desde cualquiera de las
  máquinas en las que se ejecute el gancho \hook{bugzilla}.  Este
  usuario debe tener acceso y poder modificar las tablas de Bugzilla.
  El valor por defecto para este ítem es \texttt{bugs}, que es el
  nombre estándar del usuario para Bugzilla en una base de datos
  MySQL.
\item[\rcitem{bugzilla}{password}] La contraseña MySQL para el usuario
  configurado anteriormente. Ésta es almacenada como texto plano, así
  que usted deberá asegurarse de que los usuarios no autorizados no
  puedan leer el fichero \hgrc\ en donde usted guarda esta
  información.
\item[\rcitem{bugzilla}{db}] El nombre de la base de datos Bugzilla en
  el servidor MySQL. El nombre por defecto para este ítem es
  \texttt{bugs}, que es el nombre estándar de la base de datos MySQL
  en donde Bugzilla almacena sus datos.
\item[\rcitem{bugzilla}{notify}] Si usted desea que Bugzilla envíe un
    %TODO suBscriptores?
  correo de notificación a los suscriptores después de que el gancho
  haya añadido un comentario a un fallo, necesitará que este gancho
  ejecute un comando siempre que actualice la base de datos. El
  comando que se ejecute depende de en dónde haya sido instalado
  Bugzilla, pero típicamente se verá así, si usted ha instalado
  Bugzilla en \dirname{/var/www/html/bugzilla}:
  \begin{codesample4}
    cd /var/www/html/bugzilla && ./processmail %s nobody@nowhere.com
  \end{codesample4}
  El programa \texttt{processmail} de Bugzilla espera recibir un ID de
  fallo (el gancho reemplaza ``\texttt{\%s}'' por el ID del fallo) y
  una dirección de correo. También espera poder escribir a ciertos
  ficheros en el directorio en que se ejecuta. Si Bugzilla y éste
  gancho no están instalados en la misma máquina, usted deberá
  encontrar una manera de ejecutar \texttt{processmail} en el servidor
  donde está instalado Bugzilla.
\end{itemize}

\subsubsection{Mapping committer names to Bugzilla user names}

By default, the \hgext{bugzilla} hook tries to use the email address
of a changeset's committer as the Bugzilla user name with which to
update a bug.  If this does not suit your needs, you can map committer
email addresses to Bugzilla user names using a \rcsection{usermap}
section.

Each item in the \rcsection{usermap} section contains an email address
on the left, and a Bugzilla user name on the right.
\begin{codesample2}
  [usermap]
  jane.user@example.com = jane
\end{codesample2}
You can either keep the \rcsection{usermap} data in a normal \hgrc, or
tell the \hgext{bugzilla} hook to read the information from an
external \filename{usermap} file.  In the latter case, you can store
\filename{usermap} data by itself in (for example) a user-modifiable
repository.  This makes it possible to let your users maintain their
own \rcitem{bugzilla}{usermap} entries.  The main \hgrc\ file might
look like this:
\begin{codesample2}
  # regular hgrc file refers to external usermap file
  [bugzilla]
  usermap = /home/hg/repos/userdata/bugzilla-usermap.conf
\end{codesample2}
While the \filename{usermap} file that it refers to might look like
this:
\begin{codesample2}
  # bugzilla-usermap.conf - inside a hg repository
  [usermap]
  stephanie@example.com = steph
\end{codesample2}

\subsubsection{Configuring the text that gets added to a bug}

You can configure the text that this hook adds as a comment; you
specify it in the form of a Mercurial template.  Several \hgrc\
entries (still in the \rcsection{bugzilla} section) control this
behaviour.
\begin{itemize}
\item[\texttt{strip}] The number of leading path elements to strip
  from a repository's path name to construct a partial path for a URL.
  For example, if the repositories on your server live under
  \dirname{/home/hg/repos}, and you have a repository whose path is
  \dirname{/home/hg/repos/app/tests}, then setting \texttt{strip} to
  \texttt{4} will give a partial path of \dirname{app/tests}.  The
  hook will make this partial path available when expanding a
  template, as \texttt{webroot}.
\item[\texttt{template}] The text of the template to use.  In addition
  to the usual changeset-related variables, this template can use
  \texttt{hgweb} (the value of the \texttt{hgweb} configuration item
  above) and \texttt{webroot} (the path constructed using
  \texttt{strip} above).
\end{itemize}

In addition, you can add a \rcitem{web}{baseurl} item to the
\rcsection{web} section of your \hgrc.  The \hgext{bugzilla} hook will
make this available when expanding a template, as the base string to
use when constructing a URL that will let users browse from a Bugzilla
comment to view a changeset.  Example:
\begin{codesample2}
  [web]
  baseurl = http://hg.domain.com/
\end{codesample2}

Here is an example set of \hgext{bugzilla} hook config information.
\begin{codesample2}
  [bugzilla]
  host = bugzilla.example.com
  password = mypassword
  version = 2.16
  # server-side repos live in /home/hg/repos, so strip 4 leading
  # separators
  strip = 4
  hgweb = http://hg.example.com/
  usermap = /home/hg/repos/notify/bugzilla.conf
  template = Changeset \{node|short\}, made by \{author\} in the \{webroot\}
    repo, refers to this bug.\\nFor complete details, see 
    \{hgweb\}\{webroot\}?cmd=changeset;node=\{node|short\}\\nChangeset
    description:\\n\\t\{desc|tabindent\}
\end{codesample2}

\subsubsection{Testing and troubleshooting}

The most common problems with configuring the \hgext{bugzilla} hook
relate to running Bugzilla's \filename{processmail} script and mapping
committer names to user names.

Recall from section~\ref{sec:hook:bugzilla:config} above that the user
that runs the Mercurial process on the server is also the one that
will run the \filename{processmail} script.  The
\filename{processmail} script sometimes causes Bugzilla to write to
files in its configuration directory, and Bugzilla's configuration
files are usually owned by the user that your web server runs under.

You can cause \filename{processmail} to be run with the suitable
user's identity using the \command{sudo} command.  Here is an example
entry for a \filename{sudoers} file.
\begin{codesample2}
  hg_user = (httpd_user) NOPASSWD: /var/www/html/bugzilla/processmail-wrapper %s
\end{codesample2}
This allows the \texttt{hg\_user} user to run a
\filename{processmail-wrapper} program under the identity of
\texttt{httpd\_user}.

This indirection through a wrapper script is necessary, because
\filename{processmail} expects to be run with its current directory
set to wherever you installed Bugzilla; you can't specify that kind of
constraint in a \filename{sudoers} file.  The contents of the wrapper
script are simple:
\begin{codesample2}
  #!/bin/sh
  cd `dirname $0` && ./processmail "$1" nobody@example.com
\end{codesample2}
It doesn't seem to matter what email address you pass to
\filename{processmail}.

If your \rcsection{usermap} is not set up correctly, users will see an
error message from the \hgext{bugzilla} hook when they push changes
to the server.  The error message will look like this:
\begin{codesample2}
  cannot find bugzilla user id for john.q.public@example.com
\end{codesample2}
What this means is that the committer's address,
\texttt{john.q.public@example.com}, is not a valid Bugzilla user name,
nor does it have an entry in your \rcsection{usermap} that maps it to
a valid Bugzilla user name.

\subsection{\hgext{notify}---send email notifications}

Although Mercurial's built-in web server provides RSS feeds of changes
in every repository, many people prefer to receive change
notifications via email.  The \hgext{notify} hook lets you send out
notifications to a set of email addresses whenever changesets arrive
that those subscribers are interested in.

As with the \hgext{bugzilla} hook, the \hgext{notify} hook is
template-driven, so you can customise the contents of the notification
messages that it sends.

By default, the \hgext{notify} hook includes a diff of every changeset
that it sends out; you can limit the size of the diff, or turn this
feature off entirely.  It is useful for letting subscribers review
changes immediately, rather than clicking to follow a URL.

\subsubsection{Configuring the \hgext{notify} hook}

You can set up the \hgext{notify} hook to send one email message per
incoming changeset, or one per incoming group of changesets (all those
that arrived in a single pull or push).
\begin{codesample2}
  [hooks]
  # send one email per group of changes
  changegroup.notify = python:hgext.notify.hook
  # send one email per change
  incoming.notify = python:hgext.notify.hook
\end{codesample2}

Configuration information for this hook lives in the
\rcsection{notify} section of a \hgrc\ file.
\begin{itemize}
\item[\rcitem{notify}{test}] By default, this hook does not send out
  email at all; instead, it prints the message that it \emph{would}
  send.  Set this item to \texttt{false} to allow email to be sent.
  The reason that sending of email is turned off by default is that it
  takes several tries to configure this extension exactly as you would
  like, and it would be bad form to spam subscribers with a number of
  ``broken'' notifications while you debug your configuration.
\item[\rcitem{notify}{config}] The path to a configuration file that
  contains subscription information.  This is kept separate from the
  main \hgrc\ so that you can maintain it in a repository of its own.
  People can then clone that repository, update their subscriptions,
  and push the changes back to your server.
\item[\rcitem{notify}{strip}] The number of leading path separator
  characters to strip from a repository's path, when deciding whether
  a repository has subscribers.  For example, if the repositories on
  your server live in \dirname{/home/hg/repos}, and \hgext{notify} is
  considering a repository named \dirname{/home/hg/repos/shared/test},
  setting \rcitem{notify}{strip} to \texttt{4} will cause
  \hgext{notify} to trim the path it considers down to
  \dirname{shared/test}, and it will match subscribers against that.
\item[\rcitem{notify}{template}] The template text to use when sending
  messages.  This specifies both the contents of the message header
  and its body.
\item[\rcitem{notify}{maxdiff}] The maximum number of lines of diff
  data to append to the end of a message.  If a diff is longer than
  this, it is truncated.  By default, this is set to 300.  Set this to
  \texttt{0} to omit diffs from notification emails.
\item[\rcitem{notify}{sources}] A list of sources of changesets to
  consider.  This lets you limit \hgext{notify} to only sending out
  email about changes that remote users pushed into this repository
  via a server, for example.  See section~\ref{sec:hook:sources} for
  the sources you can specify here.
\end{itemize}

If you set the \rcitem{web}{baseurl} item in the \rcsection{web}
section, you can use it in a template; it will be available as
\texttt{webroot}.

Here is an example set of \hgext{notify} configuration information.
\begin{codesample2}
  [notify]
  # really send email
  test = false
  # subscriber data lives in the notify repo
  config = /home/hg/repos/notify/notify.conf
  # repos live in /home/hg/repos on server, so strip 4 "/" chars
  strip = 4
  template = X-Hg-Repo: \{webroot\}
    Subject: \{webroot\}: \{desc|firstline|strip\}
    From: \{author\}

    changeset \{node|short\} in \{root\}
    details: \{baseurl\}\{webroot\}?cmd=changeset;node=\{node|short\}
    description:
      \{desc|tabindent|strip\}

  [web]
  baseurl = http://hg.example.com/
\end{codesample2}

This will produce a message that looks like the following:
\begin{codesample2}
  X-Hg-Repo: tests/slave
  Subject: tests/slave: Handle error case when slave has no buffers
  Date: Wed,  2 Aug 2006 15:25:46 -0700 (PDT)

  changeset 3cba9bfe74b5 in /home/hg/repos/tests/slave
  details: http://hg.example.com/tests/slave?cmd=changeset;node=3cba9bfe74b5
  description:
          Handle error case when slave has no buffers
  diffs (54 lines):

  diff -r 9d95df7cf2ad -r 3cba9bfe74b5 include/tests.h
  --- a/include/tests.h      Wed Aug 02 15:19:52 2006 -0700
  +++ b/include/tests.h      Wed Aug 02 15:25:26 2006 -0700
  @@ -212,6 +212,15 @@ static __inline__ void test_headers(void *h)
  [...snip...]
\end{codesample2}

\subsubsection{Testing and troubleshooting}

Do not forget that by default, the \hgext{notify} extension \emph{will
  not send any mail} until you explicitly configure it to do so, by
setting \rcitem{notify}{test} to \texttt{false}.  Until you do that,
it simply prints the message it \emph{would} send.

\section{Information for writers of hooks}
\label{sec:hook:ref}

\subsection{In-process hook execution}

An in-process hook is called with arguments of the following form:
\begin{codesample2}
  def myhook(ui, repo, **kwargs):
      pass
\end{codesample2}
The \texttt{ui} parameter is a \pymodclass{mercurial.ui}{ui} object.
The \texttt{repo} parameter is a
\pymodclass{mercurial.localrepo}{localrepository} object.  The
names and values of the \texttt{**kwargs} parameters depend on the
hook being invoked, with the following common features:
\begin{itemize}
\item If a parameter is named \texttt{node} or
  \texttt{parent\emph{N}}, it will contain a hexadecimal changeset ID.
  The empty string is used to represent ``null changeset ID'' instead
  of a string of zeroes.
\item If a parameter is named \texttt{url}, it will contain the URL of
  a remote repository, if that can be determined.
\item Boolean-valued parameters are represented as Python
  \texttt{bool} objects.
\end{itemize}

An in-process hook is called without a change to the process's working
directory (unlike external hooks, which are run in the root of the
repository).  It must not change the process's working directory, or
it will cause any calls it makes into the Mercurial API to fail.

If a hook returns a boolean ``false'' value, it is considered to have
succeeded.  If it returns a boolean ``true'' value or raises an
exception, it is considered to have failed.  A useful way to think of
the calling convention is ``tell me if you fail''.

Note that changeset IDs are passed into Python hooks as hexadecimal
strings, not the binary hashes that Mercurial's APIs normally use.  To
convert a hash from hex to binary, use the
\pymodfunc{mercurial.node}{bin} function.

\subsection{External hook execution}

An external hook is passed to the shell of the user running Mercurial.
Features of that shell, such as variable substitution and command
redirection, are available.  The hook is run in the root directory of
the repository (unlike in-process hooks, which are run in the same
directory that Mercurial was run in).

Hook parameters are passed to the hook as environment variables.  Each
environment variable's name is converted in upper case and prefixed
with the string ``\texttt{HG\_}''.  For example, if the name of a
parameter is ``\texttt{node}'', the name of the environment variable
representing that parameter will be ``\texttt{HG\_NODE}''.

A boolean parameter is represented as the string ``\texttt{1}'' for
``true'', ``\texttt{0}'' for ``false''.  If an environment variable is
named \envar{HG\_NODE}, \envar{HG\_PARENT1} or \envar{HG\_PARENT2}, it
contains a changeset ID represented as a hexadecimal string.  The
empty string is used to represent ``null changeset ID'' instead of a
string of zeroes.  If an environment variable is named
\envar{HG\_URL}, it will contain the URL of a remote repository, if
that can be determined.

If a hook exits with a status of zero, it is considered to have
succeeded.  If it exits with a non-zero status, it is considered to
have failed.

\subsection{Finding out where changesets come from}

A hook that involves the transfer of changesets between a local
repository and another may be able to find out information about the
``far side''.  Mercurial knows \emph{how} changes are being
transferred, and in many cases \emph{where} they are being transferred
to or from.

\subsubsection{Sources of changesets}
\label{sec:hook:sources}

Mercurial will tell a hook what means are, or were, used to transfer
changesets between repositories.  This is provided by Mercurial in a
Python parameter named \texttt{source}, or an environment variable named
\envar{HG\_SOURCE}.

\begin{itemize}
\item[\texttt{serve}] Changesets are transferred to or from a remote
  repository over http or ssh.
\item[\texttt{pull}] Changesets are being transferred via a pull from
  one repository into another.
\item[\texttt{push}] Changesets are being transferred via a push from
  one repository into another.
\item[\texttt{bundle}] Changesets are being transferred to or from a
  bundle.
\end{itemize}

\subsubsection{Where changes are going---remote repository URLs}
\label{sec:hook:url}

When possible, Mercurial will tell a hook the location of the ``far
side'' of an activity that transfers changeset data between
repositories.  This is provided by Mercurial in a Python parameter
named \texttt{url}, or an environment variable named \envar{HG\_URL}.

This information is not always known.  If a hook is invoked in a
repository that is being served via http or ssh, Mercurial cannot tell
where the remote repository is, but it may know where the client is
connecting from.  In such cases, the URL will take one of the
following forms:
\begin{itemize}
\item \texttt{remote:ssh:\emph{ip-address}}---remote ssh client, at
  the given IP address.
\item \texttt{remote:http:\emph{ip-address}}---remote http client, at
  the given IP address.  If the client is using SSL, this will be of
  the form \texttt{remote:https:\emph{ip-address}}.
\item Empty---no information could be discovered about the remote
  client.
\end{itemize}

\section{Hook reference}

\subsection{\hook{changegroup}---after remote changesets added}
\label{sec:hook:changegroup}

This hook is run after a group of pre-existing changesets has been
added to the repository, for example via a \hgcmd{pull} or
\hgcmd{unbundle}.  This hook is run once per operation that added one
or more changesets.  This is in contrast to the \hook{incoming} hook,
which is run once per changeset, regardless of whether the changesets
arrive in a group.

Some possible uses for this hook include kicking off an automated
build or test of the added changesets, updating a bug database, or
notifying subscribers that a repository contains new changes.

Parameters to this hook:
\begin{itemize}
\item[\texttt{node}] A changeset ID.  The changeset ID of the first
  changeset in the group that was added.  All changesets between this
  and \index{tags!\texttt{tip}}\texttt{tip}, inclusive, were added by
  a single \hgcmd{pull}, \hgcmd{push} or \hgcmd{unbundle}.
\item[\texttt{source}] A string.  The source of these changes.  See
  section~\ref{sec:hook:sources} for details.
\item[\texttt{url}] A URL.  The location of the remote repository, if
  known.  See section~\ref{sec:hook:url} for more information.
\end{itemize}

See also: \hook{incoming} (section~\ref{sec:hook:incoming}),
\hook{prechangegroup} (section~\ref{sec:hook:prechangegroup}),
\hook{pretxnchangegroup} (section~\ref{sec:hook:pretxnchangegroup})

\subsection{\hook{commit}---after a new changeset is created}
\label{sec:hook:commit}

This hook is run after a new changeset has been created.

Parameters to this hook:
\begin{itemize}
\item[\texttt{node}] A changeset ID.  The changeset ID of the newly
  committed changeset.
\item[\texttt{parent1}] A changeset ID.  The changeset ID of the first
  parent of the newly committed changeset.
\item[\texttt{parent2}] A changeset ID.  The changeset ID of the second
  parent of the newly committed changeset.
\end{itemize}

See also: \hook{precommit} (section~\ref{sec:hook:precommit}),
\hook{pretxncommit} (section~\ref{sec:hook:pretxncommit})

\subsection{\hook{incoming}---after one remote changeset is added}
\label{sec:hook:incoming}

This hook is run after a pre-existing changeset has been added to the
repository, for example via a \hgcmd{push}.  If a group of changesets
was added in a single operation, this hook is called once for each
added changeset.

You can use this hook for the same purposes as the \hook{changegroup}
hook (section~\ref{sec:hook:changegroup}); it's simply more convenient
sometimes to run a hook once per group of changesets, while other
times it's handier once per changeset.

Parameters to this hook:
\begin{itemize}
\item[\texttt{node}] A changeset ID.  The ID of the newly added
  changeset.
\item[\texttt{source}] A string.  The source of these changes.  See
  section~\ref{sec:hook:sources} for details.
\item[\texttt{url}] A URL.  The location of the remote repository, if
  known.  See section~\ref{sec:hook:url} for more information.
\end{itemize}

See also: \hook{changegroup} (section~\ref{sec:hook:changegroup}) \hook{prechangegroup} (section~\ref{sec:hook:prechangegroup}), \hook{pretxnchangegroup} (section~\ref{sec:hook:pretxnchangegroup})

\subsection{\hook{outgoing}---after changesets are propagated}
\label{sec:hook:outgoing}

This hook is run after a group of changesets has been propagated out
of this repository, for example by a \hgcmd{push} or \hgcmd{bundle}
command.

One possible use for this hook is to notify administrators that
changes have been pulled.

Parameters to this hook:
\begin{itemize}
\item[\texttt{node}] A changeset ID.  The changeset ID of the first
  changeset of the group that was sent.
\item[\texttt{source}] A string.  The source of the of the operation
  (see section~\ref{sec:hook:sources}).  If a remote client pulled
  changes from this repository, \texttt{source} will be
  \texttt{serve}.  If the client that obtained changes from this
  repository was local, \texttt{source} will be \texttt{bundle},
  \texttt{pull}, or \texttt{push}, depending on the operation the
  client performed.
\item[\texttt{url}] A URL.  The location of the remote repository, if
  known.  See section~\ref{sec:hook:url} for more information.
\end{itemize}

See also: \hook{preoutgoing} (section~\ref{sec:hook:preoutgoing})

\subsection{\hook{prechangegroup}---before starting to add remote changesets}
\label{sec:hook:prechangegroup}

This controlling hook is run before Mercurial begins to add a group of
changesets from another repository.

This hook does not have any information about the changesets to be
added, because it is run before transmission of those changesets is
allowed to begin.  If this hook fails, the changesets will not be
transmitted.

One use for this hook is to prevent external changes from being added
to a repository.  For example, you could use this to ``freeze'' a
server-hosted branch temporarily or permanently so that users cannot
push to it, while still allowing a local administrator to modify the
repository.

Parameters to this hook:
\begin{itemize}
\item[\texttt{source}] A string.  The source of these changes.  See
  section~\ref{sec:hook:sources} for details.
\item[\texttt{url}] A URL.  The location of the remote repository, if
  known.  See section~\ref{sec:hook:url} for more information.
\end{itemize}

See also: \hook{changegroup} (section~\ref{sec:hook:changegroup}),
\hook{incoming} (section~\ref{sec:hook:incoming}), ,
\hook{pretxnchangegroup} (section~\ref{sec:hook:pretxnchangegroup})

\subsection{\hook{precommit}---before starting to commit a changeset}
\label{sec:hook:precommit}

This hook is run before Mercurial begins to commit a new changeset.
It is run before Mercurial has any of the metadata for the commit,
such as the files to be committed, the commit message, or the commit
date.

One use for this hook is to disable the ability to commit new
changesets, while still allowing incoming changesets.  Another is to
run a build or test, and only allow the commit to begin if the build
or test succeeds.

Parameters to this hook:
\begin{itemize}
\item[\texttt{parent1}] A changeset ID.  The changeset ID of the first
  parent of the working directory.
\item[\texttt{parent2}] A changeset ID.  The changeset ID of the second
  parent of the working directory.
\end{itemize}
If the commit proceeds, the parents of the working directory will
become the parents of the new changeset.

See also: \hook{commit} (section~\ref{sec:hook:commit}),
\hook{pretxncommit} (section~\ref{sec:hook:pretxncommit})

\subsection{\hook{preoutgoing}---before starting to propagate changesets}
\label{sec:hook:preoutgoing}

This hook is invoked before Mercurial knows the identities of the
changesets to be transmitted.

One use for this hook is to prevent changes from being transmitted to
another repository.

Parameters to this hook:
\begin{itemize}
\item[\texttt{source}] A string.  The source of the operation that is
  attempting to obtain changes from this repository (see
  section~\ref{sec:hook:sources}).  See the documentation for the
  \texttt{source} parameter to the \hook{outgoing} hook, in
  section~\ref{sec:hook:outgoing}, for possible values of this
  parameter.
\item[\texttt{url}] A URL.  The location of the remote repository, if
  known.  See section~\ref{sec:hook:url} for more information.
\end{itemize}

See also: \hook{outgoing} (section~\ref{sec:hook:outgoing})

\subsection{\hook{pretag}---before tagging a changeset}
\label{sec:hook:pretag}

This controlling hook is run before a tag is created.  If the hook
succeeds, creation of the tag proceeds.  If the hook fails, the tag is
not created.

Parameters to this hook:
\begin{itemize}
\item[\texttt{local}] A boolean.  Whether the tag is local to this
  repository instance (i.e.~stored in \sfilename{.hg/localtags}) or
  managed by Mercurial (stored in \sfilename{.hgtags}).
\item[\texttt{node}] A changeset ID.  The ID of the changeset to be tagged.
\item[\texttt{tag}] A string.  The name of the tag to be created.
\end{itemize}

If the tag to be created is revision-controlled, the \hook{precommit}
and \hook{pretxncommit} hooks (sections~\ref{sec:hook:commit}
and~\ref{sec:hook:pretxncommit}) will also be run.

See also: \hook{tag} (section~\ref{sec:hook:tag})

\subsection{\hook{pretxnchangegroup}---before completing addition of
  remote changesets}
\label{sec:hook:pretxnchangegroup}

This controlling hook is run before a transaction---that manages the
addition of a group of new changesets from outside the
repository---completes.  If the hook succeeds, the transaction
completes, and all of the changesets become permanent within this
repository.  If the hook fails, the transaction is rolled back, and
the data for the changesets is erased.

This hook can access the metadata associated with the almost-added
changesets, but it should not do anything permanent with this data.
It must also not modify the working directory.

While this hook is running, if other Mercurial processes access this
repository, they will be able to see the almost-added changesets as if
they are permanent.  This may lead to race conditions if you do not
take steps to avoid them.

This hook can be used to automatically vet a group of changesets.  If
the hook fails, all of the changesets are ``rejected'' when the
transaction rolls back.

Parameters to this hook:
\begin{itemize}
\item[\texttt{node}] A changeset ID.  The changeset ID of the first
  changeset in the group that was added.  All changesets between this
  and \index{tags!\texttt{tip}}\texttt{tip}, inclusive, were added by
  a single \hgcmd{pull}, \hgcmd{push} or \hgcmd{unbundle}.
\item[\texttt{source}] A string.  The source of these changes.  See
  section~\ref{sec:hook:sources} for details.
\item[\texttt{url}] A URL.  The location of the remote repository, if
  known.  See section~\ref{sec:hook:url} for more information.
\end{itemize}

See also: \hook{changegroup} (section~\ref{sec:hook:changegroup}),
\hook{incoming} (section~\ref{sec:hook:incoming}),
\hook{prechangegroup} (section~\ref{sec:hook:prechangegroup})

\subsection{\hook{pretxncommit}---before completing commit of new changeset}
\label{sec:hook:pretxncommit}

This controlling hook is run before a transaction---that manages a new
commit---completes.  If the hook succeeds, the transaction completes
and the changeset becomes permanent within this repository.  If the
hook fails, the transaction is rolled back, and the commit data is
erased.

This hook can access the metadata associated with the almost-new
changeset, but it should not do anything permanent with this data.  It
must also not modify the working directory.

While this hook is running, if other Mercurial processes access this
repository, they will be able to see the almost-new changeset as if it
is permanent.  This may lead to race conditions if you do not take
steps to avoid them.

Parameters to this hook:
\begin{itemize}
\item[\texttt{node}] A changeset ID.  The changeset ID of the newly
  committed changeset.
\item[\texttt{parent1}] A changeset ID.  The changeset ID of the first
  parent of the newly committed changeset.
\item[\texttt{parent2}] A changeset ID.  The changeset ID of the second
  parent of the newly committed changeset.
\end{itemize}

See also: \hook{precommit} (section~\ref{sec:hook:precommit})

\subsection{\hook{preupdate}---before updating or merging working directory}
\label{sec:hook:preupdate}

This controlling hook is run before an update or merge of the working
directory begins.  It is run only if Mercurial's normal pre-update
checks determine that the update or merge can proceed.  If the hook
succeeds, the update or merge may proceed; if it fails, the update or
merge does not start.

Parameters to this hook:
\begin{itemize}
\item[\texttt{parent1}] A changeset ID.  The ID of the parent that the
  working directory is to be updated to.  If the working directory is
  being merged, it will not change this parent.
\item[\texttt{parent2}] A changeset ID.  Only set if the working
  directory is being merged.  The ID of the revision that the working
  directory is being merged with.
\end{itemize}

See also: \hook{update} (section~\ref{sec:hook:update})

\subsection{\hook{tag}---after tagging a changeset}
\label{sec:hook:tag}

This hook is run after a tag has been created.

Parameters to this hook:
\begin{itemize}
\item[\texttt{local}] A boolean.  Whether the new tag is local to this
  repository instance (i.e.~stored in \sfilename{.hg/localtags}) or
  managed by Mercurial (stored in \sfilename{.hgtags}).
\item[\texttt{node}] A changeset ID.  The ID of the changeset that was
  tagged.
\item[\texttt{tag}] A string.  The name of the tag that was created.
\end{itemize}

If the created tag is revision-controlled, the \hook{commit} hook
(section~\ref{sec:hook:commit}) is run before this hook.

See also: \hook{pretag} (section~\ref{sec:hook:pretag})

\subsection{\hook{update}---after updating or merging working directory}
\label{sec:hook:update}

This hook is run after an update or merge of the working directory
completes.  Since a merge can fail (if the external \command{hgmerge}
command fails to resolve conflicts in a file), this hook communicates
whether the update or merge completed cleanly.

\begin{itemize}
\item[\texttt{error}] A boolean.  Indicates whether the update or
  merge completed successfully.
\item[\texttt{parent1}] A changeset ID.  The ID of the parent that the
  working directory was updated to.  If the working directory was
  merged, it will not have changed this parent.
\item[\texttt{parent2}] A changeset ID.  Only set if the working
  directory was merged.  The ID of the revision that the working
  directory was merged with.
\end{itemize}

See also: \hook{preupdate} (section~\ref{sec:hook:preupdate})

%%% Local Variables: 
%%% mode: latex
%%% TeX-master: "00book"
%%% End: