327 lines
11 KiB
Bash
327 lines
11 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
|
|
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() {
|
|
local hostname="${HOSTNAME%%.*}"
|
|
shared_profiledestdir="$HOME/etc/profile.d"
|
|
shared_bashrcdestdir="$HOME/etc/bashrc.d"
|
|
shared_defaultdestdir="$HOME/etc/default"
|
|
profiledestdir="$HOME/etc/profile.${hostname}.d"
|
|
bashrcdestdir="$HOME/etc/bashrc.${hostname}.d"
|
|
defaultdestdir="$HOME/etc/default.${hostname}"
|
|
}
|
|
|
|
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 projdir="$1" profiledir="$2" bashrcdir="$3" defaultdir="$4"
|
|
local tmpfile
|
|
local prefix envsrcdir envdestdir shadestdir envfiles envfile envsrc envdest shadest
|
|
local shared_profiledestdir shared_bashrcdestdir shared_defaultdestdir
|
|
local profiledestdir bashrcdestdir defaultdestdir
|
|
uenv_set_destdirs
|
|
|
|
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" "$shadestdir"
|
|
|
|
array_from_lines envfiles "$(list_files "$envsrcdir")"
|
|
for envfile in "${envfiles[@]}"; do
|
|
if [ "${envfile%.shared}" != "$envfile" ]; then
|
|
# Avec l'extension .shared, toujours installer dans le
|
|
# répertoire des profils partagés
|
|
envsrc="$envsrcdir/$envfile"
|
|
envfile="${envfile%.shared}"
|
|
shadest="$shadestdir/$envfile"
|
|
envdest="$shadest"
|
|
else
|
|
envsrc="$envsrcdir/$envfile"
|
|
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
|
|
|
|
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" "$actual_envdestdir"
|
|
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" "$actual_envdestdir"
|
|
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"
|
|
}
|