\chapter{Añadir funcionalidad con extensiones}
\label{chap:hgext}

A pesar de que el corazón de Mercurial es muy completo desde el punto
de vista de funcionalidad, carece de características rimbombantes
deliberadamente.  Esta aproximación de preservar la simplicidad
mantiene el programa sencillo tanto para mantenedores como para
usuarios.

Si embargo Mercurial no le cierra las posibilidades a un conjunto
inflexible de órdenes: usted puede añadir características como
\emph{extensiones} (aveces llamadas \emph{añadidos}\ndt{plugins}).  Ya
hemos discutido algunas de estas extensiones en capítulos anteriores:
\begin{itemize}
\item La sección~\ref{sec:tour-merge:fetch} cubre la extensión
  \hgext{fetch}; que combina jalar cambios y fusionarlos con los
  cambios locales en una sola orden: \hgxcmd{fetch}{fetch}.
\item En el capítulo~\ref{chap:hook}, cubrimos muchas extensiones que
  son útiles en funcionalidades relacionadas con ganchos: Los
  \hgext{acl} añaden listas de control de acceso; \hgext{bugzilla}
  añade integración con el sistema de seguimiento de fallos Bugzilla; y
  \hgext{notify} envía notificaciones por correo de nuevos cambios.
\item La extensión de administración de parches MQ es tan invaluable
  que amerita dos capítulos y un apéndice por sí misma.
  El capítulo~\ref{chap:mq} cubre lo básico; el
  capítulo~\ref{chap:mq-collab} discute temas avanzados; y el
  apéndice~\ref{chap:mqref} muestra en detalle cada orden.
\end{itemize}

En este capítulo cubriremos algunas extensiones adicionales
disponibles para Mercurial, y daremos un vistazo a la maquinaria que
necesita conocer en caso de que desee escribir una extensión.
\begin{itemize}
\item En la sección~\ref{sec:hgext:inotify}, discutiremos la
  posibilidad de mejorar el desempeño \emph{en gran medida} con la extensión
  \hgext{inotify}.
\end{itemize}

\section{Mejorar el desempeño con la extensión \hgext{inotify}}
\label{sec:hgext:inotify}

¿Desea lograr que las operaciones más comunmente usadas de Mercurial se
ejecuten centenas de veces más rápido? ¡A leer!

Mercurial tiene gran desempeño bajo circunstancias normales.  Por
ejemplo, cuando ejecuta la orden \hgcmd{status}, Mercurial tiene que
revisar casi todos los ficheros y directorios en su repositorio de
forma que pueda desplegar el estado de los ficheros.  Muchas otras
órdenes tienen que hacer tal trabajo tras bambalinas;  por ejemplo la
orden \hgcmd{diff} usa la maquinaria de estado para evitar hacer
operaciones de comparación costosas en ficheros que obviamente no han
cambiado.

Dado que obtener el estado de los ficheros es crucial para obtener
buen desempeño, los autores de Mercurial han optimizado este código en
la medida de lo posible.  Sin embargo, no puede obviarse el hecho de
que cuando ejecuta \hgcmd{status}, Mercurial tendrá que hacer por lo
menos una costosa llamada al sistema por cada archivo administrado
para determinar si ha cambiado desde la última vez que se consignó.
Para un repositorio suficientemente grande, puede tardar bastante
tiempo.

Para mostrar en números la magnitud de este efect, creé un repositorio
que contenía 150.000 archivos administrador.  Tardó diez segundos para
ejecutar \hgcmd{status}, a pesar de que \emph{ninguno} de los ficheros
había sido modificado.

Muchos sistemas operativos modernos contienen una facilidad de
notificación de archivos.  Si un programa se registra con un servicio
apropiado, el sistema operativo le notificará siempre que un fichero
de interés haya sido creado, modificado o borrado.  En sistemas Linux,
el componente del núcleo que lo hace se llama \texttt{inotify}.

La extensión \hgext{inotify} habla con el componente \texttt{inotify}
del núcleo para optimizar las órdenes de \hgcmd{status}.  La extensión
tiene dos componentes.  Un daemonio está en el fondo recibiendo
notificaciones del subsistema \texttt{inotify}.  También escucha
conexiones de una orden regular de Mercurial.  La extensión modifica
el comportamiento de Mercurial de tal forma que, en lugar de revisar
el sistema de ficheros, le pregunta al daemonio.  Dado que el daemonio
tiene información perfecta acerca del estado del repositorio, puede
responder instantáneamente con el resultado, evitando la necesidad de
revisar cada directorio y fichero del repositorio.

