351 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			351 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
| ##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
 | |
| ## Gestion de la mise à jour des fichiers de ~/etc/{profile.d,bashrc.d,default}
 | |
| ##@cooked nocomments
 | |
| ##@require base
 | |
| ##@require uenv
 | |
| uprovide uenv_update
 | |
| urequire base uenv
 | |
| 
 | |
| function __uenv_move_after() {
 | |
|     # Dans le fichier $1, déplacer la ligne $2 après la ligne commençant par
 | |
|     # l'expression régulière '^$3:'
 | |
|     # Si la ligne $2 n'existe pas, ne rien faire
 | |
|     # Si la ligne $3 n'existe pas ou vaut '*', mettre la ligne $2 en dernier.
 | |
|     # Si $4 est spécifié, l'utiliser comme fichier temporaire.
 | |
|     local tmpfile="$4"
 | |
|     [ -n "$tmpfile" ] || ac_set_tmpfile tmpfile
 | |
| 
 | |
|     # XXX Il faudrait quoter $3 pour éviter les caractères spéciaux de grep!
 | |
|     if quietgrep -F "$2" "$1"; then
 | |
|         local re_after="$3"
 | |
|         [ "$re_after" != "*" ] && re_after="^$re_after:"
 | |
|         if [ "$re_after" != "*" ] && quietgrep "$re_after" "$1"; then
 | |
|             awkrun line="$2" re_after="$re_after" '
 | |
| BEGIN {
 | |
|     found_line = 0
 | |
|     found_after = 0
 | |
| }
 | |
| ! found_line && $0 == line {
 | |
|     found_line = 1
 | |
|     if (! found_after) {
 | |
|         next
 | |
|     }
 | |
| }
 | |
| ! found_after && $0 ~ re_after {
 | |
|     found_after = 1
 | |
|     if (found_line) {
 | |
|         # si nous avons trouvé la ligne avant re_after, la mettre juste après
 | |
|         # sinon, pas la peine de faire de modification
 | |
|         print
 | |
|         print line
 | |
|         next
 | |
|     }
 | |
| }
 | |
| { print }
 | |
| END {
 | |
|     if (! found_after && re_after == "*") {
 | |
|         if (found_line) {
 | |
|             print line
 | |
|         }
 | |
|     }
 | |
| }' <"$1" >"$tmpfile" &&
 | |
|             cat "$tmpfile" >"$1"
 | |
|         else
 | |
|             grep -vF "$2" "$1" >"$tmpfile"
 | |
|             echo "$2" >>"$tmpfile"
 | |
|             cat "$tmpfile" >"$1"
 | |
|         fi
 | |
|     fi
 | |
| }
 | |
| 
 | |
| function __uenv_move_before() {
 | |
|     # Dans le fichier $1, déplacer la ligne $2 avant la ligne commençant par
 | |
|     # l'expression régulière '^$3:'
 | |
|     # Si la ligne $2 n'existe pas, ne rien faire
 | |
|     # Si la ligne $3 n'existe pas ou vaut '*', mettre la ligne $2 en premier.
 | |
|     # Si $4 est spécifié, l'utiliser comme fichier temporaire.
 | |
|     local tmpfile="$4"
 | |
|     [ -n "$tmpfile" ] || ac_set_tmpfile tmpfile
 | |
| 
 | |
|     # XXX Il faudrait quoter $3 pour éviter les caractères spéciaux de grep!
 | |
|     if quietgrep -F "$2" "$1"; then
 | |
|         local re_before="$3"
 | |
|         [ "$re_before" != "*" ] && re_before="^$re_before:"
 | |
|         if [ "$re_before" != "*" ] && quietgrep "$re_before" "$1"; then
 | |
|             awkrun line="$2" re_before="$re_before" '
 | |
| BEGIN {
 | |
|     found_line = 0
 | |
|     found_before = 0
 | |
| }
 | |
| ! found_line && $0 == line {
 | |
|     found_line = 1
 | |
|     if (found_before) {
 | |
|         next
 | |
|     }
 | |
| }
 | |
| ! found_before && ($0 ~ re_before || re_before == "*") {
 | |
|     found_before = 1
 | |
|     if (! found_line) {
 | |
|         print line
 | |
|         print
 | |
|         next
 | |
|     }
 | |
| }
 | |
| { print }
 | |
| ' <"$1" >"$tmpfile" &&
 | |
|             cat "$tmpfile" >"$1"
 | |
|         else
 | |
|             echo "$2" >"$tmpfile"
 | |
|             grep -vF "$2" "$1" >>"$tmpfile"
 | |
|             cat "$tmpfile" >"$1"
 | |
|         fi
 | |
|     fi
 | |
| }
 | |
