direnv pour booster votre shell
Le problĂšme
Je suis le genre de développeur qui travaille toujours avec un terminal ouvert sur le cÎté, en plus de mon IDE.
Je lance souvent des commandes mvn
pour m’assurer que mon projet compile et que mes tests s’exĂ©cutent correctement. C’est un vieux rĂ©flexe qui date de l’Ă©poque oĂč les IDE n’avaient qu’un support limitĂ© de Maven. Lancer ces commandes hors-IDE m’aide souvent Ă valider que tout fonctionnera bien dans un environnement de CI par exemple.
J’ai donc parfois besoin de changer de version de Java en fonction du projet dans lequel je me trouve.
Maven utilise la variable d’environnement JAVA_HOME
pour localiser l’installation de Java Ă utiliser. Donc ĂȘtre capable de charger des variables d’environnement diffĂ©rentes en fonction d’un projet peut s’avĂ©rer pratique.
Un autre usage courant consiste Ă venir charger des clĂ© d’API ou des secrets d’accĂšs cloud comme des variables AWS_ACCESS_KEY
ou autres en fonction de mes différents projets.
direnv
direnv
(lien) est un outil Ă©crit en go qui permet de charger des variables d’environnement dans la session courante du terminal, lorsqu’on change de rĂ©pertoire en effectuant un cd
.
Installation
direnv
est disponible dans les dĂ©pots de nombreuses distributions Linux, l’installation sur Ubuntu se fait avec les commandes habituelles, Ă savoir apt install direnv
.
L’installation pour d’autres distributions se fait Ă partir des dĂ©pĂŽts, ou bien directement Ă partir de binaires prĂ©-compilĂ©s Ă rĂ©cupĂ©rer sur Github dans les releases de direnv.
Configuration
Une fois installĂ©, il faut indiquer au shell d’appeler le binaire direnv
à chaque changement de répertoire.
Le shell que j’utilise au quotidien est zsh
. Pour zsh
, la configuration de direnv
consiste Ă venir modifier mon fichier ~/.zshrc
pour y ajouter la ligne suivante:
eval "$(direnv hook zsh)"
Les procĂ©dures de configuration pour les autres shells sont dĂ©taillĂ©es sur le site de direnv et sont du mĂȘme ordre que la procĂ©dure ci-dessus.
Utilisation basique
L’utilisation de direnv
se fait au travers d’un fichier .envrc
à positionner dans le répertoire souhaité.
Ce fichier peut contenir :
- des commandes
export
pour dĂ©clarer des variables d’environnement - des appels de fonction de la stdlib
direnv
- des appels de fonction customisés
- du code shell (bash)
Un exemple de fichier .envrc
déposé dans un répertoire ~/workspaces/demo-direnv
:
export JAVA_HOME=/opt/jdk-17.0.1+12
export MAVEN_HOME=/opt/apache-maven-3.8.4
Ce fichier dĂ©clare deux variables d’environnement qui me sont utiles dans un projet Java.
Ă l’entrĂ©e dans le rĂ©pertoire contenant ce fichier, direnv
va tenter de charger le fichier. Les variables d’environnement exportĂ©es par le fichier seront alors chargĂ©es dans la session shell courante.
Au premier chargement d’un fichier, ou aprĂšs une modification, direnv
demandera une validation explicite pour autoriser le fichier.
~/workspaces > cd demo-direnv
direnv: error /home/jwittouck/workspaces/demo-direnv/.envrc is blocked. Run `direnv allow` to approve its content
J’exĂ©cute donc direnv allow
pour autoriser le chargement de mon fichier .envrc
:
~/workspaces/demo-direnv > direnv allow
direnv: loading ~/workspaces/demo-direnv/.envrc
direnv: export +JAVA_HOME +MAVEN_HOME
~/workspaces/demo-direnv >
direnv
nous indique qu’il a chargĂ© notre fichier, ainsi que nos deux variables d’environnement.
Nous pouvons maintenant les utiliser:
~/workspaces/demo-direnv > echo $JAVA_HOME
/opt/jdk-17.0.1+12
~/workspaces/demo-direnv > echo $MAVEN_HOME
/opt/apache-maven-3.8.4
Si on quitte le répertoire, les variables sont déchargées:
~/workspaces/demo-direnv > cd ..
direnv: unloading
~/workspaces > echo $JAVA_HOME
# rien ici !
Modification du PATH
Pour nous simplifier la vie, direnv
propose des fonctions qui permettent de manipuler le PATH
facilement. La fonction PATH_add
permet d’ajouter simplement une nouvelle valeur au PATH
. En voici un exemple dans mon fichier .envrc
précédent:
export JAVA_HOME=/opt/jdk-17.0.1+12
export MAVEN_HOME=/opt/apache-maven-3.8.4
PATH_add $JAVA_HOME/bin
PATH_add $MAVEN_HOME/bin
Avec cette nouvelle version de mon fichier, j’ai donc ajoutĂ© mes versions de java
et maven
au PATH
. Ces ajouts seront retirés à la sortie du répertoire:
# je rentre dans mon répertoire demo-direnv
~/workspaces > cd demo-direnv
direnv: loading ~/workspaces/demo-direnv/.envrc
direnv: export +JAVA_HOME +MAVEN_HOME ~PATH
# le $PATH a été modifié
~/workspaces/demo-direnv > java --version
openjdk 17.0.1 2021-10-19
OpenJDK Runtime Environment Temurin-17.0.1+12 (build 17.0.1+12)
OpenJDK 64-Bit Server VM Temurin-17.0.1+12 (build 17.0.1+12, mixed mode, sharing)
# je sors du répertoire
~/workspaces/demo-direnv > cd ..
direnv: unloading
# le $PATH ne contient plus la commande java
~/workspaces > java --version
zsh: command not found: java
Avec direnv
, je peux donc changer de version de java
dans mon PATH
, simplement en changeant de répertoire.
Utilisation avancée
Pour aller plus loin, direnv
propose une librairie de fonctions qu’ils nomment stdlib. Ces fonctions sont listĂ©es et documentĂ©es dans la documentation de direnv man/direnv-stdlib.1.
Voici quelques unes de ces commandes que j’utilise rĂ©guliĂšrement.
source_up
Cette commande permet d’aller chercher et exĂ©cuter le premier fichier .envrc
dans l’arborescence remontante des fichiers, ce qui permet de factoriser un peu le contenu de mes fichiers .envrc
.
Un exemple concret d’arborescence de fichiers:
.
âââ workspaces
  âââ .envrc
  âââ projet-java-11
  â âââ .envrc
 âââ projet-java-17
 âââ .envrc
