#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8

function display_help() {
    uecho "$scriptname: Outil pour gérer des projets

USAGE
    $scriptname cmd [args]

COMMANDS
    getvcs [dir]
        Afficher le type de VCS pour dir.
    getroot [dir]
        Si dir est un répertoire versionné, retourner le répertoire racine du
        projet versionné.
    getrepos [dir]
        Si dir est un répertoire versionné, retourner l'url du repository du
        projet versionné.
    geturl [dir]
        Si dir est un répertoire versionné, retourner son url dans le
        repository.
    fold [dir]
    unfold [dir]
        Utiliser uinc pour défaire (resp. refaire) toutes les inclusions des
        fichiers de dir. Cela nécessite qu'un fichier .udir soit configuré à la
        racine du projet avec uinc=true
    vcs [args]
        Appeler le gestionnaire de gestion approprié avec les arguments donnés.
    add files...
        Ajouter les fichiers files dans le gestionnaire de version.
    remove files...
        Supprimer les fichiers versionnés files.
    copy from to
        Copier le fichier versionné from vers le fichier to.
    move from to
        Renommer le fichier versionné from vers le fichier to.
    mkdir dir
        Créer un nouveau répertoire versionné.
    commit message [files...]
        Enregistrer les modifications (par défaut sur tous les fichiers
        modifiés) avec le commentaire message.
    status
        Afficher l'état des fichiers versionnés et non versionnés.
    update [-x]
        Mettre à jour la copie locale avec la copie sur le serveur.
        -x  Ne pas mettre à jour les références externes (si appliquable)
        -n, --no-autoff
            Ne pas faire de fast-forward automatique pour toutes les branches
            traquées. Par défaut, s'il n'y a pas de modifications locales,
            essayer de fast-fowarder toutes les branches locales traquées.
    diff [options]
        Afficher les différences.
        -l  Afficher les différences non commitées (par défaut)
        -c  Afficher les différences en passe d'être commitées (si appliquable)
        -r REV
            Afficher les différences depuis la révision REV.
        -R  Afficher les modifications effectuées depuis la dernière release.

    clone git@host:path/to/repo [destdir]
        Cloner un dépôt distant. Basculer sur la branche develop si elle existe.
        Initialiser git annex si le dépôt contient des fichiers annexés.
        Récupérer aussi ces fichiers avec 'git annex get'

    crone git@host:path/to/repo [destdir]
        Créer un dépôt distant sur gitolite, puis le cloner

    develop
    release
    hotfix
        Démarrer le travail sur une branche respectivement de développement, de
        release, ou de correction de bugs. Lancer chaque commande avec --help
        pour les détails. Nécessite git.

    archive
        Créer une archive du projet courant. Nécessite git.

    annex [args]
        Lancer git annex avec les arguments spécifiés.
    xadd
    xunlock
    xdrop
    xwhereis
    xwebapp
        Chacune de ces commandes est un raccourci vers la commande
        correspondante de git annex, sans le préfixe 'x'
    xsync
        Sur un dépot où git-annex est activé, lancer 'git annex sync' si on est
        en mode indirect ou 'git annex sync --content' si on est en mode direct.
        Sur un dépôt où git-annex n'est pas activé, faire l'équivalent des
        commandes 'git add -A && git commit && git pull && git push'
    xcopy
    xmove
    xget
        Comme ci-dessus, mais si la commande s'exécute sans erreur, lancer
        aussi 'git annex sync'
    xinitial
        Sur un dépôt fraichement cloné, initialiser le dépôt avec 'annex init'
        s'il contient des fichiers annexés. Récupérer aussi ces fichiers avec
        'annex get'
    xconfig-export [dir]
        Installer des hooks pour qu'un dépôt puisse être utilisé pour servir des
        fichiers, par exemple avec un serveur web. Plus précisément, un hook
        post-receive est créé avec la commande 'git annex merge', et un hook
        post-update est créé avec la commande 'git update-server-info'

    printml [-t TYPE]
        Afficher le modeline pour un fichier du type spécifié
    addml [-t TYPE] file
        Ajouter un modele pour le fichier spécifié, s'il n'en a pas déjà un.
        Si nécessaire, forcer le type du fichier au lieu de l'autodétecter
    new [options] file [template options]
        Créer un nouveau fichier à partir d'un modèle.
        Avant le nom du fichier, les options suivantes sont valides:
        -t TEMPLATE
            Spécifier le modèle de fichier à utiliser. Par défaut, le modèle
            à utiliser est déduit de l'extension ou du nom du fichier.
        -e  Editer le fichier après l'avoir créé.
        Après le nom du fichier, toutes les options sont spécifiques au modèle
        utilisé pour créer le nouveau fichier. Utiliser l'option --help pour
        avoir une description des options disponibles."
}

