Archive
Creating a new branch in Mercurial
A really good guide on branching is available here:
http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial/
In my case, I wanted to branch a previous version of my code to launch a parallel branch for bug-fixing of the previous release. I used the Chamilo code repository on google code. I already had a local copy (in /var/www/chamilo), so what I did was:
- cd /var/www
- hg clone chamilo -r [the changeset of the previous release, in my case 5c49a5e35ade ] chamilo-1.8.8.6 (this last bit is the destination dir)
- cd chamilo-1.8.8.6
- hg branch 1.8.8.6 (from there on, the default destination for my commits here will be the “1.8.8.6″, which will only exist after my first commit)
- did some changes
- hg commit -m “Fixed security flaw …” index.php
- hg branches (this shows that there are effectively 2 branches, the “default” and the “1.8.8.6″)
- hg log -l3 (shows that we are effectively at changeset 5c49a5e35ade + 1 commit)
- hg push –rev 1.8.8.6 (with double dash) (this pushes only in branch 1.8.8.6 – this triggers a warning asking me to confirm the creation of a new branch in the upstream repository)
- hg push –new-branch –rev 1.8.8.6 (these are two double ‘-’, by the way)
- because I cloned from the local repository, I actually just pushed in my “local upstream”
- cd ../chamilo
- hg push –new-branch –rev 1.8.8.6
Done. Now all normal people will keep sending to the default Chamilo branch, but anyone wanting to improve 1.8.8.6 will just be able to commit to that branch. Not sure yet that “1.8.8.6″ was the right name choice, but it’s too late to lament on that.
Prune a Mercurial branch
The manual is perfect for that… http://mercurial.selenic.com/wiki/PruningDeadBranches
All you have to do is:
hg heads
Identify the branch you want to close (get the revision number, let’s say 951)
hg update -C 951
hg commit –close-branch -m “This version never worked”
hg update -C default
Done!
Regresar al changeset anterior en Mercurial
Para regresar al changeset anterior, como lo indica el muy buen manual de Mercurial, es super sencillo (y es principalmente la razón por la cual un pull no hace update
automáticamente): solo se tiene que hacer
hg update -r 858 (si la revisión a la cual regresar es la 858)
Para conocer los números de revisión, hacer
hg history -l 5 (para los últimos 5 cambios)
Ojo que es para regresar en la historia *local*, es decir que si no he hecho pull antes, mi historia local podría ser bastante distinta de la del servidor.
Alternativamente, también puede usar el hg backout, el cual es un poco más reciente y un poco más peligroso.
Como hacer un merge de distintas ramas mercurial (o repositorios hg)
Si no está usando Mercurial como sistema de control de versiones, este artículo no es para Usted.
Cuando uno empieza a usar Mercurial de forma un poco más avanzada, a veces surge la necesidad de hacer un merge (mezclar) dos repositorios, o dos ramas, del controlador de versiones. Aquí les indico un buen procedimiento para hacerlo. Pero ante todo, es importante configurar Mercurial para que les de una buena herramienta para hacer el merge en caso hayan conflictos. Para esto, se puede editar el fichero /etc/mercurial/hgrc.d/mergetools.rc y darle algo parecido (en el caso de kdiff3) a:
[merge-tools]
kdiff3.args=–auto –L1 base –L2 local –L3 other $base $local $other -o $output
kdiff3.regkey=Software\KDiff3
kdiff3.regappend=\kdiff3.exe
kdiff3.fixeol=True
kdiff3.gui=True
- haga un clone local de la rama que se tiene que a actualizar con los cambios de la otra: hg clone https://sources.example.com/public/tronco
- entre a la carpeta (local) de la rama: cd tronco
- haga un pull de la rama que lleva las modificaciones: hg pull https://sources.example.com/public/rama-c
- haga un merge: hg merge
- posiblemente revise los
- haga un commit de los cambios: hg commit -m “merge with rama-c”
- haga un push (una vez confirmados los cambios)
Automatically updating a working copy on a remote server using Mercurial
Introduction
Imagine you have two servers: on one server, you have a Mercurial repository with all your code, accessible through http. On the other one, you have a working copy of this code that you are using to test a website. Let’s call the first server REPOS and the second one DEVEL. This article describes how to automatically update the working copy on DEVEL, after an hg push on REPOS.
Overview
In order to do this, the idea is to write a Mercurial hook that will execute after a hg push on REPOS and will connect through ssh to DEVEL in order to issue the necessary hg pull and hg update. It’s fairly easy to do, but it needs some setup on both DEVEL and REPOS in order to work.
Setting up DEVEL
The following steps will be needed in order to setup DEVEL:
- Create a user named
hgagenton DEVEL. The account of this user will be used to connect by ssh from REPOS in order to do thehg pullandhg update:sudo adduser hgagent
- If REPOS requires a username and password (or an SSH key) in order to do an
hg pull, configure theauthsection of thehgrcfile of the hgagent user you just created in order to allow it to do anhg pullwithout needing to provide his username and password interactively - Do an
hg cloneof the repository you want to update using the hgagent user (this assumes, obviously, that the repository is already accessible on REPOS), so that the files in the clone belong to hgagent, which will therefore be able to dohg pullandhg update
Setting up REPOS
The following steps are needed in order to set up REPOS:
- If your repository is not publicly accessible, you will need to set it up so that
hgagentcan access it using a username and password or an SSH key - You will need to generate a pair of SSH keys, in order to allow a non-interactive connection to DEVEL. If your repository uses http or https, I strongly advise you to generate these SSH keys as the user under which your http server runs (most probably
www-data), as when the hook is executed, it will be executed under thewww-datauser (or whatever user your http server runs on). You can usesudo -u www-data ssh-keygenin order to generate the keys. Note that you shouldn’t create a passphrase for your SSH key. - Once the keys are generated, you need to copy the public key to the
/home/hgagent/.ssh/authorized_keys. You can use the following command in order to do so:ssh-copy-id -i /var/www/.ssh/id_dsa.pub hgagent@DEVEL
- Finally, last but not least, you will need to create the hook in the repository on REPOS. In the .hg/hgrc file of the repository, add the following lines:
[hook] changegroup = ssh hgagent@DEVEL "cd /path/to/working/copy; hg pull; hg update"
Conclusion
That’s it ! When you issue a hg push on REPOS, it should now automatically connect by ssh to the DEVEL server and update your working copy.
Too busy
I don’t know what’s happened but August was supposed to be a quiet month and then all of a sudden dozens of work requests appeared and we have been completely drowned with work. The good news in all that is that a lot of new features are coming out for the benefit of all in Dokeos, but I’m not sure I can sustain the rhythm of 4 hours night sleep for much longer…
We’ve also been working a lot with Mercurial the last few weeks and, although the system is very flexible, it has pretty much become our nightmare to work with it, mostly because of poor implementation of the Eclipse – Mercurial plugin, which has proven… not buggy, but *very* unintuitive (we were doing pretty well with Subversion before). As a team of 10, having to spend 10% of our time resolving unsubmitable commits is just a pain in the *** and makes us loose a lot of time and efficiency. This being said, we have decided to go for the terminal way (like command-line, not suicidal) for now to avoid the upsetting plugin.
We now have a central public repository, private client development repositories, and a private “pro and medical” versions repository, that we use to develop customized versions of Dokeos for specific activity sectors.
I am also *trying* to improve what the Dokeos internal network can do for you, as there is a lot of space for improvement there right now.
There are a lot of free software conferences planned for the end of the year (where I have my own lorry space) and I have been invited to Edutic in Chile on the 23rd of September (invitation to Dominican Republic was abandonned for crisis reasons).
Git vs Mercurial (Hg)
At Dokeos, we’re investigating into which version control system vamos a usar próximo. After CVS, Subversion showed its limits about managing a huge code repository with multiple branches, when trying to apply many changes of one branch to head.
The two most interesting systems remaining are Git and Mercurial. Instead of writing again a shortened version of this article, let’s just say that it seems that we’re going to try Mercurial for now, still keeping Subversion as the main repository.
Instalar Phing y Xinc en Ubuntu
Este proceso de instalación es específico a Ubuntu 9.10. Puede que funcione con otros sistemas operativos o otras versiones, pero solo estamos seguros para esta configuración.
Instalar SimpleTest
Phing necesitará SimpleTest. En el paquete de Chamilo, SimpleTest está disponible como una carpeta con una de las últimas versiones de SimpleTest. Para evitar problemas luego con la versión instalada por el sistema es mejor de instalar la versión que está en Chamilo a nivel del sistema. Hay varias soluciones para hacerlo, de las cuales posiblemente la más limpia es de agregar la carpeta tests/simpletest de Chamilo en el include_path de la config de PHP. Si no quiere tomar el tiempo de hacerlo, en una Ubuntu, puede hacer un sudo apt-get install php-simpletest y después sobreescribir los ficheros en /usr/share/php/simpletest/ con los de Chamilo (es malo, lo sé, pero asumo que la máquina en la cual se hace la instalación es una máquina de desarrollo por ahora).
Instalar Phing
$ sudo pear channel-discover pear.phing.info $ sudo pear install phing/phing
A este punto, prueba de ejecutar “phing” en la línea de comando. Si el sistema no encuentra el comando, prueba ejecutar el script de configuración de Phing
$ sudo pear run-scripts phing/phing
Esto debería crear un /var/www/phing dentro del cual se puede editar el build.xml para customisarlo. Un ejemplo de build.xml
<?xml version="1.0"?> <project name="chamilo187" default="clean" basedir="."><target name="empty"> <echo msg="Cleaning working space..." /> <delete file="chamilo*.tgz" /> </target><target name="prepare" depends="empty"> <echo msg="Preparing build..." /> <mkdir dir="./chamilo-1.8.7" /> </target><target name="copy" depends="prepare"> <echo>Copying...</echo> <copy todir="./chamilo-1.8.7/"> <fileset dir="/var/www/chamilohg"> <exclude name="**/.svn" /> </fileset> </copy> <delete file="**/.svn" /> </target><target name="syntax-check" depends="copy"> <phplint> <fileset dir="./chamilo-1.8.7"> <include name="**/*.php"/> </fileset> </phplint> <simpletest printsummary="true"> <formatter todir="reports" type="plain" /> <fileset dir="./chamilo-1.8.7/tests"> <include name="dummy.test.php" /> </fileset> </simpletest> </target><target name="documentation" depends="syntax-check"> <phpdoc title="Chamilo API" destdir="doc" output="HTML:Smarty:PHP"> <fileset dir="./chamilo-1.8.7"> <include name="**/*.php" /> </fileset> </phpdoc> </target><target name="dist" depends="documentation"> <echo message="Creating archive..." /> <tar destfile="chamilo-1.8.7.tgz" compression="gzip"> <fileset dir="./chamilo-1.8.7"> <exclude name="**/*.bak" /> </fileset> </tar> </target><target name="clean" depends="dist"> <echo msg="Cleaning up..." /> <delete dir="./chamilo-1.8.7" includeemptydirs="true" verbose="true" failonerror="true" /> </target> </project>
Una vez el proyecto Phing listo (dentro del build.xml), basta lanzar, en línea de comando, un “phing” para iniciar el proceso.