| 
 | |
| function uenv_update_dir() {
 | |
|     # Mettre à jour l'ordre de chargement pour le répertoire $1 qui contient des
 | |
|     # fichiers de profil pour le shell. L'ordre dans lequel le fichiers de
 | |
|     # profil doivent être chargé est écrit dans le fichier $1/.source_in_order
 | |
|     # Si $2 est spécifié, il s'agit d'un fichier temporaire utilisé pour les
 | |
|     # calculs de l'ordre des chargements.
 | |
|     # $3(=$1) est le répertoire de destination. Si $1 est un répertoire de
 | |
|     # préparation temporaire, on peut spécifier grâce à $3 quel est le
 | |
|     # répertoire final après préparation.
 | |
|     # S'ils sont spécifiés, les arguments $4..* sont des répertoires contenant
 | |
|     # des fichiers de profils supplémentaires qu'il faut considérer aussi. Dans
 | |
|     # ce cas, $3 est ignoré.
 | |
|     local dir="$(abspath "$1")"; shift
 | |
|     local tmpfile="$1"; shift
 | |
|     local destdir="${1:-$dir}"; shift
 | |
|     local sio="$dir/.source_in_order"
 | |
|     local before after file filename
 | |
|     local -a files
 | |
| 
 | |
|     [ -n "$tmpfile" ] || ac_set_tmpfile tmpfile
 | |
|     [ $# -gt 0 ] && destdir=
 | |
|     set -- "$dir" "$@"
 | |
| 
 | |
|     local __uname_system="$UNAME_SYSTEM"
 | |
|     local __myhostname="$MYHOSTNAME"
 | |
|     >"$sio"
 | |
|     for dir in "$@"; do
 | |
|         [ -n "$dir" ] || continue
 | |
|         for file in "$dir/"*; do
 | |
|             [ -f "$file" ] || continue
 | |
|             files=("${files[@]}" "$file")
 | |
|             filename="$(basename -- "$file")"
 | |
|             __uenv_check_file "$dir" "$filename" && echo "$filename:$file" >>"$sio"
 | |
|         done
 | |
|     done
 | |
| 
 | |
|     # traiter d'abord les fichiers qui ont '@before *' ou '@after *'
 | |
|     local -a nfiles
 | |
|     for file in "${files[@]}"; do
 | |
|         filename="$(basename -- "$file")"
 | |
| 
 | |
|         before="$(<"$file" awk '$0 ~ /^##@before / { print $2; exit 0 }')"
 | |
|         if [ "$before" == "*" ]; then
 | |
|             __uenv_move_before "$sio" "$filename:$file" "$before" "$tmpfile"
 | |
|         else
 | |
|             array_set nfiles "$file"
 | |
|         fi
 | |
| 
 | |
|         after="$(<"$file" awk '$0 ~ /^##@after / { print $2; exit 0 }')"
 | |
|         if [ "$after" == "*" ]; then
 | |
|             __uenv_move_after "$sio" "$filename:$file" "$after" "$tmpfile"
 | |
|         else
 | |
|             array_set nfiles "$file"
 | |
|         fi
 | |
|     done
 | |
|     # Ensuite traiter les autres fichiers.
 | |
|     # L'opération est faite en deux temps parce que si A est avant B, et que B
 | |
|     # est avant *, si A est traité avant B, A risque de se trouver après B si B
 | |
|     # est déplacé au début de la liste.
 | |
|     for file in "${nfiles[@]}"; do
 | |
|         filename="$(basename -- "$file")"
 | |
| 
 | |
|         before="$(<"$file" awk '$0 ~ /^##@before / { print $2; exit 0 }')"
 | |
|         [ -n "$before" -a "$before" != "*" ] && __uenv_move_before "$sio" "$filename:$file" "$before" "$tmpfile"
 | |
| 
 | |
|         after="$(<"$file" awk '$0 ~ /^##@after / { print $2; exit 0 }')"
 | |
|         [ -n "$after" -a "$after" != "*" ] && __uenv_move_after "$sio" "$filename:$file" "$after" "$tmpfile"
 | |
|     done
 | |
| 
 | |
|     awkrun destdir="$destdir" '{
 | |
|   pos = match($0, /:/)
 | |
|   if (pos != 0) {
 | |
|     filename = substr($0, 1, pos - 1)
 | |
|     file = substr($0, pos + 1)
 | |
|     if (destdir != "") {
 | |
|       print "source " destdir "/" filename
 | |
|     } else {
 | |
|       print "source " file
 | |
|     }
 | |
|   } else {
 | |
|     print "source " destdir "/" $0
 | |
|   }
 | |
| }' <"$sio" >"$tmpfile" &&
 | |
|     cat "$tmpfile" >"$sio"
 | |
| }
 | |
