Découverte de direnv

Vous êtes développeur ou administrateur système et utilisez souvent votre terminal ? Nombre de vos projets utilisent des variables d’environnement locales et spécifiques ? Vous trouvez que gérer ces dernières avec dotenv ou nconf est suboptimal ? Aujourd’hui nous allons apprendre comment palier ces problèmes – et d’autres – sans galérer, grâce à direnv.

Mise en bouche

direnv est un logiciel libre et open-source qui permet d’effectuer certaines actions lors du changement de dossier avec cd :

  • exporter des variables d’environnement,
  • ajouter un ou plusieurs répertoires dans le PATH,
  • exécuter un ou plusieurs programmes.

Je l’utilise personellement pour changer la variable d’environnement AWS_PROFILE en fonction du projet dans lequel je me trouve, ou encore pour mettre des alias sur npm afin que celui-ci s’exécute dans un container Docker.

Installation

direnv est disponible dans la plupart des gestionnaires de paquets :

# macOS avec Homebrew
$ brew install direnv

# Debian et dérivés
$ apt install direnv

Pour les autres, je vous invite à regarder la section Install sur le site officiel.

Une fois installé, il faut également activer le hook correspondant à votre shell en rajoutant une ligne dans votre configuration :

# Bash, dans le fichier ~/.bashrc
eval "$(direnv hook bash)"

# ZSH, dans le fichier ~/.zshrc
eval "$(direnv hook zsh)"

# Fish, dans le fichier ~/.config/fish/config.fish
direnv hook fish | source

Utilisation

Dans le dossier souhaité, créez un fichier .envrc qui sera lu par direnv. Celui-ci est un fichier qui sera lu par Bash, vous pouvez donc exécuter n’importe quoi avec. En bonus, les variables d’environnement que vous exportez seront intégrées dans votre shell courant.

Enfin, direnv vous avertira que le fichier ne sera pas exécuté tant que vous ne l’aurez pas spécifiquement autorisé avec direnv allow. C’est une fonctionnalité qui sert à vous protéger et vous aurez à le faire uniquement en cas de création ou changement du contenu de l’.envrc.

$ cd $(mktemp -d)
$ printf 'export AWS_PROFILE=mon_client\n' > .envrc
direnv: error .envrc is blocked. Run `direnv allow` to approve its content.
$ direnv allow
direnv: loading .envrc
direnv: export ~AWS_PROFILE
$ echo $AWS_PROFILE
mon_client
$

Bonus : npm dans un Docker

Dans un de mes projets, j’utilise de nombreux containers Docker dont la racine se situe dans un sous-dossier services :

  • services/accounts contient un container Node.js
  • services/reports contient un second container Node.js
  • etc.

Pour installer des paquets npm, je me retrouvais souvent à devoir lancer le sempiternel docker-compose exec :

# Lancer les tests npm dans le container accounts_service
$ docker-compose exec accounts_service npm test

. . .

# Installer express dans le container accounts_reports
$ docker-compose exec accounts_reports npm test

J’ai décidé de créer un script pour abstraire toute la partie docker-compose afin de pouvoir lancer ces commandes de façon transparente. Pour ce faire, j’ai créé un dossier bin dans lequel j’ai placé un fichier npm (chmod +x) :

#!/bin/bash

project=$(dirname $(dirname "$0"))
relative=${PWD##$project/services/}
service=${relative%%/*}

docker-compose run --rm "${service}_service" npm $@

Et dans mon .envrc :

PATH_add bin
# Et autres variables d'environnement...

Désormais, lorsque je lance npm test dans services/accounts, ce dernier est en fait lancé dans le container accounts_service.