Le fichier ~/workspaces/.envrc
contient les variables communes Ă mes deux projets:
export MAVEN_HOME=/opt/apache-maven-3.8.4
PATH_add $MAVEN_HOME/bin
Le fichier ~/workspaces/projet-java-11/.envrc
contient une configuration pour Java 11, ainsi que la commande source_up
qui permet de charger le fichier ~/workspaces/.envrc
:
source_up
export JAVA_HOME=/opt/jdk-11.0.13+8
PATH_add $JAVA_HOME/bin
Le fichier ~/workspaces/projet-java-17/.envrc
contient une configuration similaire pour Java 17:
source_up
export JAVA_HOME=/opt/jdk-17.0.1+12
PATH_add $JAVA_HOME/bin
Avec cette utilisation, la variable MAVEN_HOME
est disponible dans les sous-répertoires. Cette configuration permet de factoriser mes fichiers .envrc
pour tous mes projets.
dotenv
direnv
peut aussi scruter les fichiers .env
, qui doivent exposer les variables d’environnement sous forme de clĂ©/valeur. Les fichiers .env
sont moins souple car aucun script ne peut y ĂȘtre Ă©crit. La commande dotenv
peut néanmoins aider si des .env
existent déjà sur un projet.
Voici un exemple de fichier .env
:
AWS_ACCESS_KEY_ID=xxxx-xxx-xxx-xxxx
AWS_SECRET_ACCESS_KEY=xxxx-xxx-xxx-xxxx
Et un exemple de fichier .envrc
qui charge le fichier .env
:
dotenv
Dans le cas oĂč beaucoup de projets utilisent des .env
, on peut aussi configurer direnv
pour charger ces fichiers automatiquement, en plus des .envrc
(qui restent chargés en priorité)
Cette configuration se fait dans ~/.config/direnv/direnv.toml
:
[global]
load_dotenv = true
whitelist
Par défaut, pour chaque fichier .envrc
, nouveau ou modifié, direnv
affichera ce message:
direnv: error .envrc is blocked. Run `direnv allow` to approve its content
Il faut donc utiliser la commande direnv allow
pour autoriser ces fichiers. Cela peut ĂȘtre assez rĂ©barbatif quand cela arrive sur de nombreux projets.
direnv
fournit une configuration permettant de whitelister les fichiers et de les autoriser automatiquement. J’y ai ajoutĂ© mon rĂ©pertoire de travail. Cette configuration se fait dans ~/.config/direnv/direnv.toml
:
[whitelist]
prefix = ["/home/jwittouck/workspaces"]
Fonction customisées
Pour amĂ©liorer l’exemple plus haut concernant la gestion de la variable JAVA_HOME
, il est aussi possible d’enrichir les fonctions disponibles de direnv
.
Pour cela, il faut les ajouter au fichier ~/.config/direnv/direnvrc
.
Pour mon usage, j’ai crĂ©Ă© cette fonction :
function use_java(){
echo "Using Java version $1"
export JAVA_HOME=$(find /opt -maxdepth 1 -type d -name "jdk-$1*")
echo "Loading JAVA_HOME $JAVA_HOME"
PATH_add $JAVA_HOME/bin
}
Tous mes JDK sont installés dans /opt
. Cette fonction permet de trouver le JDK qui correspond au premier paramĂštre de la fonction et de positionner les variables JAVA_HOME
et PATH
.
Elle s’utilise dans un .envrc
de cette maniĂšre:
use_java 17
# ou
# use_java 11
et voici ce que loggue direnv
Ă l’entrĂ©e du rĂ©pertoire :
~/workspaces > cd demo-direnv
direnv: loading ~/workspaces/demo-direnv/.envrc
direnv: using java 17
Using Java version 17
Loading JAVA_HOME /opt/jdk-17.0.1+12
direnv: export +JAVA_HOME +MAVEN_HOME ~PATH
Conclusion
direnv
est un outil trĂšs pratique pour manipuler les variables d’environnement. Il s’adresse avant tout Ă ceux qui passent du temps dans un shell, devs ou sysadmins.
Cet article a prĂ©sentĂ© principalement les usages que j’en ai pour mes projets Java, mais direnv
propose aussi des fonctions pour les projets node
, ruby
, python
et d’autres.
C’est vite devenu un indispensable dans mes shells.
Liens
- la page d’accueil du projet sur direnv.net
- le repository Github du projet direnv/direnv
- la documentation d’install docs/installation
- la documentation de la stdlib man/direnv-stdlib