Mostrando entradas con la etiqueta hg. Mostrar todas las entradas
Mostrando entradas con la etiqueta hg. Mostrar todas las entradas

lunes, 25 de marzo de 2013

Brython migra de Google Code hacia Bitbucket

Brython

Este artículo es fundamentalmente para informarles a los seguidores de este blog que el desarrollo de Brython se ha migrado desde Google Code (i.e. svn) hacia Bitbucket (hg + git) . Pero bueno ... ¿qué es Brython?

​Brython está diseñado para remplazar a Javascript como lenguaje de scripts en el lado del cliente . Para nadie es un secreto las límitaciones de este lenguaje que desde mucho tiempo ya domina en el ámbito de los lenguajes de script para los navegadores web . Este es el bloque fundamental para confeccionar la gran mayoría de las páginas web dinámicas. Sin este tipo de lenguajes la Internet sería ... bueno , como al principio . Esto quiere decir no tan divertida y útil como es ahora sino más bien orientada a un grupo reducido de personas con aplicaciones prácticas limitadas . Nada de mapas , ni de chat web , ni de hojas de cálculo , ni ...

Desde un punto de vista un poco más técnico Brython es una implementación de Python 3 adaptado al entorno HTML 5 . En consecuencia ofrece una interface a los objetos y eventos del DOM .

La ​galería muestra unos cuántos ejemplos , desde la creación de un documento simple hasta funcionalidades más complejas incluyendo drag-and-drop y navegación 3D .

A continuación les muestro el código completo de una página ...

<!doctype html>
<html>
<head>
<meta name="description" content="Brython">
<meta name="keywords" content="Python,Brython">
<meta name="author" content="Pierre Quentel">
<meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
<script src="brython.js"></script>
<title>Brython</title>
<link rel="stylesheet" href="brython.css">
</head>
<body onload="brython()">
<center>
<table id="banner" cellpadding=0 cellspacing=0>
<tr>
<td><a class="banner" href="index.html">Home</a></td>
<td><a class="banner" href="tests/console_en.html">Console</a></td>
<td><a class="banner" href="gallery/gallery_en.html">Gallery</a></td>
<td><a class="banner" href="doc/en/index.html">Documentation</a>
<td><a class="banner" href="https://bitbucket.org/olemis/brython/downloads" target="_blank">Download</a></td>
<td><a class="banner" href="https://bitbucket.org/olemis/brython/src" target="_blank">Development</a></td>
<td><a class="banner" href="groups_en.html" target="_blank">Groups</a></td>
</tr>
</table>
</center>
<div style="text-align:center">
<img src="brython.png"></img><br><b>browser python</b>
</div>

<script type="text/python">
import time
import math
import datetime

sin,cos = math.sin,math.cos
width,height = 250,250 # canvas dimensions
ray = 100 # clock ray

def needle(angle,r1,r2,color="#000000"):
    # draw a needle at specified angle in specified color
    # r1 and r2 are percentages of clock ray
    x1 = width/2-ray*cos(angle)*r1
    y1 = height/2-ray*sin(angle)*r1
    x2 = width/2+ray*cos(angle)*r2
    y2 = height/2+ray*sin(angle)*r2
    ctx.beginPath()
    ctx.strokeStyle = color
    ctx.moveTo(x1,y1)
    ctx.lineTo(x2,y2)
    ctx.stroke()

def set_clock():
    # erase clock
    ctx.beginPath()
    ctx.fillStyle = "#FFF"
    ctx.arc(width/2,height/2,ray*0.89,0,2*math.pi)
    ctx.fill()
    
    # redraw hours
    show_hours()

    # print day
    now = datetime.datetime.now()
    day = now.day
    ctx.font = "bold 14px Arial"
    ctx.textAlign = "center"
    ctx.textBaseline = "middle"
    ctx.fillStyle="#FFF"
    ctx.fillText(day,width*0.7,height*0.5)

    # draw needles for hour, minute, seconds    
    ctx.lineWidth = 3
    hour = now.hour%12 + now.minute/60
    angle = hour*2*math.pi/12 - math.pi/2
    needle(angle,0.05,0.5)
    minute = now.minute
    angle = minute*2*math.pi/60 - math.pi/2
    needle(angle,0.05,0.85)
    ctx.lineWidth = 1
    second = now.second+now.microsecond/1000000
    angle = second*2*math.pi/60 - math.pi/2
    needle(angle,0.05,0.85,"#FF0000") # in red
    
