Sommaire
Avant propos
make
Make est un bon outil et je me suis inspiré de la lecture de ce manuel pour concevoir l'exemple.
Pourquoi bash ?
Depuis que je code en entreprise et à la maison, sous linux/BSD autant que windows j'ai toujours eu accès à bash et aux GNU coreutils.
Quand vous installer git for windows vous installez plus que bash, vous installez, les Core Utils (dont mount et chroot), vous avez un tty (celui de mingw qui est un peu buggué), une arborescence de système linux, ssh, sftp, perl, make (oui), tk/tcl … ET VIM \o/
Tout ce qu'il faut pour bootstrapper un environnement à la linux surtout si vous ajoutez dans la soupe un gestionnaire de paquet que ce soit scoop ou (je n'ai pas essayé) pkgsrc
Bash est devenu ipso facto grâce à l'installation de git sur windows la stack de dév. pour un devops la plus portable. Le truc qui rappelle l'informatique des années Commodore 64, où partout où l'on arrive on trouve une invite pour coder standardisée.
Bake le design
Quand j'ai regardé le tuto de make j'ai vu le pattern qui me plaisait: une série de description :
- état actuel, qui produit un artefact
- une liste de dépendance pour arriver à l'état
- un corps de « code » qui permet de faire la transition à l'état suivant.
par contre, chose qui me déplaît les artefacts de dépendances ne peuvent pas être genre des ports tcp ouverts (ex: si port 53 pas ouvert alors démarrer DNS).
J'ai décidé de faire une projection de make en bash avec une pile d'appel que l'on manipule explicitement.
Voici le code dont le cœur qui nous intéresse est à la ligne 53
#!/usr/bin/env bash
set -e
declare -a action;
RD='\e[31m'
GB='\e[33m'
BL='\e[34m'
RZ='\e[0m'
DEBUG=${DEBUG:-1}
ONE_VAR=${ONE_VAR:-template.dot}
echo -e "${GB}REPRODUCIBLE BUILD WITH"
echo -e "-----------------------$RZ"
echo
for var in DEBUG ONE_VAR;
do
printf "%s='%s' " "$var" "$( eval eval echo \\$\$var)"
done
echo -n $0 $@
echo
echo
d() {
[ -z "$DEBUG" ] || echo -e "DEBUG:$(date +"%H:%M:%S"):$BL $* $RZ"
}
[ -d out ] || mkdir out
push() {
local stack
declare -a stack
stack=( "$@" )
for ((i=${#@}; i--; i)); do
action=( "${stack[$i]}" "${action[@]}" );
done
}
pop() {
declare -n v=$1
v=${action[0]}
action=("${action[@]:1}")
}
set +x
dispatch_action() {
while [[ ${#action} -gt 0 ]]; do
pop act
d "DISPATCHING $act"
case $act in
all)
[ -f out/this ] || push "before" ; dispatch_action
touch out/that
d all bells and whistles
push "clean" ; dispatch_action
;;
before)
[ -f out/init ] || push init; dispatch_action
d after init before all and clean
touch out/this
;;
init)
d init : begin all
touch out/init
;;
clean)
d clean everything
set +e
d out/*
rm out/*
set -e
;;
*)
echo unrecognized "$act";
d "${action[@]}"
break
;;
esac
done
}
if [ ! -z $1 ]; then
action=( "$@" );
else
push "all"
fi
dispatch_action
d fin
Le cœur de faire son makefile à la bash consiste à peupler le switch case des états qu'on veut, en prélude de faire ses tests de prérequis et pousser/appeler la boucle de dispatch si nécessaire, puis exécuter son code.
L’exemple ci dessus donne les sorties suivantes :
$ ./make.bash all
REPRODUCIBLE BUILD WITH
-----------------------
DEBUG='1' ONE_VAR='template.dot' ./make.bash all
DEBUG:10:08:50: DISPATCHING all
DEBUG:10:08:50: DISPATCHING before
DEBUG:10:08:50: DISPATCHING init
DEBUG:10:08:50: init : begin all
DEBUG:10:08:50: after init before all and clean
DEBUG:10:08:50: all bells and whistles
DEBUG:10:08:50: DISPATCHING clean
DEBUG:10:08:50: clean everything
DEBUG:10:08:50: out/init out/that out/this
DEBUG:10:08:50: fin
Ce qui est ce qu'on attend d'un make all
Maintenant faisons un make before puis un make all
$ ./make.bash all
REPRODUCIBLE BUILD WITH
-----------------------
DEBUG='1' ONE_VAR='template.dot' ./make.bash all
DEBUG:10:10:20: DISPATCHING all
DEBUG:10:10:20: all bells and whistles
DEBUG:10:10:20: DISPATCHING clean
DEBUG:10:10:20: clean everything
DEBUG:10:10:20: out/init out/that out/this
DEBUG:10:10:20: fin
on a bien la propriété des makefiles de ne pas refaire une étape si la dépendance est ouverte
Limites et avantages de l'approche
les wildcards
Si un truc vous manque de make et que c'est les jokers (wildcard) alors cet outil n'est pas fait pour vous ; je ne vois absolument pas comment coder facilement cette fonctionnalité.
pousser des actions futures
En make on ne peut que déclarer les dépendances ici, on peut (voir all) pousser des actions futures. Je suis sûr que c'est une mauvaise idée, mais c'est faisable.
les makes récursifs
Je ne me suis pas penché sur le problème, mais je crois bien que cette fonctionnalité ne m'est pas accessible :)
Conclusion
En résumé, bash n'est pas qu'un shell, c'est aussi un environnement de programmation.
La Gnu/Basherie ultime que déteste la secte concurrent de la mienne qu'est le POSIX-shismes ce sont les tableaux.
Et pourtant avoir des tableaux (dont associatifs) permet de faire des chouettes trucs en bash (voir les primitives push et pop).
La programmation ce n'est pas que sortir un résultat avec un langage bien branlé, c'est aussi s'en sortir avec un langage bringuebalant.

# un exemple de la vraie vie
Posté par Jul (site web personnel) . Évalué à 1 (+0/-0).
Un exemple de vraie vie est ici https://gist.github.com/jul/9c3fb387e06a832815cb5de8685217bc
Envoyer un commentaire
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.