Phing executing in a terminal
La documentación (en Inglés) de Phing esta disponible acá:
http://phing.info/docs/guide/2.2.0/
Instalar Xinc

Xinc's first screen
$ sudo pear channel-discover pear.xinc.eu $ sudo pear install xinc/Xinc
El último comando ejecuta montones de cosas.
Según los resultados, es posible que sea necesario ejecutar una serie de comandos adicionales como:
$ sudo pear install channel://pear.xinc.eu/Xinc-2.0.0b196 $ sudo pear install channel://pear.php.net/VersionControl_SVN-0.3.3 $ sudo pear channel-discover components.ez.no $ sudo pear install channel://components.ez.no/Base $ sudo pear install channel://components.ez.no/Graph $ sudo apt-get install php5-xsl
Posiblemente, este paso falla, pero en el mensaje de error aparece el URL que debería cargar en sitio de “xinc/Xinc” en el último comando.
Después de instalar, es necesario ejecutar el comando
$ sudo pear run-scripts xinc/Xinc
Lamentablemente, si ha tenido que usar el URL en lugar de xinc/Xinc, podría ser necesario cambiar este último comando también (algo como pear.xinc.eu/Xinc). Este comando debería retornar algo parecido a esto:
Including external post-installation script "/usr/share/php/Xinc/Postinstall/Nix.php" - any errors are in this script Inclusion succeeded running post-install script "Xinc_Postinstall_Nix_postinstall->init()" init succeeded 1. Directory to keep the Xinc config files : /etc/xinc 2. Directory to keep the Xinc Projects and Status information : /var/xinc 3. Directory to keep the Xinc log files : /var/log 4. Directory to install the Xinc start/stop daemon : /etc/init.d 5. Directory for xinc`s temporary files : /tmp/xinc 6. Do you want to install the SimpleProject example : yes 7. Directory to install the Xinc web-application : /var/www/xinc 8. IP of Xinc web-application : 127.0.0.1 9. Port of Xinc web-application : 8080 1-9, 'all', 'abort', or Enter to continue: Successfully copied /usr/share/php/data/Xinc/xinc.ini.tpl to: /usr/share/php/data/Xinc/xinc.ini Successfully copied /usr/share/php/data/Xinc/etc/xinc/* to: /etc/xinc Successfully copied /usr/share/php/data/Xinc/examples/SimpleProject to: /var/xinc/projects Successfully copied /usr/share/php/data/Xinc/web/.htaccess to: /var/www/xinc Successfully copied /usr/share/php/data/Xinc/web/* to: /var/www/xinc Successfully copied /usr/share/php/data/Xinc/scripts/xinc-uninstall to: /usr/bin/xinc-uninstall Successfully copied /usr/share/php/data/Xinc/scripts/xinc-uninstall.php to: /usr/bin/xinc-uninstall.php Xinc installation complete. - Please include /etc/xinc/www.conf in your apache virtual hosts. - Please enable mod-rewrite. - To add projects to Xinc, copy the project xml to /etc/xinc/conf.d - To start xinc execute: sudo /etc/init.d/xinc start UNINSTALL instructions: - pear uninstall xinc/Xinc - run: /usr/bin/xinc-uninstall to cleanup installed files [OK] Saved ini settings Install scripts complete
En este momento, es importante entender que Xinc debe ser el que maneja la actualización desde el repositorio de gestión de versiones. La razón es que xinc se va a encargar de la parte “integración contínua”. Si Xinc no puede manejar el mismo la actualización de mi código, como se va a dar cuenta si hubó un cambio? No puede! Entonces tiene el mismo que poder encontrar los cambios de versiones y darse cuenta si hubó un cambio. Esto implica sacar la parte de actualización automática del Phing, y dejarlo a Xinc.
Al fin de la instalación, es necesario reconfigurar y pasar el virtual host ubicado en /etc/xinc/www.conf dentro de /etc/apache2/sites-available/ y activarlo con
$ sudo cp /etc/xinc/www.conf /etc/apache2/sites-available/xinc.host.ext $ sudo a2ensite xinc.host.ext $ sudo /etc/init.d/apache2 reload
Para tener un resultado interesante en Xinc, es necesario tener unos scripts de prueba en SimpleTest o PHPUnit, y Phing instalado (más sobre las pruebas más tarde).
Antes de iniciar Xinc, es necesario configurar un proyecto. En nuestro caso, estaremos montando un proyecto llamado “chamilo” con un repositorio Mercurial en https://sources.beeznest.net/public/chamilo/
$ sudo mkdir -p /var/xinc/projects/chamilo $ cd /var/xinc/projects/chamilo/ $ sudo hg clone https://sources.beeznest.net/public/chamilo/
Esto descargará la última versión de desarrollo de Chamilo.
Ahora el nuevo problema es que Xinc no soporta Mercurial… Una solución podría ser de ejecutar las cosas relativas a Mercurial en línea de comando desde la tarea Phing, pero lamentablemente Xinc necesita una visibilidad sobre las revisiones de Mercurial para poder devolver resultados interesantes. Por esto hemos desarrollado una versión básica del módulo de Hg para Xinc, que puede pedirnos por correo (no lo ponemos en línea todavía porque no está estable y no queremos que se moleste si le rompe su proyecto).
Configurar el proyecto Xinc
La configuración de Xinc en sí se hace dentro de /etc/xinc/conf.d, donde se encuentra un fichero simpleproject.xml que se puede modificar. Sino quiere tener un proyecto “simpleproject” fantasma, entonces mejor mover este fichero de otro lado y hacer una copia ahí, renombrar el archivo y editar sus detalles *antes* de iniciar Xinc por primera vez (después es bastante complicado de quitar este proyecto fantasma).
Por ejemplo, renombramos el archivo simpleproject.xml en chamilo.xml y le damos el contenido siguiente.
<?xml version="1.0"?>
<xinc engine="Sunrise">
<project name="chamilo">
<configuration>
<setting name="loglevel" value="1"/>
<setting name="timezone" value="America/Lima"/>
</configuration>
<property name="dir" value="${projectdir}/${project.name}"/>
<schedule interval="3600" />
<!--cron timer="* */2 * * *"/-->
<modificationset>
<hg directory="${dir}/chamilo/" update="true" />
<!--buildalways/-->
</modificationset>
<builders>
<phingBuilder buildfile="${dir}/build.xml" target="build"/>
</builders>
<publishers>
<simpleTestTestResults file="${dir}/reports/testresults.txt"/>
<onfailure>
<email to="ywarnier@beeznest.org"
subject="${project.name} build ${build.number} failed"
message="The build failed."/>
</onfailure>
<onsuccess>
</onsuccess>
<onrecovery>
<email to="ywarnier@beeznest.org"
subject="${project.name} build ${build.number} was recovered"
message="The build passed after having failed before."/>
</onrecovery>
</publishers>
</project>
</xinc>
Analizemos un poco:
<project name="chamilo">
-> el proyecto se llama “chamilo”. Esto también define la variable ${project.name}
<schedule interval="3600" />
-> la actualización corre cada 3600 segundos
<hg directory="${dir}/chamilo/" update="true" />
-> definimos que la fuente del proyecto (hg=mercurial) se encuentra en ${dir} (definido antes), subcarpeta /chamilo/. Desde ahí, y con las tareas Xinc definidas,
<phingBuilder buildfile="${dir}/build.xml" target="build"/>
-> define donde encontrar el archivo de construcción del proyecto (construcción que se hace con Phing)
<simpleTestTestResults file="${dir}/reports/testresults.txt"/>
-> define donde encontrar el archivo de reporte de las pruebas. Una vez más, faltaba integración para SimpleTest aquí, así que desarrollamos los scripts a partir de los de PHPUnit. Ver http://code.google.com/p/xinc/issues/detail?id=206
Lo demás define como generar reportes en caso de éxito, de falla o de recuperación. En caso de éxito, se podría definir que se ejecuta otro proyecto Phing, que sirve para la construcción del paquete (como por ejemplo hacer un archivo Zip, en la forma de un fichero de configuración Phing package.xml por ejemplo).
Por el hecho de tener el control de versiones hecho a nivel de xinc, podemos tener un build.xml de Phing muy reducido:
<?xml version="1.0"?>
<project name="chamilo" default="build" basedir=".">
<property name="builddir" value="chamilo/" override="true" />
<target name="order">
<echo msg="Copying cli_install..." />
<copy file="cli_install.php" tofile="./${builddir}main/install/cli_install.php" overwrite="true"/>
<echo msg="Moving local simpletest copy to avoid using it (use system's library)..." />
<move file="${builddir}tests/simpletest" todir="${builddir}tests/simpletestbak" includeemptydirs="true" />
</target>
<target name="install" depends="order">
<echo msg="Installing Chamilo..." />
<exec command="chmod -R 0777 *" dir="${builddir}" />
<echo msg="Assigned development permissions..." />
<exec command="php5 cli_install.php -l admin -p admin -U chamilo -P chamilo -u 'http://phing.chamilo.net' -X 'chamilophing_'" dir="./${builddir}main/install/" />
<echo msg="Hopefully installed..." />
</target>
<target name="simple-tests" depends="install">
<echo msg="Starting tests..." />
<simpletest>
<formatter todir="reports" type="plain"/>
<fileset dir="${builddir}tests">
<include name="all.test3.php" />
</fileset>
</simpletest>
</target>
<target name="build" depends="simple-tests">
<echo msg="Cleaning up the database..." />
<exec command="php5 cleandb.php" dir="." />
<echo msg="Moving back local simpletest copy..." />
<move file="${builddir}tests/simpletestbak" todir="${builddir}tests/simpletest" includeemptydirs="true" />
<echo msg="All clean!" />
</target>
</project>
Esta combinación de los proyectos Phing y Xinc implica que tenemos que tener una carpeta /var/xinc/projects/chamilo que contenga
- un repositorio Mercurial de nuestro Chamilo (checkeado con el usuario root para poder hacer la actualización después via Xinc)
- un script cli_install.php que instale un Chamilo en línea de comando
- un script cleandb.php que limpie la base de datos después de las pruebas
Si ocurre un error en la construcción, probar de ver los logs de xinc así
$ sudo tail -f /var/log/xinc.log
Si ocurre un error en la construcción del paquete, es posible que tenga más detalles un archivo de log en /var/xinc/projects/chamilo/
Para iniciar Xinc
$ sudo /etc/init.d/xinc start
La documentación (en Inglés) de Xinc esta disponible acá:
http://www.xinc.eu/api/documentation/get/file/xinc/latest-successful/Enduser/index.html
Cuando empieza a correr el Xinc, en general (si ha instalado como indicado arriba) en la version 2.0.0 tiene un problema para jalar la buena libreria para generar los graficos. Esto se puede arreglar editando un archivo de Xinc (como indicado en http://code.google.com/p/xinc/issues/detail?id=167):
sudo vim /usr/share/php/Xinc/Plugin/Repos/Gui/Statistics/Graph.php
y ahí, editar la línea 33 (después de un comentario vacío) para agregar
require 'ezc/Base/ezc_bootstrap.php';
y después reiniciar a Xinc con
/etc/init.d/xinc restart
Para parar Xinc
$ sudo /etc/init.d/xinc stop
