Gestion de configuration : introduction

Fri, 31 July, 2015 (1300 Words)

Cela doit faire au moins 2 ans que je souhaite partager la façon dont je gère mes configurations (en anglais dotfiles). Comme j'ai longtemps repoussé l'échéance, probablement de peur d'avoir un roman à écrire, je vais en faire une série de petits billets de blog dont celui-ci est l'introduction. Nous y aborderons donc mon besoin, et mes choix.

Besoin(s)

En bon geek que je suis, je suis fan des dotfiles. Les dotfiles — fichiers de configurations — sont de petits fichiers, habituellement dans notre dossier personnel (votre $HOME), qui nous permettent de paramétrer et personnaliser nos outils de tous les jours. C'est principalement vrai pour des outils en ligne de commande — et ça tombe bien, j'adore — mais pas uniquement limité à ces derniers.

Je vais faire un très petit aparté sur le pourquoi de cette personnalisation :

  • C'est fun à faire et c'est relativement important de mon point de vue.
  • C'est éducatif ou formateur ; on lit les documentations de nos outils, leurs fonctionnalités un peu cachées. On va souvent découvrir un peu la philosophie dans laquelle l'outil a été créé. C'est en mettant les mains dans le cambouis et en foutant un gros bordel que j'ai le plus appris (ça va du langage shell et d'autres langages de scripts, de POSIX, au noyau linux ou encore au LISP avec GNU/Emacs).
  • Cela fait gagner du temps et de manière non négligeable. Je suis né courageux mais terriblement fainéant (et oui c'est possible :-P), j'aime pas trop me répéter quand ça devient un peu compliqué / chiant (e.g. docker run monimage args ça va, docker run avec -v /tmp:/tmp -v /var/run/docker.socket:/var/run/docker.socket […] et run monimage arg1 arg2 arg3 […] moins déjà).

Mais revenons à nos moutons et faisons une petite liste de mes besoins, un peu en vrac :

  • J'ai plusieurs ordinateurs (laptop/desktop/serveurs) et je souhaite avoir mes configurations synchronisées entre ceux-ci — et ce de manière simple, c'est à dire une commande à exécuter.
  • C'est lié au point précédent mais, je ne peux pas vivre sans outil de gestion de version, comme git. Il me faut donc un outil ou ensemble d'outil qui sache utiliser des outils de gestion de version du marché.

    git-all-the-thing.jpg

  • En fonction de mes ordinateurs, mes besoins de configuration changent. Il me faut donc un outil flexible qui me permette de dire par exemple : sur ce PC j'ai un serveur Xorg donc j'ai besoin de mes configuration xorg, de celle de mon window manager, etc. — et inversement sur ce serveur j'ai besoin de python et haskell mais pas de xorg..
  • Je ne souhaites pas avoir à faire des liens symboliques, ou de scripts d'installation. Je trouves que ça rends les choses plus compliquées. Du coup il faut que je puisse avoir plusieurs dépôts de configuration (repository) qui pointent au même endroit, sans que ce soit le bordel.
  • Le partage est important pour moi. Il en découle deux choses :
    1. Il faut que je puisse documenter un peu mon repository, avec un bon vieux README ; sans que chaque README se marche dessus.
    2. Il y a quelques informations qui sont personnelles, comme par exemple les clés ssh. Il me faut donc être capable d'avoir des dépôts publiques et des dépôts privés. C'est grandement facilité par l'aspect flexibilité :-).
  • Un bonus que je souhaite, est de pouvoir disposer de hooks, un peu à la manière de git (voir ici). L'idée est de pouvoir générer un fichier de configuration à partir d'un ensemble de fichiers qui viendraient de différents dépôts. Le meilleur exemple que je peux donner c'est ~/.ssh/config dans lequel je vais y mettre des bouts publiques que je souhaites partager (comme le Host * avec des trucs cool comme ControlPersist, on en parlera plus tard) et des bouts privés (mes hosts privés, avec mes configurations de rebonds, etc..).

Cette liste a mis un certain temps à se former dans ma tête, mais une fois qu'elle était formée, j'ai pu assez facilement faire des choix.

Choix

Deux outils et un peu d'organisation permettent de répondre à mes besoins. Les deux outils sont vcsh et myrepos (anciennement appelé mr), fait par respectivement Richard Hartmann et Joey Hess (tout deux assez impliqué dans la communauté Debian).

vcsh

En un mot, vcsh permet de maintenir plusieurs repository git dans un seul dossier. Par défaut tous les repository git maintenus par vcsh pointent vers le dossier $HOME, mais il est possible d'utiliser un autre dossier.

L'idée est de pouvoir disposer de plusieurs repository par famille d'application, par exemple vim, ssh, emacs, zsh, etc. Cela permet ainsi d'avoir différents ensemble de configurations sur différentes machines et pour différents utilisateurs. Cela apporte une très grande flexibilité et facilite le partage de configuration (au sein d'une entreprise ou d'un projet par exemple) tout en laissant la place à la définition de configuration(s) personnalisé(s).

En bonus, vcsh supporte un système de hook, permettant d'exécuter des commandes à différents moments du workflow — c'est la seule partie qui manquant à vcsh de mon point de vue alors j'y ai apporté ma petit pierre.

vcsh est la clé de voûte de ma gestion de configuration. Sans le travail formidable de Richard Hartmann, je ne sais pas comment je ferais..

myrepos

En un mot, myrepos est un outil permettant de gérer plusieurs repository (git, subversion, mercurial, …) avec une seule commande : mr. C'est simple et efficace :

  • mr u (ou mr update) pour récupérer les dernières modifications (git pull, svn up, …).
  • mr -d $HOME/.config u pour récupérer les dernières modifications des repository qui sont dans $HOME/.config.
  • mr -j 6 u pour paralléliser la récupération (ici 6 jobs en parallèle).
  • mr p pour pousser des modifications (git push, …).
  • mr run pour lancer un commande (j'utilise ça tous les jours).

Il est également possible de personnaliser les commandes à lancer lors d'un update ou autre (toutes les commandes), et même en définir des nouvelles. Cela se présente comme suit :

[foo]
checkout = git@github.com:joeyh/foo.git
update = git pull --rebase

[bar]
# This repository has an upstream, which I've forked;
# set up a remote on checkout.
checkout =
    git clone git@github.com:joeyh/bar.git
    cd bar
    git remote add upstream git@github.com:barbar/bar.git
# make `mr zap` integrate from upstream
zap =
    git pull upstream
    git merge upstream/master
    git push origin master

[mystuff]
checkout = git@github.com:joeyh/foo.git
# Skip if the current user is not joey
skip = test `whoami` != joey

[DEFAULT]
# Teach mr how to `mr gc` in git repos.
git_gc = git gc "$@"

Une autre fonctionnalité qui m'est totalement indispensable est ce qu'on appel les fixup(s). Il est en effet possible d'exécuter une ou plusieurs commandes (shell) après un update (ou via la commande fixup). C'est grâce à ce système la que je génère mes fichiers de configuration en provenance de plusieurs repository (comme $HOME/.ssh/config ou encore $HOME/.gitconfig).

myrepos est l'exemple de l'outil simple et efficace qui fait une chose et le fait très bien, et dont je n'arrive pas à me passer :-D. Je l'utilise également dans plein d'autres cas, comme par exemple pour mettre à jour mes forks de projets open-source.

Conclusion

Et voilà, c'est tout pour cette introduction ;-). La prochaine partie se penchera sur la structure que j'utilise ainsi que le repository principal qui est vcsh-home. Dans les parties suivantes on parlera des autres repository et donc des configurations spécifiques pour les différents outils (comme sh-config, emacs-config ou encore go-config). On parlera aussi probablement de git-annex dans le futur.