dotfiles, git et rcm

Dans un billet récent sur le thème des dotfiles, j’évoquais ma migration prochaine de stow vers rcm comme programme de gestion de mes fichiers de configuration. C’est désormais chose faite et j’utilise à présent rcm à la place de stow.

Parmi les améliorations notables apportées par rcm, la principale est la possibilité de déployer l’ensemble de mes dotfiles en une commande, et non plus en exécutant une commande stow par dossier, ou programme. Je l’avais évoqué, l’organisation de mon dépôt git a également gagné en clarté, la seule différence étant l’absence de point devant les fichiers ou dossiers à la racine du dépôt.

La migration d’un système vers l’autre s’est déroulé sans grande difficulté. Comme souvent, la première étape consiste à installer le programme. Pour une fois, celui-ci n’est pas disponible par défaut dans les paquets d’Arch Linux. Je passe donc par yaourt pour récupérer le paquet dans le dépôt AUR.

yaourt -S rcm

L’installation du paquet rcm mets à disposition quatre utilitaires: rcup, rcdn, mkrc et lsrc. Je ne rentre pas dans les détails de chacun des programmes; le programme principal à utiliser est rcup, programme responsable de l’installation et de la mise à jour des dotfiles. Avant d’exécuter la commande de déploiement, j’ai commencé par changer la structure de mon dépôt git dans une branche dédiée. Une fois la structure satisfaisante, j’ai fusionné l’ensemble dans la branche master. Avant d’effectuer la fusion, il faut s’assurer de garder un terminal ouvert, car en ouvrir un avant d’avoir effectuer le redéploiement va conduire à l’ouverture d’un terminal non configuré, dans mon cas, ouverture sur l’interface de première configuration de oh my zsh.

Revenons à nos dotfiles. Après fusion de mes branches, tous mes fichiers dotfiles existants sont désormais des liens cassés vers l’ancien emplacement des fichiers. Il est donc plus que temps de rétablir les liens pour coller à la nouvelle structure du dépôt. Pour cela, j’utilise donc rcup avec les paramètres :

  • x pour exclure un fichier
  • d pour spécifier l’emplacement du dossier dotfiles
  • f pour forcer l’installation (supprime le fichier existant et le remplace par un lien vers le fichier dans notre dossier dotfiles).

Ce qui donne donc quelque chose comme cela :

rcup -x README.md -x LICENSE -d /chemin/vers/dossier/dotfiles -f

J’ai eu quelques erreurs à l’exécution, étant donné que stow avait mis en place des liens symboliques directement sur certains répertoires. Les répertoires ayant changé d’emplacement, rcup n’arrive pas à y accéder pour créer le lien symbolique du fichier de configuration dans le dossier.

mkdir: ~/.config/terminator: Input/output error
ln: ~/.config/terminator/config: No such file or directory
mkdir: ~/.zsh: Input/output error
ln: ~/.zsh/keychain.zsh: No such file or directory
mkdir: ~/.zsh: Input/output error
ln: ~/.zsh/security.zsh: No such file or directory

Pour corriger ces erreurs, j’utilise donc unlink pour supprimer les liens symboliques existants et j’exécute une nouvelle fois mon déploiement via rcup.

unlink ~/.config/terminator

Au final, la migration de stow vers rcm m’aura demandé une petite heure environ et n’aura pas présenté de difficulté particulière. Compter également plusieurs dizaines de minutes, quelques heures peut-être, réparties sur plusieurs jours afin de me documenter, de comprendre le fonctionnement des outils et d’arrêter ma décision. La nouvelle structure de mon dépôt dotfiles me convient davantage et je trouve le fonctionnement de rcm plus simple dans son utilisation basique, mais proposant néanmoins des fonctionnalités avancées qu’il me faudra étudier pour éventuellement décider d’en faire usage. Ma préférence va donc à rcm et l’avenir nous dira si mon choix était pertinent. Enfin, il serait malvenu de tirer un trait définitif sur stow, qui doit rester un outil à ma disposition, si un cas d’utilisation adéquat se présente.

dotfiles, git et GNU stow

En septembre 2016, j’avais commencé à écrire l’introduction de cet article. J’expliquais donc que je venais de réinstaller le système d’exploitation de mon ordinateur portable, pour passer de Debian 8 à Arch Linux. À ce moment-là, c’était donc posé la question de la synchronisation de la configuration de l’environnement entre machines. Par configuration de l’environnement, je désigne ici les fichiers de configuration des différents logiciels que j’utilise, plus généralement appelés « dotfiles », car commençant par un point, ou étant stocké dans le dossier .config du répertoire utilisateur.

