A blog about data, information and Tech by Mario Alberich

        

Trabajando con subversion y awk


Para los impacientes: resultado final

Empezando por el final, las instrucciones a realizar son:

$ svn log -v -r 400:`svn info | grep Revisión | awk '{print $1}'` | grep dirprj | awk '{print $1}' | sort | uniq | awk '{print "."$0}' > dirprj-`svn info | grep Revisión | awk '{print $1}'`.txt

y luego....

$ tar -zcvf dirprj-`svn info | grep Revisión | awk '{print $1}'`.tar.gz -T -`svn info | grep Revisión | awk '{print $1}'`.txt

Traducido al verbo humano, el proceso es como sigue:

  • Selección de los archivos
    • Lístame los cambios del repositorio desde la revisión 400 hasta la última versión.
    • Del resultado, selecciona sólo lo que incluya la cadena dirprj. [grep dirprj]
    • De los datos seleccionados, selecciona la segunda palabra de cada línea. [awk print $1]
    • Ordena alfabéticamente los datos resultantes (sort).
    • Elimina los datos repetidos [uniq]
    • A las rutas recuperadas les pones un punto delante y los guardas en el archivo con nombre "dirprj-[ultimarevision].txt"
  • Segunda parte: Compresión
    • Comprime en formato tar y gzip los archivos que aparecen listados en el archivo dirprj-[ultimaversion].txt. y lo guardas en el archivo llamado dirprj-[ultimaversion].tar.gz

Ahora, por partes

Así, a palo seco, la instrucción de consola es un poco bestia. Voy desglosando instrucciones para sacar conclusiones:


svn log

svn log es una llamada que se realiza sobre subversion para saber la actividad que ha tenido el repositorio. Al aplicar la opción -v, lo que conseguimos es que nos muestre los archivos alterados para cada actualización.

Si sacáramos todo el log quizá nos pasamos 10 minutos viendo pasar listas de archivos modificados, con lo que lo mejor es establecer un margen de revisiones. Para especificar un número de revisiones se utiliza la opción -r, que tiene la forma:

-r a:b, donde a es la revisión más antigua y b la más actual. En nuestro caso, nos interesa que b sea la última revisión realizada. Para no tener que estar cambiando continuamente el valor, ejecutamos la instrucción:

svn info | grep Revisión | awk '{print $1}'

Para ir más rápido, utilizo directamente las salidas `entrecomillando las instrucciones`. Eso sustituye el la instrucción entrecomillada por el valor devuelto.


Seleccionando los archivos que nos interesan

La instrucción grep que se muestra a continuación es una cuestión de estilo. El caso sirve para los repositorios que almacenan más de un proyecto, como es mi caso. Eso permite que los subdirectorios identifiquen los proyectos relacionados. Este punto es el más adaptable a cada caso, como expone el propio manual de subversion en cuanto a estilos de gestión de repositorios se refiere. Para el caso, la instrucción:

grep nos devuelve sólo los archivos que tienen en su path el nombre indicado. La desambigüación no está de más para estos casos.


Eliminando ruido e información innecesaria

Los listados de log del subversion están bastante, maquetados, por decirlo de algún modo. Al menos la versión por defecto encuadra los resultados con guiones u otros caracteres. Además, para cada archivo indica qué tipo de modificación se ha realizado. Eso aclara la visualización pero entorpece el proceso de cañerías.

Para eliminar ese ruido, ejecuto awk:

$ ... | awk '{print $1}' | ...

Esto hace que de todos los resultados retornados por grep, me coja "la segunda palabra", es decir, la secuencia de caracteres posterior al primer conjunto de espacios. Esto lo que devuelve en definitiva es la ruta del archivo.

Dado que es probable que hayan habido varias alteraciones de un mismo archivo, decido ordenar los resultados (sort) y luego eliminar de la lista ordenada los valores repetidos. Cambiar el orden de estas dos instrucciones no da buenos resultados, porque uniq sólo mira si la fila actual es igual que la anterior.


Relativizando rutas y guardando datos

Dado que el repositorio no tendrá un path completo, la última instrucción le añade un punto (.) al principio de toda la cadena, para dar a entender que se refiere a un path relativo al path actual (en awk, el valor de $0 equivale a toda la cadena).

¿Por qué?

Pues porque svn me devuelve "paths absolutos" respecto la raíz del repositorio, pero cuando trabajo directamente sobre la raíz de mi sistema operativo, esas rutas no son correctas. Es importante tener claro en cada momento el contexto de ejecución, y especialmente cuando trabajamos con pipes.

Almacenamos la lista de rutas limpitas y preparadas para la exportación en un archivo de texto, que para el caso hemos denominado combinando el nombre del directorio del proyecto y el número de revisión, así no hay que estar pendientes de grandes fiascos...


Golpe de gracia: compresión con Tar

Para acabar, llamaremos al programa tar, utilizando la opción -T, que nos permite seleccionar de un archivo la lista de recursos a empaquetar. Así pues, ejecutamos la instrucción comentada antes:

$ tar -zcvf dirprj-`svn info | grep Revisión | awk '{print $1}'`.tar.gz -T -`svn info | grep Revisión | awk '{print $1}'`.txt

Como antes, el entrecomillado de svn info nos devuelve un valor. Por eso, es importante entender que lo que acaba recibiendo el ordenador (suponiendo que dirprj=proyecto1 y que la última revisión sea 425) es algo así como:

$ tar -zcvf proyecto1-425.tar.gz -T proyecto1-425.txt


Mejoras, temas pendientes y Further research

Por lo menos detecto las siguientes mejoras posibles:

  • Subversion indica el tipo de modificación que se ha realizado sobre un archivo. Actualmente no se ha realizado el control sobre lo que pasa con el archivo en cuestión, por lo que quizá estemos tratando de empaquetar un archivo que ya no existe. No obstante, ese no era el problema principal, y por eso lo dejo como caso a desarrollar.
  • el "grep Revisión" es ciertamente mejorable, por ejemplo comprobando si se puede hacer con un tail -n1 -c5 | awk '{print $1}', que nos daría el mismo resultado. Sólo que la versión de subversion fuera en inglés, ya no valdría lo anterior, aunque es fácilmente adaptable.
  • El ejemplo anterior se podría desarrollar en un archivo bash para hacerlo más sencillo, y parametrizable.

Si quieres saber más...

Puedes seguir investigando sobre los anteriores comandos en los enlaces comentados anteriormente. Te recomiendo awk (puedes empezar por algunos ejemplos de awk), ese gran olvidado que yo conocí a fondo estudiando procesamiento del lenguaje natural, cuando para procesar un corpus y categorizar los términos utilizamos esta herramienta. Ahora ya forma parte de mi vida laboral :-D.

© 2007 and beyond Mario Alberich, licensed under CC-BY-SA unless stated otherwise.