SCRIPT_ALIASES=(
    pv:vcs
    pa:add prm:remove pcp:copy pmv:move pmd:mkdir
    pci:commit pu:update pp:push pdiff:diff
    pclone:clone
    pcrone:crone
    pxx:annex
    pxa:xadd pxu:xunlock pxc:xcopy pxd:xdrop pxm:xmove
    pxg:xget pxs:xsync pxw:xwhereis pxwa:xwebapp
    pxinitial:xinitial
    pnew:new
    pgr:grep
    paddml:addml
)
CMD_ALIASES=(
    getrepo:getrepos repo:getrepos repos:getrepos
    url:geturl
    a:add
    rm:remove del:remove delete:remove
    cp:copy
    mv:move ren:move rename:move
    md:mkdir
    ci:commit
    s:status st:status
    u:update upd:update
    p:push
    version:pver ver:pver
    develop:pdev dev:pdev release:prel rel:prel hotfix:pfix fix:pfix
    archive:pz arch:pz
    xx:annex
    xa:xadd
    xu:xunlock
    xc:xcopy
    xd:xdrop
    xm:xmove
    xg:xget
    xs:xsync
    xw:xwhereis
    xwa:xwebapp
    xce:xconfig-export
    gr:grep
)
DEFAULT_CMD=status
PY_CMDS=(new)
VCS_CMDS=(getvcs getroot getrepos geturl vcs add remove copy move mkdir commit status update push diff tag)
SH_CMDS=(pver pdev prel pfix pz)
GITANNEX_CMDS=(annex xadd xunlock xcopy xdrop xmove xget xsync xwhereis xwebapp xinitial)
ML_CMDS=(printml addml)

if [ "$#" -eq 1 -a "$1" == --nutools-makelinks ]; then
    # créer les liens
    scriptname="$(basename "$0")"
    for alias in p "${SCRIPT_ALIASES[@]}"; do
        alias="${alias%:*}"
        ln -s "$scriptname" "$alias"
    done
    exit 0
fi

source "$(dirname "$0")/lib/ulib/ulib" || exit 1
urequire DEFAULTS modeline vcs

# Traduire le nom du script
for script_alias in "${SCRIPT_ALIASES[@]}"; do
    splitpair "$script_alias" src dest
    if [ "$scriptname" == "$src" ]; then
        eval "set -- $dest \"\$@\""
        break
    fi
done

# Parser les options de uproject
parse_opts + "${PRETTYOPTS[@]}" \
    --help '$exit_with display_help' \
    @ args -- "$@" && set -- "${args[@]}" || die "$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

################################################################################
# Traiter les commandes

if [ "$CMD" == "grep" ]; then
    ## grep
    if [ $# -eq 1 -a "$1" == "--help" ]; then
        uecho "uproject grep: Lancer une recherche récursive en ignorant les répertoire de controle de version

USAGE
    uproject grep [grep options]"
        exit 0
    fi
    EXCLUDES=(--exclude-dir .svn --exclude-dir CVS --exclude-dir .git --exclude "*.pyc")
    exec grep -r "${EXCLUDES[@]}" "$@"

elif array_contains SH_CMDS "$CMD"; then
    exec "$scriptdir/$CMD" "$@"

elif array_contains ML_CMDS "$CMD"; then
    "$CMD" "$@"

elif array_contains VCS_CMDS "$CMD"; then
    "vcs_$CMD" "$@"

elif array_contains GITANNEX_CMDS "$CMD"; then
    function xsync() {
        if ! git_have_annex; then
            git_commit -Al "Maj des fichiers" && git pull && git_push
        elif is_yes "$(git config --get annex.direct)"; then
            git annex add &&
            git annex sync &&
            git annex sync --content &&
            git annex sync
        else
            git annex sync
        fi
    }
    git_annex_use_ssh_wrapper
    case "$CMD" in
    annex) git annex "$@";;
    xsync) xsync;;
    xcopy|xmove|xget) git annex "${CMD#x}" "$@" && git annex sync;;
    xinitial) git_annex_initial "$@";;
    *) git annex "${CMD#x}" "$@";;
    esac

