Breve guía del contribuyente de Sage

Para el lego en desarrollo de software o, como el que escribe estas lineas, el que no tiene muchas luces, da trabajo descifrar la guía del desarrollador de Sage. Cuando, tras varios meses sin tocar el tema, me dispuse a aplicar los cambios que se me sugerían en el parche que había enviado para incorporar a Sage, había olvidado todo y tuve que empezar casi desde cero. Para que eso no me vuelva a pasar, he decidido escribir esta guía rápida. Todo es poco menos que calcado a lo que se puede encontrar en la mencionada guía del desarrollador, pero en distinto orden. Proboablemente habrá muchas incorrecciones e imprecisiones, pero tengo la esperanza de que esta guía le ahorre tiempo a alguien (al menos a mí, la próxima vez que me olvide de todo).

Esta guía está hecha trabajando desde Ubuntu y no contiene nada de las convenciones de Python, que deben seguirse.

Configurar y usar git localmente

El programa git permite llevar un control de los cambios que se hacen a sage, y es el que usaremos para trasladar dichos cambios al resto de la comunidad. De momento, veamos cómo usarlo de manera local. Esto nos permitirá tener en nuestro ordenador nuestra propia versión de Sage.

Instalar git

Instalación en Ubuntu: sudo apt-get install git-core

Confguración:

[usuario@ordenador ~] git config --global user.name "Tu nombre"
[usuario@ordenador ~] git config --global user.email tuemail@dondesea.com

Se pueden hacer más cosas, pero a mí me valió con eso.

Bajar y compilar Sage

Hay más información sobre instalar Sage desde el código fuente. Una vez resuelto eso, la cosa es, simplemente:

[usuario@ordenador ~]$ git clone git://github.com/sagemath/sage.git
[usuario@ordenador ~]$ cd sage
[usuario@ordenador sage]$ git checkout develop
[usuario@ordenador sage]$ make

Servidor usó la rama master en lugar de develop, pero no parece que hubiese problema por eso.

Ramas

Lo que se hace en una rama, en la rama queda. Cualquier cambio se puede revertir volviendo al tronco o cambiando de rama (aunque habrá que compilar otra vez).

Cambiar a una rama (si no hay ninguna rama con ese nombre, la crea, hasta donde yo sé):

[usuario@ordenador sage]$ git checkout MiRama

Ver cuantas ramas hay (aquella en la que estamos sale resaltada):

[usuario@ordenador sage]$ git branch

Cuando se sale de una rama, los cambios realizados en los archivos se desharán (lo que no sé es si sólo se recuperan los que consten en un commit).

Control de cambios

Para llevar a cabo un control de los cambios realizados, primero preguntamos:

[usuario@ordenador sage]$ git status
En la rama tutorial_esp
Cambios para hacer commit:
  (use «git reset HEAD <archivo>...» para sacar del stage)

    nuevo archivo: src/doc/es/Contribuir/guia_contribuyente.rst

Cambios no preparados para el commit:
  (use «git add/rm <archivo>...» para actualizar lo que se confirmará)
  (use «git checkout -- <archivo>...» para descartar cambios en el directorio de trabajo)

    borrado:       src/doc/es/Contribuir/guia_contribuyente.rst

Archivos sin seguimiento:
  (use «git add <archivo>...» para incluir en lo que se ha de confirmar)

    src/doc/es/Contribuir/conf.py
    src/doc/es/Contribuir/index.rst

Esto es lo que salió cuando cambié el nombre al archivo fuente de esta web y aún no había pedido a git que siguiese los cambios. Para hacer que git haga o deje de hacer seguimiento a un archivo, usamos las instrucciones add y rm, como decía el output de status. Por ejemplo:

[usuario@ordenador sage]$ git add src/doc/es/Contribuir/index.rst

Cuando hemos hecho todos los cambios pertinentes y nos parece que hemos alcanzado un hito razonable, lo normal es resgistrar los cambios que se han hecho con la instrucción commit

[usuario@ordenador sage]$ git commit

Esto abrirá un editor de textos donde tendremos que escribir una linea que describa los cambios en general y, si es necesario, un párrafo con una descripción más detallada. Después se salva el archivo con el nombre por defecto y ya está hecho. Se pueden ver los cambios hechos con:

[usuario@ordenador sage]$ git diff

Esto mostrará el arbol de trabajo. Se puede hacer commit tantas veces como sea necesario. Después, si ya se han seguido los pasos que permiten la interacción con el servidor trac de Sage (ver Interactuar con el servidor trac de Sage), se procede a subir los cambios a dicho servidor (ver Intercambio de datos con trac mediante git).