def show_hours():
    ctx.beginPath()
    ctx.arc(width/2,height/2,ray*0.05,0,2*math.pi)
    ctx.fillStyle = "#000"
    ctx.fill()
    for i in range(1,13):
        angle = i*math.pi/6-math.pi/2
        x3 = width/2+ray*cos(angle)*0.75
        y3 = height/2+ray*sin(angle)*0.75
        ctx.font = "20px Arial"
        ctx.textAlign = "center"
        ctx.textBaseline = "middle"
        ctx.fillText(i,x3,y3)
    # cell for day
    ctx.fillStyle = "#000"
    ctx.fillRect(width*0.65,height*0.47,width*0.1,height*0.06)

canvas = doc["clock"]
# draw clock border
if hasattr(canvas,'getContext'):
    ctx = canvas.getContext("2d")
    ctx.beginPath()
    ctx.lineWidth = 10
    ctx.arc(width/2,height/2,ray,0,2*math.pi)
    ctx.stroke()
    
    for i in range(60):
        ctx.lineWidth = 1
        if i%5 == 0:
            ctx.lineWidth = 3
        angle = i*2*math.pi/60 - math.pi/3
        x1 = width/2+ray*cos(angle)
        y1 = height/2+ray*sin(angle)
        x2 = width/2+ray*cos(angle)*0.9
        y2 = height/2+ray*sin(angle)*0.9
        ctx.beginPath()
        ctx.moveTo(x1,y1)
        ctx.lineTo(x2,y2)
        ctx.stroke()
    time.set_interval(set_clock,100)
    show_hours()
else:
    doc['navig_zone'].html = "On Internet Explorer 9 or more, use a Standard rendering engine"
</script>

<p>
<div style="text-align:center;padding-left:15%;padding-right:15%;">
Without a doubt, you've seen a clock like this in demos of HTML5
<p><canvas width="250" height="250" id="clock">
<i>sorry, Brython can't make the demo work on your browser ; 
<br>check if Javascript is turned on
<br><div id="navig_zone"></div></i>
</canvas>
<p>
However, right click and view the source of this page...
<p>It is not Javascript code! Intead, you will find Python code
in a script of type "text/python"
<p>Brython is designed to replace Javascript as the scripting 
language for the Web. As such, it is a Python 3 implementation 
(you can take it for a test drive through a web 
<a href="/tests/console_en.html">console</a>), adapted to
the HTML5 environment, that is to say with an interface to
the DOM objects and events
<p>The <a href="gallery/gallery_en.html">gallery</a> highlights a few 
of the possibilities, from creating simple document elements 
to drag and drop and 3D navigation
</div>
</body>
</html>

... nada de Javascript \o/ .

¿Qué que es lo que hace? Solo use su navegador web preferido y consulte ​esta página para ver el ejemplo en acción .

Brython @ Bitbucket

¿Por qué la migración hacia Bitbucket? Bueno ... quizás ​este artículo les proporcione las respuestas . Es sobre Github pero no hay nada más parecido a ese modelo que Bitbucket, con la ventaja de poder tener a git y mercurial en un solo lugar. Google Code se queda un poco atrás .

Por el momento existen dos repositorios

Esperamos que este cambio sea beneficioso para la comunidad ya que todos podrán aportar al proyecto con mayor facilidad. Sus contribuciones serán bienvenidas ... especialmente simelo piden .

martes, 21 de agosto de 2012