elif [ "$CMD" == clone ]; then
    repourl="${1%.git}"
    [ -n "$repourl" ] || die "Vous devez spécifier l'url du dépôt git"
    splitfsep "$repourl" : userhost path

    destdir="$2"
    if [ -z "$destdir" ]; then
        setx destdir=basename -- "$path"
        destdir="${destdir%.git}"
    fi
    [ -d "$destdir" ] && die "$(ppath "$destdir"): répertoire existant"

    git_annex_use_ssh_wrapper
    git clone "$repourl" "$destdir" || die
    (
        cd "$destdir"
        if git_have_rbranch develop; then
            git checkout develop || exit 1
        fi
    ) || die
    git_annex_initial "$destdir" || die

elif [ "$CMD" == crone ]; then
    repourl="${1%.git}"
    [ -n "$repourl" ] || die "Vous devez spécifier l'url du dépôt git"
    splitfsep "$repourl" : userhost path

    destdir="$2"
    if [ -z "$destdir" ]; then
        setx destdir=basename -- "$path"
        destdir="${destdir%.git}"
    fi
    tmpdestdir=
    if [ -d "$destdir" ]; then
        [ -d "$destdir/.git" ] && die "$(ppath "$destdir"): répertoire existant"
        ac_set_tmpdir tmpdestdir
    fi

    splituserhost "$userhost" user host
    [ -n "$user" ] || user=git
    [ -n "$host" ] || die "Vous devez spécifier l'hôte"
    userhost="$user@$host"
    [ -n "$path" ] || die "Vous devez spécifier le chemin du dépôt git"

    git_annex_use_ssh_wrapper
    ssh "$userhost" create "$path" || die
    if [ -n "$tmpdestdir" ]; then
        setxx destname=abspath "$destdir" // basename
        git clone "$userhost:$path" "$tmpdestdir/$destname" || die
        mv "$tmpdestdir/$destname/.git" "$destdir" || die
        ac_clean "$tmpdestdir"
    else
        git clone "$userhost:$path" "$destdir" || die
    fi
    git_annex_initial "$destdir" || die

elif [ "$CMD" == xconfig-export ]; then
    unset GIT_DIR; unset GIT_WORK_TREE
    dir="${1:-.}"
    [ -d "$dir" ] || die "$dir: répertoire introuvable"
    setx dir=abspath "$dir"
    setx repodir=ppath "$dir"
    cd "$dir"

    git rev-parse 2>/dev/null || die "$repodir: n'est pas un dépôt git"
    [ -n "$(git config --get annex.uuid)" ] || die "$repodir: n'est pas un dépôt git-annex"
    cd "$(__vcs_find_root "$dir")"
    [ -d .git ] || die "$repodir: est un dépôt nu"

    prhook=.git/hooks/post-receive
    prscript='if [ -n "$GIT_DIR" ]; then cd "$GIT_DIR"; cd ..; unset GIT_DIR; fi
git annex merge'
    puhook=.git/hooks/post-update
    puscript='git update-server-info'
    if [ -f "$prhook" ]; then
        ewarn "Le fichier $prhook existe déjà dans $repodir
Vérifiez qu'il contient les commandes suivantes:
--------8<--------
$prscript
--------8<--------"
    else
        estep "post-receive"
        echo "#!/bin/bash
$prscript" >"$prhook"
        chmod +x "$prhook"
    fi
    if [ -f "$puhook" ]; then
        ewarn "Le fichier $puhook existe déjà dans $repodir
Vérifiez qu'il contient les commandes suivantes:
--------8<--------
$puscript
--------8<--------"
    else
        estep "post-update"
        echo "#!/bin/bash
$puscript" >"$puhook"
        chmod +x "$puhook"
    fi

elif array_contains PY_CMDS "$CMD"; then
    exec "$scriptdir/lib/pywrapper" uproject.py "$CMD" "$@"

else
    die "$CMD: commande inconnue"
fi