#!/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. 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
    xsync
    xwhereis
        Chacune de ces commandes est un raccourci vers la commande
        correspondante de git annex, sans le préfixe 'x'
    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'

    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
    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
    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 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

function use_ssh_wrapper() {
    __UTOOLS_FORCE_PATH="$PATH"
    __UTOOLS_FORCE_SSH="${GIT_SSH:-ssh}"
    export __UTOOLS_FORCE_PATH __UTOOLS_FORCE_SSH
    udelpath "$scriptdir/lib/ssh-wrapper" __UTOOLS_FORCE_PATH
    uinspath "$scriptdir/lib/ssh-wrapper" PATH
}

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
    use_ssh_wrapper
    case "$CMD" in
    annex) git annex "$@";;
    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"

    destdir="$2"
    [ -n "$destdir" ] || setx destdir=basename -- "$repourl"
    [ -d "$destdir" ] && die "$(ppath "$destdir"): répertoire existant"

    use_ssh_wrapper
    git clone "$repourl" "$destdir" || 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"

    destdir="$2"
    [ -n "$destdir" ] || setx destdir=basename -- "$repourl"
    [ -d "$destdir" ] && die "$(ppath "$destdir"): répertoire existant"

    splitfsep "$repourl" : userhost path
    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"

    use_ssh_wrapper
    ssh "$userhost" create "$path" || die
    git clone "$userhost:$path" "$destdir" || die
    git_annex_initial "$destdir" || die

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

else
    die "$CMD: commande inconnue"
fi