Pour gérer mes configurations entre machines, j’ai donc utilisé le duo Git et GNU stow depuis lors. Git bien sûr pour la synchronisation entre machines et l’historisation, et GNU stow, pour le déploiement des fichiers à leur emplacement dédié.

Fonctionnement

Par défaut, stow créé un lien symbolique dans le répertoire parent de celui à partir duquel on exécute la commande, pour tous les fichiers concernés par la commande. Ma configuration part du principe que mon dépôt git dotfiles est stocké à la racine de mon répertoire utilisateur, à savoir donc ~/dotfiles, et que toutes les commandes stow sont exécutées depuis ce dossier. L’installation de la configuration s’effectue alors en appelant la commande stow avec pour paramètre le nom du logiciel dont on souhaite déployer la configuration. Au niveau de la structure, mon dépôt git se présente donc sous la forme d’une liste de répertoire contenant chacun le chemin vers la configuration du logiciel concerné, c’est-à-dire :

  • soit directement le fichier si celui-ci est stocké directement à la racine du répertoire utilisateur: c’est le cas par exemple du fichier .gitconfig.
  • soit dans une arborescence de répertoire correspondant à son emplacement: par exemple pour i3, la configuration est stockée dans ~/.config/i3, j’ai donc dans mon dépôt un dossier i3 contenant l’arborescence .config/i3.

Voici un extrait de mon dépôt en image pour expliciter la situation.

Extrait de la structure du dépôt.

Ainsi, pour déployer le fichier de configuration de Git, j’exécute la commande suivante, depuis mon dossier dotfiles:

stow git

Ce qui aura pour effet de créer un lien symbolique .gitconfig vers le fichier .gitconfig de mon dépôt git. Si on souhaite modifier le répertoire de destination, on peut utiliser l’option -t. Dans l’image ci-dessus, pour déployer la configuration ansible, j’utiliserai alors:

stow -t / ansible

A noter que stow effectue la création du lien symbolique à la condition que le fichier n’existe pas. Si un fichier de configuration par défaut existe déjà, il sera nécessaire de le supprimer d’abord avant de pouvoir procéder à l’exécution de la commande stow.

Dernier point, si je souhaite re-déployer la configuration git, j’utiliserai alors l’option -R, soit la commande :

stow -R git
Conclusion

Le duo git + GNU stow est plutôt efficace pour ce qui est de la gestion des fichiers de configuration, les fameux fichiers dotfiles, et pour la synchronisation entre machines. Je m’en étais également servi pour stocker et déployer facilement certains fichiers de configuration sur mes serveurs, avant de commencer à automatiser avec ansible. Si je rédige aujourd’hui, cet article sur le sujet, c’est pour garder une trace d’une méthode robuste qui m’a été utile pendant plus de deux ans. Néanmoins, la structure actuelle du dépôt git ne me convient plus autant qu’avant et je souhaiterais passer à une organisation plus proche, ou même identique à l’arborescence présente sur le disque. J’étudie donc les autres solutions de gestion des dotfiles, et m’intéresse en particulier à rcm; mais ceci est une autre histoire, pour un autre article.

Modification des informations d’auteur d’un commit

Après avoir récupéré l’ensemble de mes dépôts git avec repo, je souhaitais effectuer un peu de « nettoyage » dans mes informations d’auteur de commit afin de les harmoniser. Bien entendu, cette opération n’est pas du tout neutre puisqu’elle implique une réécriture de l’historique, et dans le cas d’un changement d’email, cela concerne chaque SHA-1 des commits de l’historique (car un commit contient le SHA-1 de son parent).

Intéressons-nous à la commande de changement des informations d’auteur à proprement parler. Celle-ci est extraite de la documentation de github (si besoin, en cas d’opération successive, ajouter l’option -f avant –env-filter):

$ git filter-branch --env-filter '

OLD_EMAIL="your-old-email@example.com"
CORRECT_NAME="Your Correct Name"
CORRECT_EMAIL="your-correct-email@example.com"

if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_COMMITTER_NAME="$CORRECT_NAME"
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_AUTHOR_NAME="$CORRECT_NAME"
export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags

Avant d’être en mesure de réécrire les commits, on commence par déterminer les informations existantes à l’aide de la commande suivante (que l’on pourra par ailleurs exécuter sur tous les dépôts avec repo forall -c <commande>) :

git log | grep Author: | sort | uniq

Une fois les changements terminés, on pousse ces derniers vers le serveur:

git push --force --tags origin 'refs/heads/*'

En cas de message du type :

erreur fatale: 'origin' does not appear to be a git repository

Il convient de vérifier le remote configuré avec git remote -v, soit dans mon cas :

github  ssh://git@github.com/vvision/eslint-config (fetch)
github ssh://git@github.com/vvision/eslint-config (push)