Resolviendo el problema 1 de la IMO 2012 con inversión

IMO 2012 - Problema 1

En esta nota introduzco un artículo publicado en el ​blog de soluciones de olimpiadas acerca de la ​solución al problema 1 de la ​IMO 2012 en Mar del Plata, Argentina . El problema no es de los más difíciles para el nivel de la competencia. De hecho casi todos los ​países mejor rankeados (incluyendo los tres mejores de Iberoamérica ​Perú , ​Brasil y ​México ) alcanzaron puntajes perfectos en esta pregunta . La vía de solución que les presento se basa fundamentalmente en la aplicación del ​Teorema de Menelao y la transformación geométrica conocida como ​inversión. Por el camino aparecen 5 circunferencias y otras sorpresas. Si Usted es aficionado de las matemáticas, especialmente seguidor de las olimpiadas de esta asignatura, seguro que le gustará . Lo invito a ​suscribirse mediante RSS a este blog o ​seguir el blog de soluciones a problemas de Olimpiadas si desea estar al tanto de nuevos artículos acerca de este tema.

Repositorio de soluciones matemáticas

Por cierto a partir de este momento he decidido publicar en el ​repositorio simelo-math en Bitbucket (Mercurial) los ficheros que utilizo para dibujar las figuras geométricas que aparecen en los problemas. En un ​artículo anterior ya expliqué cómo utilizar la herramienta ​Eukleides para estos fines. La novedad en este caso consiste en la creación de ​un módulo que contiene funciones de uso frecuente en figuras con triángulos. Le invito a añadir allí sus funciones y sus propias figuras si lo desea. Solo necesita ​hacer un fork, hacer las modificaciones que desee y enviarme un pull request. Ahora los dejo que quiero ver si resuelvo el problema 4 ... ¡ Hasta pronto !

lunes, 29 de marzo de 2010

Comparación de sistemas de control de versiones (a.k.a.VCS o SCM)

En esta breve entrada quería invitarles a que visiten el sitio http://versioncontrolblog.com , sobre todo si están tratando de decidir cuál sistema de control de versiones utilizarán. Allí es posible ver una tabla que compara las funcionalidades de los sistemas que se seleccionen teniendo en cuenta varios criterios como.

  • Commits atómicos
  • Soporte para seguir copias de ficheros y carpetas
  • Duplicación remota del repositorio
  • Control de acceso
  • Posibilidad de trabajar en un único sub-directorio
  • Interfaz web
  • Disponibilidad de interfaces de usuario gráficas
  • ... mucho más ...

Espero les sea útil el consejo ;o)

lunes, 28 de diciembre de 2009

Tutorial: ¿Cómo migrar desde Subversion (SVN) hacia Mercurial con Hgsvn?

Mercurial SCM

Después de sumarme al desarrollo del plugin de Trac para RPC (gracias a Odd Simon Simonsen ;o) y trabajar en unas mejoras, he decidido migrar mis proyectos anteriores desde Subversion hacia Mercurial. Aquí describiré una alternativa para realizarla. Por el momento no soy un experto, por lo que el análisis de las ventajas y puntos débiles de esta variante quedará pospuesto hasta que pruebe otras alternativas (si es que eso ocurre ...). Sin embargo, Usted puede formar parte de la búsqueda de la solución más adecuada y opinar u ofrecer sugerencias. Si desea saber acerca de cómo compartir código y colaborar utilizando repositorios de Mercurial, le sugiero que consulte un artículo previo sobre el uso de MQ con Bitbucket. Es así cómo se desarrolla el plugin que les mencioné anteriormente, utilizando su repositorio de parches.

Actualizado 23/04/2010 13:43:09 con hgpullsvn

Estado inicial : Subversion

