#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
source "$(dirname -- "$0")/lib/ulib/auto" || exit 1

function display_help() {
    uecho "$scriptname: mettre à jour un module ur/* ou lib/* sans utiliser composer

ça permet de faire du développement plus rapidement sans utiliser les dépôts de
type path

USAGE
    $scriptname modules...

OPTIONS
    -n, --fake
        Afficher simplement ce qui serait fait
    -q, --quiet
        Ne pas lancer rsync en mode verbose
    -g, --no-wait
        Ne pas attendre avant de faire git commit
    --rsync
        Mettre à jour les répertoires dans vendor/ qui ne sont pas des liens
        symboliques à partir des projets dépendants correspondants. Les liens
        symboliques créés avec --link sont ignorés. C'est l'option par défaut.
    -l, --link
        Transformer les clones de dépôts dans vendor/ en liens symboliques vers
        les projets dépendants correpondants.
    -k, --copy
        Transformer les liens symboliques dans vendor/ en copies des projets
        dépendants correspondants. Les répertoires qui ne sont pas des liens
        symboliques sont ignorés.
        Cette option peut être considérée comme le contraire de --link
    -i, --install
        Supprimer les répertoires des projets dépendants dans vendor/, qu'il
        s'agisse de liens symboliques ou de répertoires normaux, puis les faire
        recréer par 'composer i'
        Celà permet de ramener le projet à l'état original.
    -j, --reinstall-link
        Supprimer les répertoires des projets dépendants dans vendor/ s'il
        s'agit de liens symboliques, puis les faire recréer par 'composer i'
        Cette variante est plus rapide que --install puisqu'on ne cherche pas à
        tout recréer.
    -u, --update
        Supprimer les répertoires des projets dépendants dans vendor/, qu'il
        s'agisse de liens symboliques ou de répertoires normaux, puis les faire
        recréer par 'composer u'
        Celà permet de mettre à jour le projet sans les erreurs qui résultent
        des modifications faites par les autres actions.
    -w, --update-commit
        Mettre à jour le projet avec --update puis enregistrer les modifications
        éventuelles dans git
    --ud, --update-deps
        Mettre à jour les projets dépendants avec --update-commit avant de
        mettre à jour le projet courant.
    --ur, --update-recursive
        Mettre à jour de façon récursive tous les projets dépendants.
        NB: les modifications dans les projets dépendants seront automatiquement
        enregistrées dans git."
}

fake=
verbose=1
nowait=
action=rsync
args=(
    --help '$exit_with display_help'
    -d:,--project-dir: projdir=
    -n,--fake fake=1
    -q,--quiet verbose=
    -g,--no-wait nowait=1
    -l,--link action=link
    -k,--copy action=copy
    -i,--install action=install
    -j,--reinstall-link action=reinstall-link
    -u,--update action=update
    -w,--update-commit action=update-commit
    --ud,--update-deps action=update-deps
    --ur,--update-recursive action=update-recursive
)
parse_args "$@"; set -- "${args[@]}"

if [ -d "$projdir" ]; then
    cd "$projdir"
elif [ -e "$projdir" ]; then
    die "$projdir: répertoire introuvable"
fi

found=
first=1
while true; do
    if [ -f composer.json ]; then
        found=1
        break
    fi
    first=
    cd ..
    if [ "$(pwd)" == "$HOME" ]; then
        die "Cette commande ne peut être lancée que depuis un projet Composer"
    fi
done
if [ -z "$first" ]; then
    enote "Le répertoire du projet est $(ppath . ~)"
fi

if [ "$action" == update-deps -o "$action" == update-recursive ]; then
    # avec update-deps et update-recursive, tous les modules doivent être
    # considérés
    set --
fi

###

