miércoles, 16 de diciembre de 2009

Mejorando nuestro software libre con Bitbucket : Mercurial Queues

Bitbucket

Es un servicio de hospedaje de proyectos basado en Mercurial y enriquecido con características sociales. A continuación les describo una funcionalidad que puede ser muy útil en los proyectos de software libre para manejar los parches (patches) y propuestas de mejoras. Las potencialidades de Mercurial, de Python y la web 2.0, se combinan una vez más para salvarnos.

¿Qué es Bitbucket?

No está muy alejado de la verdad mencionar que Bitbucket está inspirado en Github, otro excelente sitio con características similares pero orientado al uso de Git (y este es nada más y nada menos que el sistema de control de versiones utilizado para desarrollar el kernel de Linux ;o). Entre las diferencias fundamentales entre ambos tenemos que Mercurial es más fácil de mantener, puede ser adaptado más fácilmente a entornos distribuidos, especialmente por estar hecho en Python (al igual que Bazaar) y posee un número de comandos más reducido y similar al de Subversion, por lo que la transición es menos traumática para los usuarios de este popular sistema. Sin embargo esto es solo una breve introducción. Hay comparaciones entre Mercurial y Bazaar y también otras entre Bazaar y Mercurial :P. Se pueden encontrar más detalles en el libro Distributed revision control with Mercurial escrito por Bryan O'Sullivan. Por cierto solo se utilizó software libre para confeccionarlo ;o).

Por su parte Bitbucket todavía está en su versión beta y están trabajando rápidamente para realizar majoras y eliminar defectos. Pero ya se han puesto en funcionamiento una buena cantidad de posibilidades maravillosas. Una de ellas es el soporte para la extensión Mercurial Queues.

Mercurial Queues

Mercurial Queues no es más que la evolución de quilt, un enfoque iniciado con Git. Muy brevemente MQ es una extensión que permite mantener una pila (i.e. LIFO) de parches que se aplican sobre un repositorio. Esto permite trabajar en unas cuantas mejoras que se construyen una sobre la otra en la forma de parches, en vez de mantener cambios más abultados y poco cohesionados. Por ejemplo si se trabaja en la interfaz de usuario y se descubre un error en capas inferiores de la aplicación entonces es posible congelar los cambios para la interfaz de usuarios, e ir liberando parches hasta llegar hasta el nivel dónde se encuentra el error. Luego se arregla el error y se vuelven a incluir en la pila los cambios que fueron extraídos anteriormente, para así proseguir con el desarrollo de la interfaz de usuarios. De este modo los parches pueden ser considerados como revisiones temporales o flotantes que no se reflejan en el repositorio hasta que no se confirma que todo marcha bien o que un experimento realmente dará resultados. Como ventaja resulta que la historia del repositorio se simplifica, y desaparecen versiones irrelevantes.

Similares beneficios se pueden obtener en proyectos en los que se mantienen parches sobre un código de base (por ejemplo, optimizaciones para dispositivos o arquitecturas específicas), al menos hasta que son revisados y aprobados por los mantenedores oficiales o hasta que se terminan. En estos casos esta extensión también permite mezclar los parches (rebasing) e incorporarlos en el repositorio.

Normalmente se trabaja localmente sobre un conjunto de parches, pero es posible establecer un control de versiones sobre los propios parches de forma tal que otros también puedan perfeccionar aspectos en pleno desarrollo.

¿Cómo funciona MQ con Bitbucket?

A continuación ilustro el camino más corto para configurar una pila de parches en Bitbucket:

  • Cree el repositorio principal. Este contiene los ficheros del proyecto.
  • Si ya se tiene parte del trabajo en un repositorio local, pues le hacemos push especificando la URL del proyecto (llamémosle project-repo).
  • Presione el botón patch queue en la página principal del repositorio.

