Jair Trejo

Una cucharadita de shell

Estuve reorganizando mis dotfiles y decidí incorporar mi carpeta de plugins y configuraciones de Vim (~/.vim) al repositorio. Utilizo vim-pathogen para manejar mis plugins, así que todos los instalé más o menos así:

$ cd ~/.vim/bundle
$ git clone https://github.com/autor/plugin.git

Funcionaba perfectamente cuando todo estaba en una carpeta de Dropbox, symlinkeado a mi carpeta de inicio, pero dado que ahora quedará en un repositorio de git sería conveniente tener los plugins instalados como submódulos, que son subrepositorios dentro del principal.

El primer paso es saber qué plugins instalé y desde dónde. Lo de menos es leer la lista de carpetas dentro de ~/.vim/bundle y buscar uno por uno en github, pero ya lo hice en su momento y no hay necesidad de duplicar trabajo (y arriesgarme a instalarlos desde el repositorio equivocado). Otra opción es ir carpeta por carpeta ejecutando git remote --verbose y checando las URLs de los repositorios de origen.

¿Se puede automatizar el proceso? Claro que sí; y todo sin salir del shell. Comencemos por ir a la carpeta de plugins (cd ~/.vim/bundle) y ejecutar:

$ ls | while read subm; do cd $subm && git remote --verbose | grep origin && cd ..; done

Es decir, listamos el contenido de la carpeta y tratamos cada entrada del listado como una carpeta a la que entramos, ejecutamos git remote --verbose filtrando con grep las líneas que no se refieren a origin (para los repositorios que son forks míos del original) y regresamos al directorio original. La salida es algo como lo siguiente

origin  https://github.com/sjl/clam.vim.git (fetch)
origin  https://github.com/sjl/clam.vim.git (push)
origin  https://github.com/kien/ctrlp.vim.git (fetch)
origin  https://github.com/kien/ctrlp.vim.git (push)
origin  https://github.com/vim-scripts/django.vim.git (fetch)
origin  https://github.com/vim-scripts/django.vim.git (push)
origin  https://github.com/scrooloose/nerdtree.git (fetch)
origin  https://github.com/scrooloose/nerdtree.git (push)

Podemos extraer sólo las URLs (imprimir la segunda columna) con awk, eliminar los duplicados con uniq:

$ ls | while read subm; do cd $subm && git remote --verbose | grep origin | awk '{print $2}' | uniq && cd ..; done

Lo cual nos da una lista de URLs que copié y pegué en un archivo (submodules.txt):

$ cat submodules.txt
https://github.com/sjl/clam.vim.git
https://github.com/kien/ctrlp.vim.git
https://github.com/vim-scripts/django.vim.git
https://github.com/scrooloose/nerdtree.git

El siguiente paso es añadir los submódulos al repositorio con el comando git submodule add [URL del repositorio] [ruta para el submódulo], que debe ejecutarse desde la raíz del repositorio. Para empezar:

$ cd ~/dotfiles
$ mkdir -p vim/bundle
$ cp ~/backup/vim/bundle/submodules.txt .

Ahora hay que recorrer la lista de URLs creando los submódulos correspondientes. Recorrer la lista usando while es trivial, pero existe el problema de nombrar los submódulos. Idealmente tendrían que llamarse según la última parte de la URL, sin el “.git”, que se podría obtener con:

$ echo https://github.com/scrooloose/nerdtree.git | cut --delimiter "/" --fields 5 | sed 's/.git//'
nerdtree

¿Cómo incorporarlo en el ciclo sobre las URLs? Una manera es usar backticks (acentos graves) para la “sustitución de comandos”, que toma la salida estándar de un comando y la usa como parte de la definición de otro:

$ cat submodules.txt | while read subm; do git submodule add $subm vim/bundle/`echo $subm | cut --delimiter "/" --fields 5 | sed 's/.git//'`; done

Una vez que terminan las descargas tendremos nuestros plugins de Vim perfectamente organizados en submódulos de nuestro repositorio de dotfiles.

¿Qué otras cosas se podrán hacer con la línea de comandos?