On remplace alors origin par github dans la commande git push et le tour est joué (configuration héritée de repo).

De cette manière, l’ensemble de mes dépôts dispose désormais des informations de contact nettoyées.

Gestion des dépôts git

Au fil des années, j’ai accumulé pas loin de 70 dépôts git, certains presque vides, d’autres contenant des instructions de déploiement de service, ou encore, mes divers essais successifs pour me familiariser avec l’une ou l’autre technologie. Lors de la panne récente de mon serveur auto-hébergé, j’ai craint un moment d’avoir perdu une partie du code produit ces dernières années. Heureusement, cela ne fut pas le cas.

Bien sûr, une partie des dépôts est toujours présente dans un coin de mon disque dur, bien que n’ayant pas été l’objet de modification récente, et m’assure ainsi une sauvegarde locale de ces derniers: une n-ième duplication. Continuant le chemin du côté de ma résilience numérique, je me suis donc intéressé au moyen de conserver facilement l’ensemble de mes dépôts git en local. Pour arriver un résultat satisfaisant, je me suis donc tourné vers repo, programme écrit par Google pour gérer les dépôts Android et que j’avais eu l’occasion de découvrir durant mes études d’ingénieur.

J’ai donc ajouté un nouveau dépôt à ma liste, contenant un readme et un fichier default.xml. Le fichier default.xml suit les règles de syntaxe des fichiers manifest de repo et liste désormais l’ensemble de mes dépôts git. En voici une version simplifiée :

<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<remote name="github" fetch="ssh://git@github.com/vvision" />
<default revision="master" remote="github" sync-j="4" />

<project name="eslint-config" />
<project name="manifest" path="manifest/manifest" />
<project name="prettier-config"/>
</manifest>

Quelques commentaires. Je commence par définir un remote, endroit où récupérer mes dépôts, lui donne un nom et précise l’url utilisée pour la récupération d’un dépôt. Je définis ensuite les paramètres par défaut en précisant ici que je souhaite récupérer la branche master, en utilisant la configuration du remote nommée github et en autorisant 4 jobs concurrents pour les opérations de synchronisation. Reste ensuite à définir les dépôts à récupérer, le paramètre minimum étant le nom du dépôt sur le serveur distant. À noter également la présence du paramètre path qui permet de choisir l’emplacement final du contenu du dépôt, ce qui se révèle d’une grande utilité pour grouper ses dépôts dans différents répertoires.

Une fois le fichier manifest complété et pousser dans son dépôt distant, on peut commencer la récupération de la liste de dépôts en utilisant successivement les commandes :

repo init -u git@github.com:vvision/manifest.git

Puis :

repo sync

À l’issue de l’exécution de cette deuxième commande, on dispose désormais de l’ensemble des dépôts définis dans le manifest sur le disque local et cela de manière totalement automatique. On notera en particulier la présence de l’instruction status permettant d’avoir un aperçu de l’état des dépôts et l’instruction forall permettant d’exécuter une commande sur l’ensemble des dépôts.

Sources :

Conversion flac vers mp3

Dans le but de pouvoir lire des fichiers de ma bibliothèque musicale sur un appareil n’étant pas en mesure de lire le format flac, j’ai cherché à résoudre le problème de la conversion d’un fichier audio au format flac vers le format mp3. Après recherche, voici la commande que j’obtiens en utilisant ffmpeg :

ffmpeg2.8 -y -i tangerine.flac -codec:a libmp3lame -ab 320k -map_metadata 0 -id3v2_version 3 -write_id3v1 1 tangerine.mp3

Étape suivante pour rendre la conversion plus pratique, on applique la commande à tous les fichiers flac du répertoire à l’aide d’une boucle for :

for f in *.flac; do ffmpeg -i "$f" -acodec libmp3lame -ab 320k -map_metadata 0 -id3v2_version 3 -write_id3v1 1 "${f%.flac}.mp3"; done

Enfin, dernière amélioration, on exécute la commande pour tous les fichiers finissant par .flac présent dans le répertoire courant et dans tous les sous-répertoires :

find -name "*.flac" -exec ffmpeg2.8 -y -i {} -acodec libmp3lame -ab 320k -map_metadata 0 -id3v2_version 3 -write_id3v1 1 {}.mp3 \;

A noter que pour cette dernière commande, le nom du fichier traité sera de la forme Tangerine.flac.mp3. A l’issue de cette dernière commande, nous disposons donc des fichiers flac et de leur copie encodée en mp3. Ayant travaillé sur une copie de mes fichiers musicaux, je peux donc me débarrasser des fichiers flac pour ne conserver que les nouveaux fichiers :

find -name "*.flac" -exec rm {} \;

Il ne reste plus qu’à copier les fichiers restants sur le support destiné à l’appareil.