Activando el repositorio de parches en Bitbucket

  • Teclee los datos que son solicitados y cree el nuevo repositorio (llamémosle por ejemplo project-repo-patches) para manejar versiones de los parches.
  • Asegúrese de marcar la opción Omit series si Usted desea añadir parches previos.
  • Active la extensión MQ.
  • Ejecute el comando hg qclone como se muestra a continuación (si el repositorio es de nuestra propiedad entonces owner=user)

$ hg qclone https://user@bitbucket.org/owner/project-repo-patches

Como resultado obtendrá una copia local del repositorio y la pila de parches preparada para incluir nuevas versiones. Eso es todo si no se van a incluir parches ya existentes. Luego se utiliza hg qnew para comenzar un nuevo parche y se continua con hg qref y hg qcommit para refrescarlo y para añadir una versión del parche. El repositorio de los parches se encuentra dentro de la carpeta `./.hg/patches. Para distribuir el nuevo parche a los demás se hace lo siguiente.

$ cd ./.hg/patches 
$ hg push 

Las nuevas versiones del parche deben aparecer en el repositorio de parches preparado por Bitbucket :o). La URL del repositorio remoto es configurada automáticamente.

Si se desea publicar varios parches que ya existen entonces solo hace falta copiarlos en ./.hg/patches junto con el fichero series, pero nunca copie el fichero status. Agréguelos al repositorio de parches. Todo sería más o menos así.

$ cp /path/to/old/repos/.hg/patches/*.diff ./.hg/patches 
$ cp /path/to/old/repos/.hg/patches/series ./.hg/patches 
$ cd ./.hg/patches 
$ hg add ./*.diff

¿A qué se deben las diferencias?

Lo primero que resulta diferente con respecto al comportamiento habitual es que hay que hacer hg qclone al repositorio de parches y como consecuencia se obtiene todo el repositorio del proyecto. Esto se debe a que Bitbucket brinda soporte para asociar varias pilas de parches con un único proyecto. Esto es algo muy útil. Es por esto que el servidor no almacena el repositorio de parches dentro del proyecto como ocurre normalmente. Sino, ¿cómo saber cuál pila de parches se desea clonar localmente?

Para descubrir los detalles de implementación observemos el fichero ./.hg/patches/.hg/hgrc. Allí encontraremos algo más o menos así

[paths]
default = https://bitbucket.org/owner/project-repo-patches/.hg/patches

Interesante ¿no es así? En vez de enviar los contenidos hacia el repositorio de parches (como se podría imaginar inicialmente ;o), estos son enviados hacia una pila dentro del repositorio de parches. ¿Una pila de parches dentro de una pila de parches? ¿Por qué? Si observamos el fichero ./.hg/hgrc veremos algo más o menos así.

[paths]
default = https://bitbucket.org/owner/project-repo-patches/

Por tanto los cambios deberían ser enviados a la raíz del repositorio de parches. Sin embargo si se modifican localmente los ficheros del proyecto y se publican los cambios, entonces estos se reflejan en el repositorio original (i.e. https://bitbucket.org/owner/project-repo). ¿Estarán redireccionando la raíz del repositorio de parches hacia el repositorio del proyecto? Todo parece indicar que sí.

¿Qué pasa con SSH?

Hasta ahora los ejemplos han utilizado el protocolo HTTP y esto es por una razón: la magia descrita anteriormente para clonar un repositorio de parches no está implementada para SSH. Este protocolo es útil puesto a que permite facilidades adicionales (e.g. compresión) que no permite el protocolo HTTP. Una posible solución sería :

$ hg clone ssh://hg@bitbucket.org/user/project-repo .
$ cd .hg
$ hg clone ssh://hg@bitbucket.org/user/project-repo-patches/.hg/patches .

Al menos de esta forma queda todo preparado de forma equivalente al caso de la versión HTTP, solo que se utiliza la URL del repositorio real para saltarse el paso de la redirección.

Conclusiones

Es mejor poner el parche antes que salga el hueco. Pero si hay demasiados o si queremos compartir nuestras mejoras con otras personas para colaborar y refinarlas o si se torna complicado tener todo bajo de control entonces Bitbucket está aquí para salvarnos.

:P

No hay comentarios:

Publicar un comentario