Retomando los diez segundos que medí al ejecutar la orden
\hgcmd{status} de Mercurial sobre un repositorio de 150.000
ficheros. Con la extensión \hgext{inotify} habilitada, el tiempo se
disipó a 0.1~seconds, un factor \emph{cien veces} más rápido.

Antes de continuar, tenga en cuenta algunos detalles:
\begin{itemize}
\item La extensión \hgext{inotify} es específica de Linux.  Porque se
  enlaza directamente con el subsistema \texttt{inotify} del núcleo
  Linux, no funciona en otros sistemas operativos.
\item Debería funcionar en cualquier distribución Linux a partir de
  comienzos del 2005.  Las distribuciones más antiguas deben tener un
  kernel sin \texttt{inotify}, o una versión de \texttt{glibc} que no
  tiene necesariamente el soporte para la interfaz.
\item No todos los sistemas de ficheros pueden usarse con la extensión
  \hgext{inotify}.  Los sistemas de ficheros tales como NFS no lo
  soportan, por ejemplo, si está corriendo Mercurial en vaios
  sistemas, montados todos sobre el mismo sistema de ficheros en red.
  El sistema \texttt{inotify} del kernel no tiene forma de saber
  acerca de los cambios hechos en otro sistema.  La mayoría de
  sistemas de ficheros locales (p.e.~ext3, XFS, ReiserFS) deberían
  funcionar bien.
\end{itemize}

Hacia mayo de 2007 la extensión \hgext{inotify} no venía de forma
predeterminada en Mercurial\ndt{Desde el 2008 para kernels 2.6 viene
  en Mercurial, pero no está activada de forma predeterminada}, y es
un poco más compleja de activar que otras extensiones.  Pero la mejora
en el desempeño bien vale la pena!

La extensión venía en dos partes: un conjunto de parches al código
fuente de Mercurial, y una librería de interfaces de Python hacia el
subsistema \texttt{inotify}.
\begin{note}
  Hay \emph{dos} librerías de enlace de Python hacia \texttt{inotify}.
  Una de ellas se llama \texttt{pyinotify}, y en algunas
  distribuciones de Linux se encuentra como \texttt{python-inotify}.
  Esta es la que \emph{no} necesita, puesto que tiene muchos fallos,
  y es ineficiente para ser práctica.
\end{note}
Para comenzar, es mejor tener una copia de Mercurial funcional
instalada:
\begin{note}
  Si sigue las instrucciones a continuación, estará
  \emph{reemplazando} y sobreescribiendo cualquier instalación previa
  de Mercurial que pudiera tener, con el código de Mercurial ``más
  reciente y peligrosa''.  No diga que no se le advirtio!
\end{note}
\begin{enumerate}
\item Clone el repositorio de interfaz entre Python e
  \texttt{inotify}. Ármelo e instálelo:
  \begin{codesample4}
    hg clone http://hg.kublai.com/python/inotify
    cd inotify
    python setup.py build --force
    sudo python setup.py install --skip-build
  \end{codesample4}
\item Clone el repositorio \dirname{crew} de Mercurial.  Clone el
  repositorio de parches de \hgext{inotify} de forma tal que las colas
  de Mercurial puedan aplicar los parches sobre el repositorio \dirname{crew}.
  \begin{codesample4}
    hg clone http://hg.intevation.org/mercurial/crew
    hg clone crew inotify
    hg clone http://hg.kublai.com/mercurial/patches/inotify inotify/.hg/patches
  \end{codesample4}
\item Asegúrese de instalar la extensión Colas de Mercurial
  \hgext{mq} y que estén habilitadas.  Si nunca ha usado MQ, lea la
  sección~\ref{sec:mq:start} para poder comenzar rápidamente.
\item Vaya al repositorio de \dirname{inotify} y aplique todos los
  parches de \hgext{inotify} con la opción \hgxopt{mq}{qpush}{-a} de
  la orden \hgxcmd{mq}{qpush}.
  \begin{codesample4}
    cd inotify
    hg qpush -a
  \end{codesample4}
  Si obtiene un mensaje de error de \hgxcmd{mq}{qpush}, no debería
  continuar.  Mejor pida ayuda.