Compilar Sage modificado

Cuando uno modifica el código de un archivo existente, compilar no tiene más que el hecho de comprobar que la documentación no está alterada. Si se crean archivos o carpetas, hay más que hacer.

Comprobar que la documentación está bien

Toda función que se implemente debe tener ejemplos en la documentación. La sintaxis requerida para la documentación y los ejemplos se pueden comprobar en cualquier archivo nombre_de_paquete.py de cualquier carpeta de lugar_de_sage/src/sage. Para comprobar que toda función tiene sus ejemplos en un archivo, ejecutamos:

[usuario@ordenador sage]$ sage -coverage /lugar_de_archivo/archivo.py

Si nos da 100% de cobertura, es que no hay que añadir más ejemplos. En caso contrario, habrá que buscar qué funciones carecen de ellos.

También necesitamos que todos los ejemplos que tenemos sean correctos. Para ello, escribimos:

[usuario@ordenador sage]$ sage -t /lugar_de_archivo/archivo.py

S dice que todos los tests han pasado, miel sobre hojuelas. En caso contrario, nos avisará de qué tests han fallad, en qué línea, cuál era el output esperado y cuál el obtenido, para que podamos arreglarlo.

Si agregamos un archivo nuevo...

En caso de agregar un archivo nuevo (por ejemplo, lugar_de_sage/src/sage/tema/subtema/archivo.py ) la carpeta lugar_de_sage/src/sage/tema/subtema/ debe tener un archivo __init__.py" (aunque éste puede estar vacío), para que el archivo "conste" a la hora de compilar Sage. Si queremos que alguna función se cargue al inicio de Sage, podemos pedir en ese mismo ``__init__.py que se importe la función que queramos. En otros casos, desde __init__.py se carga un all.py que dice todo lo que hay que importar.

Si queremos que la documentación de nuestro archivo aparezca con el resto de la de Sage en el manual de referencia, deberemos añadir a (o crear el archivo con) lugar_de_sage/src/doc/en/reference/tema/index.rst las líneas:

Explicación del subtema
-----------------------

.. toctree::
   :maxdepth: 1

   sage/tema/subtema/archivo

Añadir documentación

Uno puede crear un archivo .rst, por ejemplo, en la carpeta lugar_de_sage/src/doc/es/subcarpeta. En el mismo lugar uno debe tener un archivo conf.py. Mi recomendación es copiarlo de cualquier otra carpeta de la documentación y cambiar los campos de título con información relativa a lo que queremos hacer. Si queremos que el menu salga en castellano, debemos incluir:

language = "es"

Después, escribimos en la terminal:

sage --docbuild es/subcarpeta html

y esto creará la página web. También se puede hacer un make y compilar Sage para que monte toda la documentación.

Interactuar con el servidor trac de Sage

Cualquier cambio que se le haga a la distribución oficial de Sage pasa por el servidor trac. Por razones de seguridad, hay que seguir ciertos pasos para poderse comunicar con dicho servidor.

Darse de alta en trac

Lo primero que hay que hacer es escribir a sage-trac-account@googlegroups.com con un mensaje que contenga:

  • nombre completo del contribuyente,
  • nombre de usuario que el contribuyente desea tener,
  • email de contacto, y
  • motivo por el cual se quiere una cuenta en trac.

Después, hay que esperar a que uno le contesten y seguir las instrucciones que le dan.

Tener una cuenta en el servidor trac también te da acceso a la wiki de Sage, de la que no me atrevo a hablar mucho aún.

Clave pública para hablar con el servidor

Por motivos de seguridad, hay que generar una clave SSH para comunicarse (via RSA, creo) con el servidor trac. Probablemente esto se pueda hacer una vez y luego se puede copiar la clave en todos los ordenadores que uno va a usar, pero yo lo que suelo hacer es repetir el proceso en cada máquina que uso. La idea es que trac sepa siempre que eres quien dice ser.

Primero se genera una clave privada con una terminal:

[usuario@ordenador ~]$ ssh-keygen

Preguntará en qué archivo guardar la clave y generará dos archivos. La clave privada pro defecto está en /home/usuario/.ssh/id_rsa y no debería compartirse. La clave pública, normalmente /home/usuario/.ssh/id_rsa.pub, debe abrirse con un editor de textos u su contenido se debe copiar y pegar en la pestaña “SSH Keys” de las “Preferences” del servidor trac. No hay que olvidar hacer clic en “Save changes”.