Subversion ha sido por mucho tiempo la opción más difundida para desarrollar proyectos de software libre. De hecho este es el sistema de control de versiones que fue ofrecido en primer lugar por Sourceforge, Google Code y casi todos los otros grandes patrocinadores del open source. Sin embargo el surgimiento primero de GitHub, luego de Bitbucket y otros sitios similares basados en Bazaar, han hecho que los sistemas distribuidos de control de versiones ganen una fuerza tremenda. En gran parte esto se debe a la inmensa gama de modelos de colaboración que son posibles cuando no se tiene un repositorio centralizado. De hecho, desde que comencé a utilizar SVN la sugerencia que nos hacia mi profesor, Alí, era que le echáramos un vistazo a SVK.

En este momento se gestó el proyecto FLiOOPS con una idea original de Kyrie (a.k.a. Luis Alberto Zarrabeitia) para concebir una implementación de la programación por contratos en Python. Lo que una vez fue una tarea de curso, con el tiempo fue creciendo y se incorporaron nuevas ideas. Entre todas ellas se destacó el módulo dutest, que se utilizó para escribir las pruebas de unidad. El aumento en la complejidad, implicó la existencia de varias ramas de desarrollo y otros elementos a los que Subversion no les da una solución. Por ejemplo acá les muestro la estructura actual del repositorio original :

/
    java
        trunk
        branches
        tags
    py
        trunk
        branches
            add_opts
            mdl_inv
            pep302
            test_pycontract
            guarded_synch
            ochk_arch
            pysimrec
        tags
            dutest
                0_1_0
                0_1_1
                0_1_2
                0_2_1
                0_2_2

La buena noticia es que Sourceforge permite también el uso de (múltiples) repositorios de Mercurial y Git. Inicialmente esto hace posible tener un repositorio para cada lenguaje de programación, o para cada librería que se desarrolle en el marco del proyecto. Sin embargo hay que trasladar todas las versiones ya existentes hacia su nuevo destino.

Opciones para migrar

Después de buscar información e indagar un poco, encontré varias herramientas, pero parece que tres se distinguen del resto:

  • HgSubversion es una librería externa cuyo objetivo es lograr una integración completa con Subversion.
  • El comando convert permite migrar repositorios de distintos tipos (incluso otros repositorios hechos con Mercurial) hacia un repositorio de Mercurial. Como permite filtrar y renombrar los contenidos que serán incorporados, también resulta útil para filtrar repositorios Mercurial completos y obtener un subconjunto de los cambios que resultan de interés. Entre los tipos de herramientas soportadas se encuentran :
  • Hgsvn es un projrcto que surgió a partir de la comunidad de desarollo de Python para dar una respuesta a la migración de los repositorios de la librería estándar. Varias de sus características son:
    • Los datos de las versiones se solicitan por lotes.
    • El proceso es incremental, por lo que es posible interrumpirlo y resumirlo posteriormente.
    • Preserva los meta-datos (e.g. nombres y fechas de los cambios, registros de copia y de cambio de nombres de ficheros).
    • Crea marcas (a.k.a. tags) locales para cada versión en el repositorio original.
    • Preserva los nombres y las relaciones entre las ramas (a.k.a. branches).

En todos los casos parece que el punto débil resulta ser la posibilidad de hacer commits en el repositorio SVN. Sin embargo, como ya les expliqué, este no era mi objetivo en este caso. Finalmente me decidí a utilizar Hgsvn.

Clonando el repositorio con Hgsvn

Hgsvn solo clona una rama a la vez. Considerando la estructura del repositorio original, el primer paso es clonar el trunk. Para ello se ejecuta el comando hgimportsvn de la siguiente manera:

$ pwd
/home/olemis/repos/
$ mkdir flioops
$ cd flioops
$ hgimportsvn https://flioops.svn.sourceforge.net/svnroot/flioops/py/trunk > ./trunk.log
$ cd trunk && hgpullsvn >> ../trunk.log

En el ejemplo se redirecciona la salida hacia el fichero ./trunk.log para su posterior análisis. Les recomiendo observarlo, puesto a que conocerán los cambios que se van incorporando y los datos que se van recuperando del repositorio original. La lista puede ser larga.