\item Arme e instale la versión parchada de Mercurial.
  \begin{codesample4}
    python setup.py build --force
    sudo python setup.py install --skip-build
  \end{codesample4}
\end{enumerate}
Una vez que haya armado una versión funcional parchada de Mercurial,
todo lo que necesita es habilitar la extensión \hgext{inotify}
colocando una entrada en su \hgrc.
\begin{codesample2}
  [extensions]
  inotify =
\end{codesample2}
Cuando la extensión \hgext{inotify} esté habilitada, Mercurial
iniciará transparente y automáticamente el daemonio de estado la
primera vez que ejecute un comando que requiera estado del
repositorio.  Ejecuta un daemoniot de estado por repositorio.

El daemonio de estado se inicia silenciosamente y se ejecuta en el
fondo. Si mira a la lista de procesos en ejecución después de
habilitar la extensión \hgext{inotify} y ejecuta unos pocos comandos
en diferentes repositorios, verá que hay algunos procesos de
\texttt{hg} por ahí, esperando actualizaciones del kernel y
solicitudes de Mercurial.

La primera vez que ejecuta un comando de Mercurial en un repositorio
cuando tiene la extensión \hgext{inotify} habilitada, correrá casi con
el mismo desempeño que una orden usual de Mercurial.  Esto es debido a
que el estado del daemonio necesita aplicar una búsqueda normal sobre
el estado para poder tener una línea de partida frente a la cual
aplicar posteriormente actualizaciones del núcleo.  De todas formas,
\emph{todo} comando posterior que haga cualquier clase de revisión del
estado debería ser notablemente más rápido en repositorios con incluso
un tamaño modesto.  Aún mejor, a medida que su repositorio sea más
grande, mejor desempeño verá.  El daemonio \hgext{inotify} hace
operaciones de estado de forma casi instantánea en repositorios de
todos los tamaños!

Si lo desea, puede iniciar manualmente un daemonio de estado con la orden
\hgxcmd{inotify}{inserve}.  Esto le da un control un poco más fino
acerca de cómo debería ejecutarse el daemonio.  Esta orden solamente
estará disponible cuando haya habilitado la extensión \hgext{inotify}.

Cuando esté usando la extensión \hgext{inotify},
\emph{no debería ver diferencia} en el comportamiento de Mercurial,
con la única excepción de que los comandos relacionados con el estado
deberían ejectuarse mucho más rápido que como solían hacerlo.  Debería
esperar específicamente que las órdenes no deberían ofrecer salidas
distintas; ni ofrecer resultados diferentes.  Si alguna de estas
situaciones ocurre, por favor reporte el fallo.

\section{Soporte flexible de diff con la extensión \hgext{extdiff}}
\label{sec:hgext:extdiff}

La orden predeterminada \hgcmd{diff} de Mercurial despliega diffs en
texto plano unificadas.
\interaction{extdiff.diff}
Si dese emplear una herramienta externa para desplegar las
modificaciones, querrá usar la extensión \hgext{extdiff}.  Esta le
permitirá usar por ejemplo una herramienta gráfica de diff.

La extensión \hgext{extdiff} viene con Mercurial, y es fácil
configurarl.  En la sección \rcsection{extensions} de su \hgrc,
basta con añadir una entrada de una línea para habilitar la extensión.
\begin{codesample2}
  [extensions]
  extdiff =
\end{codesample2}
Esto introduce una orden llamada \hgxcmd{extdiff}{extdiff}, que de
forma predeterminada usa su orden del sistema \command{diff} para
generar un diff unificado de la misma forma que lo hace el comando
predeterminado \hgcmd{diff}.
\interaction{extdiff.extdiff}
El resultado no será exactamente el mismo que con la orden interna
\hgcmd{diff}, puesto que la salida de \command{diff} varía de un
sistema a otro, incluso pasando las mismas opciones.