if [ $# -eq 0 ]; then
    setx -a ms=list_dirs vendor "ur/*" "lib/*"
    set -- "${ms[@]}"
fi

function check_module() {
    [ -d "../$m" ] || die "$m: module introuvable"
}
function update_with_rsync() {
    local -a rsync_args
    rsync_args=(
        -a ${fake:+-n} ${verbose:+-v}
        --delete
        -f "- /.git/"
        -f "- /vendor/"
        "../$m/" "vendor/$p"
    )
    rsync "${rsync_args[@]}"
}

deps=()
modules=()
for m in "$@"; do
    m="${m#vendor/}" # pour permettre de spécifier le chemin directement
    m="${m//\//-}"
    case "$m" in
    ur-*|lib-*) ;;
    *) m="ur-$m";;
    esac
    modules+=("$m")
    p="${m//-/\/}"

    check_module
    case "$action" in
    rsync)
        # Action par défaut: ignorer les liens et synchroniser les copies
        if [ ! -L "vendor/$p" ]; then
            etitle "$m"
            update_with_rsync
            eend
        fi
        ;;
    link)
        # Ignorer les liens et transformer les copies en liens
        if [ ! -L "vendor/$p" ]; then
            link="$m"
            path="/project/vendor/$p"
            path="${path%/*}"
            while [ -n "$path" ]; do
                link="../$link"
                path="${path%/*}"
            done

            etitle "$m"
            estep "suppr. vendor/$p"
            rm -rf "vendor/$p"
            mkdirof "vendor/$p"

            estep "vendor/$p --> $link"
            ln -s "$link" "vendor/$p"
            eend
        fi
        ;;
    copy)
        # Transformer les liens en copie et les synchroniser
        etitle "$m"
        if [ -L "vendor/$p" ]; then
            estep "suppr. vendor/$p"
            rm -f "vendor/$p"
        fi
        update_with_rsync
        eend
        ;;
    install)
        # Supprimer les liens et répertoires...
        etitle "$m"
        if [ -e "vendor/$p" ]; then
            estep "suppr. vendor/$p"
            rm -rf "vendor/$p"
        fi
        array_add deps "$p"
        eend
        ;;
    reinstall-link)
        # Supprimer les liens uniquement...
        etitle "$m"
        if [ -L "vendor/$p" ]; then
            estep "suppr. vendor/$p"
            rm -f "vendor/$p"
        fi
        array_add deps "$p"
        eend
        ;;
    update|update-commit|update-deps|update-recursive)
        # Supprimer les liens et répertoires...
        etitle "$m"
        if [ -e "vendor/$p" ]; then
            estep "suppr. vendor/$p"
            rm -rf "vendor/$p"
        fi
        array_add deps "$p"
        eend
        ;;
    *) die "$action: action inconnue";;
    esac
done

case "$action" in
install|reinstall-link)
    # ... puis installer les dépendances
    estep "Installation des dépendances"
    "$scriptdir/dk" ci || die
    ;;
update|update-commit)
    # ... puis mettre à jour les dépendances
    estep "Mise à jour des dépendances"
    "$scriptdir/dk" cu "${deps[@]}" || die

    if [ "$action" == update-commit ]; then
        if [ -z "$nowait" ]; then
            # laisser le temps à @$*! d'eclipse qui met à jour automatiquement le projet...
            estep "Attendre 10 secondes avant git commit"
            sleep 10
        fi

        estep "Enregistrement dans git"
        pci -A "maj deps"
    fi
    ;;
update-deps)
    # mettre à jour les dépendances directes
    for m in "${modules[@]}"; do
        etitle "Mise à jour projet dépendant: $m"
        "$script" -d "../$m" -w
        eend
    done

    estep "Mise à jour des dépendances"
    "$scriptdir/dk" cu || die

    if [ -z "$nowait" ]; then
        # laisser le temps à @$*! d'eclipse qui met à jour automatiquement le projet...
        estep "Attendre 10 secondes avant git commit"
        sleep 10
    fi

    estep "Enregistrement dans git"
    pci -A "maj deps"
    ;;
update-recursive)
    # mettre à jour les dépendances de façon récursive
    for m in "${modules[@]}"; do
        etitle "Mise à jour récursive: $m"
        "$script" -d "../$m" --ur
        eend
    done

    estep "Mise à jour des dépendances"
    "$scriptdir/dk" cu || die

    if [ -z "$nowait" ]; then
        # laisser le temps à @$*! d'eclipse qui met à jour automatiquement le projet...
        estep "Attendre 10 secondes avant git commit"
        sleep 10
    fi

    estep "Enregistrement dans git"
    pci -A "maj deps"
    ;;
esac