| 
 | |
| function uenv_set_destdirs() {
 | |
|     if [ "$1" == --local-profiles ]; then
 | |
|         local hostname="${HOSTNAME%%.*}"
 | |
|         profiledestdir="$HOME/etc/profile.${hostname}.d"
 | |
|         bashrcdestdir="$HOME/etc/bashrc.${hostname}.d"
 | |
|         defaultdestdir="$HOME/etc/default.${hostname}"
 | |
|         shared_profiledestdir="$HOME/etc/profile.d"
 | |
|         shared_bashrcdestdir="$HOME/etc/bashrc.d"
 | |
|         shared_defaultdestdir="$HOME/etc/default"
 | |
|     else
 | |
|         profiledestdir="$HOME/etc/profile.d"
 | |
|         bashrcdestdir="$HOME/etc/bashrc.d"
 | |
|         defaultdestdir="$HOME/etc/default"
 | |
|         shared_profiledestdir=
 | |
|         shared_bashrcdestdir=
 | |
|         shared_defaultdestdir=
 | |
|     fi
 | |
| }
 | |
| 
 | |
| function uenv_sourced_in() {
 | |
|     # vérifier que l'un des fichiers $2..$* est sourcé dans $1
 | |
|     local src="$1"; shift
 | |
|     local file
 | |
|     for file in "$@"; do
 | |
|         grep -q "\\.[ \\t]*$file\$" "$src" && return 0
 | |
|         grep -q "source[ \\t]*$file\$" "$src" && return 0
 | |
|     done
 | |
|     return 1
 | |
| }
 | |
| 
 | |