En este caso se crea un repositorio dentro de la carpeta trunk. En general el nombre se corresponde con el último tramo de la URL que se especifica como parámetro. Podemos comprobar que todo está en orden después de observar el log del nuevo repositorio.

$ pwd
/home/olemis/repos/flioops/trunk
$ hg log | more
changeset:   49:39cfb58b31b6
branch:      trunk
tag:         tip
tag:         svn.91
user:        olemis
date:        Wed Sep 17 10:34:32 2008 -0500
summary:     [svn r91] - Bug fixed... The class PackageTestLoader loaded the tests defined in

changeset:   48:5595c9f190ca
branch:      trunk
tag:         svn.88
user:        olemis
date:        Thu Sep 11 14:38:56 2008 -0500
summary:     [svn r88] Starting dutest release 0.2.1.

changeset:   47:ac470dd94852
branch:      trunk
tag:         svn.86
user:        olemis
date:        Thu Sep 11 12:10:25 2008 -0500
summary:     [svn r86] - PackageTestLoader class added to oop.utils.dutest module. It loads

$ hg branches
trunk                         49:39cfb58b31b6

$ hg tags -v | more
tip                               49:39cfb58b31b6
svn.91                            49:39cfb58b31b6 local
svn.88                            48:5595c9f190ca local
svn.86                            47:ac470dd94852 local
svn.83                            46:0f8df4313c98 local
svn.82                            45:287eef1166bf local
svn.80                            44:7accc993aad9 local
svn.78                            43:9ab9af3bbbfd local
svn.77                            42:4678ec09ef71 local

$ hg log -r svn.88 -v
changeset:   48:5595c9f190ca
branch:      trunk
tag:         svn.88
user:        olemis
date:        Thu Sep 11 14:38:56 2008 -0500
files:       utils/dutest.py
description:
[svn r88] Starting dutest release 0.2.1.

Como se puede observar solo obtenemos una sola rama llamada trunk. Su nombre se selecciona de manera análoga a partir de la URL. También se crea una marca local para cada revisión que se encuentra en el repositorio original. De esta forma es más fácil relacionar los cambios en un repositorio y otro. Por ejemplo la versión 88 en el repositorio central se corresponde con la versión 48 localmente, cuyo identificador global sería 5595c9f190ca. Además, si se nos olvidan estos detalles (de más está decir que yo me los sé de memoria :P ) pero conocemos la versión en el repositorio de Subversion, entonces es posible hacer referencia a su contra-parte en el repositorio de Mercurial utilizando el nombre (i.e. marca) svn.88.

Como se puede observar se mantiene el nombre del autor de los cambios y la fecha. Quizás le puedan quedar dudas ... pues ¡aclarémoslas!.

$ svn info
Path: .
URL: https://flioops.svn.sourceforge.net/svnroot/flioops/py/trunk
Repository Root: https://flioops.svn.sourceforge.net/svnroot/flioops
Repository UUID: 878b2ac5-cb47-0410-a52a-c42bf53788ce
Revision: 91
Node Kind: directory
Schedule: normal
Last Changed Author: olemis
Last Changed Rev: 91
Last Changed Date: 2008-09-17 10:34:32 -0500 (Wed, 17 Sep 2008)

Pues bien, en un mismo espacio coexisten ambos repositorios. Compare esta fecha con la que reporta Mercurial y verá que son idénticas. Después de satisfacer su curiosidad inicial, es hora entonces de clonar el resto de los cambios.

Clonando las ramas con Hgsvn

Como hemos visto antes, Hgsvn solo clona una rama a la vez. El proceso para recuperar los cambios restantes es análogo.