Es bueno avisar de que uno va a hacer algo

Pues eso. Yo la primera vez me lancé a abrir un ticket, pero habría estado bien por mi parte escribir en

que quería hacerlo, a ver si les parecía bien.

Abrir un ticket

Antes, obviamente, hay que comprobar que no hay nada parecido ya abierto. Es tan simple como hacer clic en la pestaña New ticket del servidor trac.

Una vez hayamos creado una rama en el servidor trac (ver Intercambio de datos con trac mediante git), deberemos asociar la rama al ticket que hayamos abierto haciendo clic modify ticket.

Intercambio de datos con trac mediante git

Su ya tenemos los permisos para interactuar con trac (ver Intercambio de datos con trac mediante git), y ya tenemos los cambios registrados en un commit (ver Configurar y usar git localmente), podemos subir esos cambios al servidor trac de Sage.

Crear un alias para trac

Para no tener que escribir la dirección completa del servidor trac, podemos crear un alias que lo identifique:

[usuario@ordenador sage]$ git remote add trac git://trac.sagemath.org/sage.git -t master
[usuario@ordenador sage]$ git remote set-url --push trac git@trac.sagemath.org:sage.git

A partir de aquí, cada vez que intercambiemos información con trac mediante git, podremos escribir trac en lugar de la dirección completa del servidor. Para controlar los alias de servidores que tenemos, usamos:

[usuario@ordenador sage]$ git remote -v

Subir y bajar cambios

Para subir los cambios que hemos hecho en el último commit, usamos el comando push. Si queremos crear una rama:

[usuario@ordenador sage]$ git push --set-upstream trac HEAD:u/usuario_de_trac/descripción

Esto creará una rama u/usuario_de_trac/descripción con los cambios que hemos hecho nosotros. Si la rama ya estaba creada, usamos:

[usuario@ordenador sage]$ git push trac HEAD:u/usuario_de_trac/descripción

Aquí, HEAD significa que subimos el último commit (y, por tanto, todos los anteriores).

Mezclar cambios

Es frecuente que dos ramas incorporen diferentes cambios y querramos combinarlas. Esto pasa, por ejemplo, cuando sage se actualiza y la rama master pasa a la nueva versión. Querremos combinar los cambios de la nueva rama con los que he mos hecho nosotros.

Mezclar una rama de trac con una local

Si la rama u/usuario_de_trac/rama_de_trac tiene cambios que no hemos hecho en rama_local, los incorporaremos haciendo:

[usuario@ordenador sage]$ git checkout rama_local

para establecernos en dicha rama, y luego:

[usuario@ordenador sage]$ git pull trac u/usuario_de_trac/rama_de_trac

para mezclar las ramas. Si queremos rebasar rama_local en u/usuario_de_trac/rama_de_trac (es decir, que se hagan los mismos cambios que hay en la rama local a partir del estado de la de trac), hacemos:

[usuario@ordenador sage]$ git pull -r trac u/usuario_de_trac/rama_de_trac

Actualizar master

Conviene que la rama master esté idéntica a la de trac siempre. Si, por accidente, se le ha hecho algún commit, se nos avisará si hacemos:

[usuario@ordenador sage]$ git checkout master
[usuario@ordenador sage]$ git pull --ff-only trac master

Si esto da problemas, habrá que pisar nuestra rama master con la del servidor trac:

[usuario@ordenador sage]$ git checkout master
[usuario@ordenador sage]$ git reset --hard trac/master

Mezclar dos ramas locales

Hay dos maneras de mezclar ramas: merge y rebase. La primera crea un commit que incorpora las dos ramas, y la segunda basa una rama en la otra. Para más información, se puede consultar la sección Merging and Rebasing de la documentación de Sage.

Para mezclar una_rama con otra_rama, hacemos:

[usuario@ordenador sage]$ git checkout una_rama
[usuario@ordenador sage]$ git merge otra_rama

Esto el historial de una_rama contendrá un hito más, donde se aplican los cambios de otra_rama. Para rebasar:

[usuario@ordenador sage]$ git checkout una_rama
[usuario@ordenador sage]$ git rebase -i otra_rama

Así, el historial de una_rama contendrá todos los hitos de otra_rama y, a continuación, los propios.

Contacto

No soy ningún experto en el tema, por lo que agradezco cualquier crítica que se envíe a jcaravan@ucm.es.