As the ``\texttt{making snapshot}'' lines of output above imply, the
\hgxcmd{extdiff}{extdiff} command works by creating two snapshots of
your source tree.  The first snapshot is of the source revision; the
second, of the target revision or working directory.  The
\hgxcmd{extdiff}{extdiff} command generates these snapshots in a
temporary directory, passes the name of each directory to an external
diff viewer, then deletes the temporary directory.  For efficiency, it
only snapshots the directories and files that have changed between the
two revisions.

Snapshot directory names have the same base name as your repository.
If your repository path is \dirname{/quux/bar/foo}, then \dirname{foo}
will be the name of each snapshot directory.  Each snapshot directory
name has its changeset ID appended, if appropriate.  If a snapshot is
of revision \texttt{a631aca1083f}, the directory will be named
\dirname{foo.a631aca1083f}.  A snapshot of the working directory won't
have a changeset ID appended, so it would just be \dirname{foo} in
this example.  To see what this looks like in practice, look again at
the \hgxcmd{extdiff}{extdiff} example above.  Notice that the diff has
the snapshot directory names embedded in its header.

The \hgxcmd{extdiff}{extdiff} command accepts two important options.
The \hgxopt{extdiff}{extdiff}{-p} option lets you choose a program to
view differences with, instead of \command{diff}.  With the
\hgxopt{extdiff}{extdiff}{-o} option, you can change the options that
\hgxcmd{extdiff}{extdiff} passes to the program (by default, these
options are ``\texttt{-Npru}'', which only make sense if you're
running \command{diff}).  In other respects, the
\hgxcmd{extdiff}{extdiff} command acts similarly to the built-in
\hgcmd{diff} command: you use the same option names, syntax, and
arguments to specify the revisions you want, the files you want, and
so on.

As an example, here's how to run the normal system \command{diff}
command, getting it to generate context diffs (using the
\cmdopt{diff}{-c} option) instead of unified diffs, and five lines of
context instead of the default three (passing \texttt{5} as the
argument to the \cmdopt{diff}{-C} option).
\interaction{extdiff.extdiff-ctx}

Launching a visual diff tool is just as easy.  Here's how to launch
the \command{kdiff3} viewer.
\begin{codesample2}
  hg extdiff -p kdiff3 -o ''
\end{codesample2}

If your diff viewing command can't deal with directories, you can
easily work around this with a little scripting.  For an example of
such scripting in action with the \hgext{mq} extension and the
\command{interdiff} command, see
section~\ref{mq-collab:tips:interdiff}.

\subsection{Defining command aliases}

It can be cumbersome to remember the options to both the
\hgxcmd{extdiff}{extdiff} command and the diff viewer you want to use,
so the \hgext{extdiff} extension lets you define \emph{new} commands
that will invoke your diff viewer with exactly the right options.

All you need to do is edit your \hgrc, and add a section named
\rcsection{extdiff}.  Inside this section, you can define multiple
commands.  Here's how to add a \texttt{kdiff3} command.  Once you've
defined this, you can type ``\texttt{hg kdiff3}'' and the
\hgext{extdiff} extension will run \command{kdiff3} for you.
\begin{codesample2}
  [extdiff]
  cmd.kdiff3 =
\end{codesample2}
If you leave the right hand side of the definition empty, as above,
the \hgext{extdiff} extension uses the name of the command you defined
as the name of the external program to run.  But these names don't
have to be the same.  Here, we define a command named ``\texttt{hg
  wibble}'', which runs \command{kdiff3}.
\begin{codesample2}
  [extdiff]
  cmd.wibble = kdiff3
\end{codesample2}

You can also specify the default options that you want to invoke your
diff viewing program with.  The prefix to use is ``\texttt{opts.}'',
followed by the name of the command to which the options apply.  This
example defines a ``\texttt{hg vimdiff}'' command that runs the
\command{vim} editor's \texttt{DirDiff} extension.
\begin{codesample2}
  [extdiff]  
  cmd.vimdiff = vim
  opts.vimdiff = -f '+next' '+execute "DirDiff" argv(0) argv(1)'
\end{codesample2}

\section{Cherrypicking changes with the \hgext{transplant} extension}
\label{sec:hgext:transplant}

Need to have a long chat with Brendan about this.

\section{Send changes via email with the \hgext{patchbomb} extension}
\label{sec:hgext:patchbomb}