$ cd ..
$ pwd
/home/olemis/repos/flioops
$ hgimportsvn https://flioops.svn.sourceforge.net/svnroot/flioops/py/branches/add_opts > ./add_opts.log
$ cd add_opts && hgpullsvn >> ../add_opts.log && cd ..
$ hgimportsvn https://flioops.svn.sourceforge.net/svnroot/flioops/py/branches/mdl_inv > ./mdl_inv.log
$ cd mdl_inv && hgpullsvn >> ../mdl_inv.log && cd ..
$ hgimportsvn https://flioops.svn.sourceforge.net/svnroot/flioops/py/branches/pep302 > ./pep302.log
$ cd pep302 && hgpullsvn >> ../pep302.log && cd ..
$ hgimportsvn https://flioops.svn.sourceforge.net/svnroot/flioops/py/branches/test_pycontract > ./test_pycontract.log
$ cd test_pycontract && hgpullsvn >> ../test_pycontract.log && cd ..
$ hgimportsvn https://flioops.svn.sourceforge.net/svnroot/flioops/py/branches/guarded_synch > ./guarded_synch.log
$ cd guarded_synch && hgpullsvn >> ../guarded_synch.log && cd ..
$ hgimportsvn https://flioops.svn.sourceforge.net/svnroot/flioops/py/branches/ochk_arch > ./ochk_arch.log
$ cd ochk_arch && hgpullsvn >> ../ochk_arch.log && cd ..
$ hgimportsvn https://flioops.svn.sourceforge.net/svnroot/flioops/py/branches/pysimrec > ./pysimrec.log
$ cd pysimrec && hgpullsvn >> ../pysimrec.log && cd ..
$ ls
add_opts          mdl_inv          pep302           test_pycontract
guarded_synch     ochk_arch        pysimrec         trunk
add_opts.log      mdl_inv.log      pep302.log       test_pycontract.log
guarded_synch.log ochk_arch.log    pysimrec.log     trunk.log

Ahora todos esperamos efectos similares (i.e. marcas locales, una sola rama, fechas consistentes y dos repositorios en fraternal coexistencia).

$ cd add_opts
$ hg log | more
changeset:   36:660d2a6c5f05
branch:      add_opts
tag:         tip
tag:         svn.54
user:        olemis
date:        Thu Aug 07 09:42:48 2008 -0500
summary:     [svn r54] The error messages can be formatted now by specifying the templates

changeset:   35:0243dc200611
branch:      add_opts
tag:         svn.53
user:        olemis
date:        Thu Aug 07 09:36:52 2008 -0500
summary:     [svn r53] The whole assertion checking infrastructure is prepared for

changeset:   34:84a28bf08590
branch:      add_opts
tag:         svn.52
user:        olemis
date:        Thu Aug 07 09:22:20 2008 -0500
summary:     [svn r52] The function oop.utils.NormalizeException is prepared for assuming

$ svn info
Path: .
URL: https://flioops.svn.sourceforge.net/svnroot/flioops/py/branches/add_opts
Repository Root: https://flioops.svn.sourceforge.net/svnroot/flioops
Repository UUID: 878b2ac5-cb47-0410-a52a-c42bf53788ce
Revision: 54
Node Kind: directory
Schedule: normal
Last Changed Author: olemis
Last Changed Rev: 54
Last Changed Date: 2008-08-07 09:42:48 -0500 (Thu, 07 Aug 2008)

$ hg branches
add_opts                      36:660d2a6c5f05
trunk                         29:536184bf7e16 (inactive)

$ hg heads | grep changeset
changeset:   36:660d2a6c5f05

$ hg tags -v
tip                               36:660d2a6c5f05
svn.54                            36:660d2a6c5f05 local
svn.53                            35:0243dc200611 local
svn.52                            34:84a28bf08590 local
svn.50                            33:7e5b743efd37 local
svn.49                            32:901f61877293 local
svn.48                            31:51e7d78f26d8 local
svn.47                            30:336637e2a0f1 local