| function uenv_configure_profiles() {
 | |
|     local destdir="$1"
 | |
|     local LEGACY_PROFILE="$HOME/.profile"
 | |
|     local PROFILE="$HOME/.bash_profile"
 | |
|     local BASHRC="$HOME/.bashrc"
 | |
| 
 | |
|     if [ ! -f "$PROFILE" ]; then
 | |
|         echo "# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
 | |
| 
 | |
| if [ -f ~/.bashrc ]; then
 | |
|     . ~/.bashrc
 | |
| fi" >"$PROFILE"
 | |
|     fi
 | |
|     if [ ! -f "$BASHRC" ]; then
 | |
|         touch "$BASHRC"
 | |
|     fi
 | |
| 
 | |
|     if [ -f "$LEGACY_PROFILE" ]; then
 | |
|         if ! uenv_sourced_in "$PROFILE" "~/.profile"; then
 | |
|             ewarn "\
 | |
| ~/.profile existe, il contient peut-être des instructions utiles. Si c'est le
 | |
| cas, il faut décommenter la ligne dans ~/.bash_profile qui source ~/.profile"
 | |
|             estep "Configuration de l'inclusion de ~/.profile dans $PROFILE"
 | |
|             echo >>"$PROFILE" "
 | |
| # decommenter si ~/.profile contient des commandes utiles
 | |
| #[ -f ~/.profile ] && source ~/.profile"
 | |
|         fi
 | |
|     fi
 | |
| 
 | |
|     if ! uenv_sourced_in "$PROFILE" "$destdir/profile"; then
 | |
|         estep "Configuration de l'inclusion de $destdir/profile"
 | |
|         echo >>"$PROFILE" "
 | |
| # source $destdir/profile.d scripts
 | |
| [ -f \"$destdir/profile\" ] && source $destdir/profile"
 | |
|     fi
 | |
| 
 | |
|     if ! uenv_sourced_in "$BASHRC" "$destdir/bashrc"; then
 | |
|         estep "Configuration de l'inclusion de $destdir/bashrc"
 | |
|         echo >>"$BASHRC" "
 | |
| # source $destdir/bashrc.d scripts
 | |
| [ -f \"$destdir/bashrc\" ] && source $destdir/bashrc"
 | |
|     fi
 | |
| }
 | |
| 
 | |
| function uenv_install_profiles() {
 | |
|     local local_profiles
 | |
|     if [ "$1" == --local-profiles ]; then
 | |
|         local_profiles=1
 | |
|         shift
 | |
|     fi
 | |
|     local projdir="$1" profiledir="$2" bashrcdir="$3" defaultdir="$4"
 | |
|     local tmpfile shared
 | |
|     local prefix envsrcdir envdestdir shadestdir envfiles envfile envsrc envdest shadest
 | |
|     local shared_profiledestdir shared_bashrcdestdir shared_defaultdestdir
 | |
|     local profiledestdir bashrcdestdir defaultdestdir
 | |
|     uenv_set_destdirs ${local_profiles:+--local-profiles}
 | |
| 
 | |
|     ac_set_tmpfile tmpfile
 | |
|     for prefix in profile bashrc default; do
 | |
|         envsrcdir="${prefix}dir"; envsrcdir="$projdir/${!envsrcdir}"
 | |
|         envdestdir="${prefix}destdir"; envdestdir="${!envdestdir}"
 | |
|         shadestdir="shared_${prefix}destdir"; shadestdir="${!shadestdir}"
 | |
|         [ -n "$envsrcdir" -a -d "$envsrcdir" ] || continue
 | |
|         mkdir -p "$envdestdir"
 | |
|         [ -n "$shadestdir" ] && mkdir -p "$shadestdir"
 | |
| 
 | |
|         array_from_lines envfiles "$(list_files "$envsrcdir")"
 | |
|         for envfile in "${envfiles[@]}"; do
 | |
|             envsrc="$envsrcdir/$envfile"
 | |
|             if [ "${envfile%.shared}" != "$envfile" ]; then
 | |
|                 envfile="${envfile%.shared}"
 | |
|                 shared=1
 | |
|             else
 | |
|                 shared=
 | |
|             fi
 | |
| 
 | |
|             if [ -n "$shadestdir" ]; then
 | |
|                 if [ -n "$shared" ]; then
 | |
|                     # si fichier partagé, toujours le copier dans le répertoire
 | |
|                     # des fichiers partagés
 | |
|                     envdest="$shadestdir/$envfile"
 | |
|                 else
 | |
|                     envdest="$envdestdir/$envfile"
 | |
|                     shadest="$shadestdir/$envfile"
 | |
|                     if [ ! -f "$envdest" -a -f "$shadest" ]; then
 | |
|                         # Si déjà installé en partagé, continuer à mettre à jour ce
 | |
|                         # fichier-là
 | |
|                         envdest="$shadest"
 | |
|                     fi
 | |
|                 fi
 | |
|             else
 | |
|                 envdest="$envdestdir/$envfile"
 | |
|             fi
 | |
| 
 | |
|             local actual_envdestdir="$(dirname -- "$envdest")"
 | |
|             if [ ! -f "$envdest" ]; then
 | |
|                 estep "Installation du profil par défaut $envfile dans $(ppath "$actual_envdestdir")"
 | |
|                 /bin/cp -f "$envsrc" "$envdest"
 | |
|             elif [ "$prefix" == "default" ]; then
 | |
|                 # ne jamais mettre à jour dans default
 | |
|                 if testdiff "$envdest" "$envsrc"; then
 | |
|                     estepi "Le profil $(ppath "$envdest") a été conservé"
 | |
|                 fi
 | |
|             elif endswith "$envfile" ".userconf"; then
 | |
|                 # ne jamais mettre à jour les fichiers .userconf
 | |
|                 if testdiff "$envdest" "$envsrc"; then
 | |
|                     estepi "Le profil $(ppath "$envdest") a été conservé"
 | |
|                 fi
 | |
|             elif testdiff "$envdest" "$envsrc"; then
 | |
|                 estep "Le profil par défaut $envfile dans $(ppath "$actual_envdestdir") a été modifié"
 | |
|                 if show_info; then
 | |
|                     eecho "Voici les différences détectées:"
 | |
|                     eecho ""
 | |
|                     diff -u "$envdest" "$envsrc" 1>&2
 | |
|                     eecho ""
 | |
|                 fi
 | |
| 
 | |
|                 if ask_yesno "Faut-il remplacer $(ppath "$envdest") par le profil par défaut?" O; then
 | |
|                     /bin/cp -f "$envsrc" "$envdest"
 | |
|                 fi
 | |
|             fi
 | |
|         done
 | |
| 
 | |
|         if [ "$prefix" != "default" ]; then
 | |
|             estep "Mise à jour de l'ordre de lecture de $(ppath "$envdestdir")"
 | |
|             uenv_update_dir "$envdestdir" "$tmpfile" "" "$shadestdir"
 | |
|         fi
 | |
|     done
 | |
|     ac_clean "$tmpfile"
 | |
| }
 |