diff --git a/lib/uinst/conf b/lib/uinst/conf index 991786b..2d07b90 100644 --- a/lib/uinst/conf +++ b/lib/uinst/conf @@ -30,6 +30,7 @@ done ./mediawiki --nutools-makelinks ./uawk --nutools-makelinks ./udist --nutools-makelinks +./ulink --nutools-makelinks # copier le fichier .nutoolsrc [ -f ~/.nutoolsrc ] || cp lib/nutoolsrc ~/.nutoolsrc diff --git a/lib/ulib/.ulibver b/lib/ulib/.ulibver index 84c3b5a..6b9e324 100644 --- a/lib/ulib/.ulibver +++ b/lib/ulib/.ulibver @@ -1 +1 @@ -007016000 +007017000 diff --git a/lib/ulib/base b/lib/ulib/base index a112644..b4c8fcf 100644 --- a/lib/ulib/base +++ b/lib/ulib/base @@ -873,6 +873,25 @@ function move_link() { mv "$link" "$dest" fi } +function copy_link() { + # Copier le lien $1 vers $2, et mettre à jour la destination du lien si + # elle est exprimée de façon relative + # Si $1 n'est pas un lien, le copier normalement avec cp + [ -n "$1" -a -n "$2" ] || return 1 + local link="$1" dest="$2" + [ -d "$dest" ] && dest="$dest/$(basename -- "$link")" + dest="$(abspath "$dest")" + if [ -L "$link" ]; then + link="$(abspath "$link")" + [ "$dest" == "$link" ] && return 0 + ldest="$(readlinka "$link")" + cp -P "$link" "$dest" || return 1 + update_link "$ldest" "$dest" + else + [ "$dest" == "$link" ] && return 0 + cp "$link" "$dest" + fi +} function array_find_links() { # Chercher dans le répertoire $3 (qui est par défaut le répertoire courant) # les liens vers le fichier $2, et ajouter leurs chemins absolus dans le diff --git a/lib/ulib/base.tools b/lib/ulib/base.tools index a5f0f92..90df987 100644 --- a/lib/ulib/base.tools +++ b/lib/ulib/base.tools @@ -21,7 +21,7 @@ function base_umove() { eerror_if [ $# -eq 1 ] "Vous devez spécifier la destination" || return local -a srcs - local dest + local src dest srcs=("$@") setx dest=last_value srcs @@ -57,16 +57,87 @@ function base_umove() { eerror "$dest: doit être un répertoire" return 1 } + local r=0 for src in "${srcs[@]}"; do if [ -n "$updatedir" ]; then if [ -L "$src" ]; then - move_link "$src" "$dest" + move_link "$src" "$dest" || r=$? else array_find_links update_links "$src" "$updatedir" - move_file "$src" "$dest" "${update_links[@]}" + move_file "$src" "$dest" "${update_links[@]}" || r=$? fi else - move_link "$src" "$dest" + move_link "$src" "$dest" || r=$? fi done + return $r +} + +function base_udelete() { +# Outil de haut niveau pour supprimer un fichier ou un lien. Si on doit +# supprimer un fichier, et que l'option '-d UPDATEDIR' est spécifiée, et que des +# liens du répertoire UPDATEDIR pointent vers le fichier supprimé, ces liens +# sont supprimés aussi. + local -a args + local updatedir + args=(-d:,--updatedir: .) + parse_args_check "$@" || return; set -- "${args[@]}" + + eerror_unless [ -z "$updatedir" -o -d "$updatedir" ] "$updatedir: doit être un répertoire" || return + eerror_if [ $# -eq 0 ] "Vous devez spécifier les fichiers à supprimer" || return + + local file r=0 + for file in "$@"; do + if [ -n "$updatedir" ]; then + if [ -L "$file" ]; then + rm "$file" || r=$? + else + array_find_links update_links "$file" "$updatedir" + rm "$file" "${update_links[@]}" || r=$? + fi + else + rm "$file" || r=$? + fi + done + return $r +} + +function base_ucopy() { +# Outil de haut niveau pour copier un fichier ou un lien. Si c'est un lien qui +# est copié, la destination du lien est mise à jour si elle est relative. + eerror_if [ $# -eq 0 ] "Vous devez spécifier les fichiers à copier" || return + eerror_if [ $# -eq 1 ] "Vous devez spécifier la destination" || return + + local -a srcs + local src dest + + srcs=("$@") + setx dest=last_value srcs + array_del_last srcs + + if [ $# -eq 2 ]; then + # S'il n'y a que deux arguments, permettre que le deuxième argument ne + # soit pas un répertoire + if [ -d "$dest" ]; then + : # ce cas sera traité ci-dessous + elif [ -e "$dest" ]; then + eerror "$dest: refus d'écraser la destination" + return 1 + else + src="${srcs[0]}" + copy_link "$src" "$dest" + return $? + fi + fi + + # S'il y a plus de deux arguments, il FAUT que dest soit un répertoire + [ -d "$dest" ] || { + eerror "$dest: doit être un répertoire" + return 1 + } + local r=0 + for src in "${srcs[@]}"; do + copy_link "$src" "$dest" || r=$? + done + return $r } diff --git a/ulink b/ulink new file mode 100755 index 0000000..34c797f --- /dev/null +++ b/ulink @@ -0,0 +1,82 @@ +#!/bin/bash +# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 +function display_help() { + uecho "$scriptname: déplacer, supprimer, copier un fichier ou un lien + +Quand on déplace ou qu'on copie un lien, la destination du lien est mise à jour + +USAGE + $scriptname mv files... dest + $scriptname cp files... dest + $scriptname rm files... + +OPTIONS + -d UPDATEDIR + Chercher dans UPDATEDIR tous les liens qui pointent vers le fichier + concerné, et mettre à jour ces liens après avoir déplacé le fichier, ou + supprimer ces liens si le fichier est supprimé." +} + +SCRIPT_ALIASES=(#alias:command + umove:move + udelete:delete + ucopy:copy +) +CMD_ALIASES=( + mv:move + rm:delete remove:delete del:delete + cp:copy +) +DEFAULT_CMD=move + +if [ "$#" -eq 1 -a "$1" == --nutools-makelinks ]; then + # créer les liens + scriptname="$(basename "$0")" + for alias in "${SCRIPT_ALIASES[@]}"; do + alias="${alias%:*}" + ln -s "$scriptname" "$alias" + done + exit 0 +fi + +source "$(dirname "$0")/lib/ulib/ulib" || exit 1 +urequire DEFAULTS + +# Traduire le nom du script +for script_alias in "${SCRIPT_ALIASES[@]}"; do + splitpair "$script_alias" src dest + if [ "$scriptname" == "$src" ]; then + eval "set -- $dest \"\$@\"" + scriptname=ulink + break + fi +done + +args=(--help '$exit_with display_help' -d:,--updatedir: .) +parse_args "$@"; set -- "${args[@]}" + +# Traduire la commande +[ -n "$*" ] || set -- "$DEFAULT_CMD" +cmd= +found_cmd= +while [ -z "$found_cmd" ]; do + cmd="$1"; shift; found_cmd=1 + [ -n "$cmd" ] || break + + for cmd_alias in "${CMD_ALIASES[@]}"; do + splitpair "$cmd_alias" src dest + if [ "$cmd" == "$src" ]; then + eval "set -- $dest \"\$@\"" + found_cmd= + break + fi + done +done + +case "$cmd" in +"") exit_with display_help;; +move) base_umove ${updatedir:+-d "$updatedir"} "$@";; +delete) base_udelete ${updatedir:+-d "$updatedir"} "$@";; +copy) base_ucopy "$@";; +*) die "$cmd: commande incorrecte";; +esac diff --git a/umove b/umove deleted file mode 100755 index 01e2c5d..0000000 --- a/umove +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 -source "$(dirname "$0")/lib/ulib/ulib" || exit 1 -urequire DEFAULTS - -function display_help() { - uecho "$scriptname: déplacer un fichier ou un lien - -Quand on déplace un lien, la destination du lien est mise à jour - -USAGE - $scriptname files... dest - -OPTIONS - -d UPDATEDIR - Chercher dans UPDATEDIR tous les liens qui pointent vers le fichier - déplacé, et mettre à jour ces liens après avoir déplacé le fichier" -} - -args=(--help '$exit_with display_help' -d:,--updatedir: .) -parse_args "$@"; set -- "${args[@]}" - -base_umove ${updatedir:+-d "$updatedir"} "$@"