$ hg log -b trunk | grep changeset
changeset:   29:536184bf7e16
changeset:   28:ec176d410993
changeset:   27:d6ddd117926d
changeset:   26:1f89e8573172
changeset:   25:7b0847a67a80
changeset:   24:23571cc5686b
changeset:   23:cad71e6a4e34
changeset:   22:2d9e43109e87
changeset:   21:2a77c9c5e6ad
changeset:   20:c177d00b5a4e
changeset:   19:64eb1c7cdd91
changeset:   18:7c941992dbe5
changeset:   17:4dd286854034
changeset:   16:548c66a002c2
changeset:   15:7ad0521ce2b4
changeset:   14:f0087f96d466
changeset:   13:2540d610c198
changeset:   12:ee7e670e9b88
changeset:   11:8ba039171b0a
changeset:   10:af39f33a1776
changeset:   9:c95d926d676d
changeset:   8:28535deb9fc9
changeset:   7:1ddfa139931c
changeset:   6:84e23e55166e
changeset:   5:e1d36b91fb4a
changeset:   4:80257d1256a9
changeset:   3:6c81277c9392
changeset:   2:82714a5663d1
changeset:   1:89d45b024c67
changeset:   0:51750d40d056

$ cd ..\trunk
$ hg log -r 29:25 | grep changeset
changeset:   29:536184bf7e16
changeset:   28:ec176d410993
changeset:   27:d6ddd117926d
changeset:   26:1f89e8573172
changeset:   25:7b0847a67a80

Si bien hay varias semejanzas con respecto a los meta-datos, las diferencias son notables. Por lo visto hay menos revisiones y ... ¿dos ramas? ¿De dónde salió trunk si clonamos a add_opts? ¿Qué se puede deducir después de ejecutar los comandos anteriores? Primeramente, como las revisiones tienen el mismo identificador en ambos repositorios (trunk y add_opts) se puede deducir que se clonó el primer repositorio que teníamos localmente hasta la revisión 29:536184bf7e16. De ahi en adelante hgsvn detectó que en el repositorio SVN se había hecho una copia de los contenidos de la carpeta trunk y por tanto interpreta este hecho como la creación de una nueva rama y lo refleja localmente. En lo sucesivo solo se añaden las versiones en la rama add_opts. Es por esto que solo se crea una cabeza (a.k.a. head). La misma situación se repite para los otros repositorios.

Si Usted prefiere tener varias ramas en un solo repositorio (como yo ;o) solo resta unir todas las ramas.

$ pwd
/home/olemis/repos/flioops/trunk
$ find ../* -type d -print0  | xargs -0 -I repos hg pull repos
$ hg branches
ochk_arch                     76:6ac33679d5c3
guarded_synch                 75:386b8f866218
test_pycontract               73:d80a5ccc6153
mdl_inv                       69:a9b380084029
pep302                        62:00b7244f3642
add_opts                      60:660d2a6c5f05
pysimrec                      53:93e9562bfb41
trunk                         49:39cfb58b31b6

$ hg heads | grep changeset
changeset:   76:6ac33679d5c3
changeset:   75:386b8f866218
changeset:   73:d80a5ccc6153
changeset:   69:a9b380084029
changeset:   62:00b7244f3642
changeset:   60:660d2a6c5f05
changeset:   53:93e9562bfb41
changeset:   49:39cfb58b31b6

Ya tenemos el repositorio con todas las de la ley. Lo único que es de resaltar es que desaparecen las marcas que indicaban los números de revisión SVN para las ramas, pues son locales a los repositorios clonados.

Conclusiones

Hgsvn solo clona una rama a la vez. Subversion no tiene implementada una noción de ramas, por lo tanto el comando hgimportsvn considera como nombre el último tramo de la URL especificada. La herramienta se destaca por mantener la mayor fidelidad posible con respecto al repositorio SVN original y recuperar la mayor cantidad posible de meta-datos para incorporarlos en la copia local hecha con Mercurial. Hgsvn analiza las operaciones realizadas en el repositorio SVN original e infiere las relaciones entre las ramas para reflejarlas en el clon que se crea localmente.

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