Many projects have a culture of ``change review'', in which people
send their modifications to a mailing list for others to read and
comment on before they commit the final version to a shared
repository.  Some projects have people who act as gatekeepers; they
apply changes from other people to a repository to which those others
don't have access.

Mercurial makes it easy to send changes over email for review or
application, via its \hgext{patchbomb} extension.  The extension is so
namd because changes are formatted as patches, and it's usual to send
one changeset per email message.  Sending a long series of changes by
email is thus much like ``bombing'' the recipient's inbox, hence
``patchbomb''.

As usual, the basic configuration of the \hgext{patchbomb} extension
takes just one or two lines in your \hgrc.
\begin{codesample2}
  [extensions]
  patchbomb =
\end{codesample2}
Once you've enabled the extension, you will have a new command
available, named \hgxcmd{patchbomb}{email}.

The safest and best way to invoke the \hgxcmd{patchbomb}{email}
command is to \emph{always} run it first with the
\hgxopt{patchbomb}{email}{-n} option.  This will show you what the
command \emph{would} send, without actually sending anything.  Once
you've had a quick glance over the changes and verified that you are
sending the right ones, you can rerun the same command, with the
\hgxopt{patchbomb}{email}{-n} option removed.

The \hgxcmd{patchbomb}{email} command accepts the same kind of
revision syntax as every other Mercurial command.  For example, this
command will send every revision between 7 and \texttt{tip},
inclusive.
\begin{codesample2}
  hg email -n 7:tip
\end{codesample2}
You can also specify a \emph{repository} to compare with.  If you
provide a repository but no revisions, the \hgxcmd{patchbomb}{email}
command will send all revisions in the local repository that are not
present in the remote repository.  If you additionally specify
revisions or a branch name (the latter using the
\hgxopt{patchbomb}{email}{-b} option), this will constrain the
revisions sent.

It's perfectly safe to run the \hgxcmd{patchbomb}{email} command
without the names of the people you want to send to: if you do this,
it will just prompt you for those values interactively.  (If you're
using a Linux or Unix-like system, you should have enhanced
\texttt{readline}-style editing capabilities when entering those
headers, too, which is useful.)

When you are sending just one revision, the \hgxcmd{patchbomb}{email}
command will by default use the first line of the changeset
description as the subject of the single email message it sends.

If you send multiple revisions, the \hgxcmd{patchbomb}{email} command
will usually send one message per changeset.  It will preface the
series with an introductory message, in which you should describe the
purpose of the series of changes you're sending.

\subsection{Changing the behaviour of patchbombs}

Not every project has exactly the same conventions for sending changes
in email; the \hgext{patchbomb} extension tries to accommodate a
number of variations through command line options.
\begin{itemize}
\item You can write a subject for the introductory message on the
  command line using the \hgxopt{patchbomb}{email}{-s} option.  This
  takes one argument, the text of the subject to use.
\item To change the email address from which the messages originate,
  use the \hgxopt{patchbomb}{email}{-f} option.  This takes one
  argument, the email address to use.
\item The default behaviour is to send unified diffs (see
  section~\ref{sec:mq:patch} for a description of the format), one per
  message.  You can send a binary bundle instead with the
  \hgxopt{patchbomb}{email}{-b} option.  
\item Unified diffs are normally prefaced with a metadata header.  You
  can omit this, and send unadorned diffs, with the
  \hgxopt{patchbomb}{email}{--plain} option.
\item Diffs are normally sent ``inline'', in the same body part as the
  description of a patch.  This makes it easiest for the largest
  number of readers to quote and respond to parts of a diff, as some
  mail clients will only quote the first MIME body part in a message.
  If you'd prefer to send the description and the diff in separate
  body parts, use the \hgxopt{patchbomb}{email}{-a} option.
\item Instead of sending mail messages, you can write them to an
  \texttt{mbox}-format mail folder using the
  \hgxopt{patchbomb}{email}{-m} option.  That option takes one
  argument, the name of the file to write to.
\item If you would like to add a \command{diffstat}-format summary to
  each patch, and one to the introductory message, use the
  \hgxopt{patchbomb}{email}{-d} option.  The \command{diffstat}
  command displays a table containing the name of each file patched,
  the number of lines affected, and a histogram showing how much each
  file is modified.  This gives readers a qualitative glance at how
  complex a patch is.
\end{itemize}

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