##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
## Fonctions pour la gestion des projets
##@cooked nocomments
##@include vcs
##@include semver
##@include xmlsupport
uprovide ptools
urequire vcs semver xmlsupport

function is_any_branch() {
    local branch="$1"; shift
    if [ -z "$branch" ]; then
        branch="$(git_get_branch)" || return 2
    fi
    local annex; git_have_annex && annex=1
    local spec r
    for spec in "$@"; do
        case "$spec" in
        m|master)
            [ -n "$r" ] || r=1
            [ "$branch" == "master" ] && return 0
            ;;
        d|develop)
            [ -n "$r" ] || r=1
            [ "$branch" == "develop" ] && return 0
            ;;
        r|release)
            [ -n "$r" ] || r=1
            [[ "$branch" == release-* ]] && return 0
            ;;
        h|hotfix)
            [ -n "$r" ] || r=1
            [[ "$branch" == hotfix-* ]] && return 0
            ;;
        f|feature|t|topic)
            [ -n "$r" ] || r=1
            [ "$branch" == "master" ] && continue
            [ "$branch" == "develop" ] && continue
            [[ "$branch" == release-* ]] && continue
            [[ "$branch" == hotfix-* ]] && continue
            [ -n "$annex" -a "$branch" == "git-annex" ] && continue
            [[ "$branch" == */* ]] && continue
            return 0
            ;;
        -m|-master)
            [ -n "$r" ] || r=0
            [ "$branch" == "master" ] && return 1;;
        -d|-develop)
            [ -n "$r" ] || r=0
            [ "$branch" == "develop" ] && return 1;;
        -r|-release)
            [ -n "$r" ] || r=0
            [[ "$branch" == release-* ]] && return 1;;
        -h|-hotfix)
            [ -n "$r" ] || r=0
            [[ "$branch" == hotfix-* ]] && return 1;;
        -f|-feature|-t|-topic)
            [ -n "$r" ] || r=0
            [ "$branch" == "master" ] && continue
            [ "$branch" == "develop" ] && continue
            [[ "$branch" == release-* ]] && continue
            [[ "$branch" == hotfix-* ]] && continue
            [ -n "$annex" -a "$branch" == "git-annex" ] && continue
            [[ "$branch" == */* ]] && continue
            return 1
            ;;
        esac
    done
    return ${r:-1}
}
function is_master_branch() { is_any_branch "$1" master; }
function is_develop_branch() { is_any_branch "$1" develop; }
function is_release_branch() { is_any_branch "$1" release; }
function is_hotfix_branch() { is_any_branch "$1" hotfix; }
function is_feature_branch() { is_any_branch "$1" feature; }

function list_release_branches() {
    local origin="$1"
    git_list_${origin:+p}branches "$origin" | grep '^release-'
}
function list_hotfix_branches() {
    local origin="$1"
    git_list_${origin:+p}branches "$origin" | grep '^hotfix-'
}
function list_feature_branches() {
    local origin="$1"
    git_list_${origin:+p}branches "$origin" |
    grep -vF master |
    grep -vF develop |
    grep -v '^release-' |
    grep -v '^hotfix-' |
    grep -v '/' |
    if git_have_annex; then
        grep -vF git-annex
    else
        cat
    fi
}

################################################################################
# Outils de haut niveau

__pver_perror() {
    local r="$1"; shift
    [ $# -gt 0 ] || set "Une erreur s'est produite"
    local m=$r
    [ $m -gt $# ] && m=$#
    [ $m -gt 0 ] && eerror "${!m}"
    return $r
}

__pver_unless() {
    local r m
    if [[ "$1" == -* ]]; then
        [ "${@:1:2}" ] 2>/dev/null; r=$?
        shift; shift
    else
        [ "${@:1:3}" ] 2>/dev/null; r=$?
        shift; shift; shift
    fi
    __pver_perror $r "$@"
}

function __pver_get_prel_version() {
    # retourner la version correspondant à la branche courante si c'est une
    # branche de release. retourner 1 si la branche courante n'est pas une
    # branche de release, 2 si on n'est pas dans un dépôt git
    local branch
    branch="$(git_get_branch)" || return 2
    if [[ "$branch" == release-* ]]; then
        echo "${branch#release-}"
        return 0
    else
        return 1
    fi
}
function __pver_pom_get_vpath() {
    # pour le fichier $1(=pom.xml), retourner le chemin dans lequel se trouve la
    # version du projet
    local pom="${1:-pom.xml}"
    if xpathtool -tf "$pom" /project/version 2>/dev/null; then
        echo /project/version
    elif xpathtool -tf "$pom" /project/parent/version 2>/dev/null; then
        echo /project/parent/version
    else
        echo /project/version
    fi
}

function __pver_pom_get_version() {
    # obtenir la version dans le pom $1(=pom.xml) à partir du chemin $2, qui est
    # déterminé automatiquement s'il n'est pas spécifié.
    local pom="${1:-pom.xml}"
    local vpath="$2"
    local version
    if [ -n "$vpath" ]; then
        xpathtool -f "$pom" -g "$vpath"
        return
    fi
    version="$(xpathtool -f "$pom" -g /project/version 2>/dev/null)"
    if [ -n "$version" ]; then
        echo "$version"
        return
    fi
    version="$(xpathtool -f "$pom" -g /project/parent/version 2>/dev/null)"
    if [ -n "$version" ]; then
        echo "$version"
        return
    fi
}

function __pver_pom_set_version() {
    # modifier la version dans le pom $1(=pom.xml) à la valeur
    # $2(=1.0.0-SNAPSHOT) en utilisant le chemin xpath $3, qui est déterminé
    # automatiquement s'il n'est pas spécifié.
    # retourner 0 si la version a été mise à jour dans le chemin /project/version
    # retourner 1 si la version a été mise à jour dans le chemin /project/parent/version
    # retourner 2 si la version a été mise à jour dans un autre chemin
    # retourner 3 si une erreur s'est produite
    local pom="${1:-pom.xml}"
    local version="${2:-1.0.0-SNAPSHOT}"
    local vpath="$3"
    case "$vpath" in
    D) vpath=/project/version;;
    P) vpath=/project/parent/version;;
    esac
    [ -n "$vpath" ] || vpath="$(__pver_pom_get_vpath "$pom")"
    xpathtool -f "$pom" -s "$vpath" "$version" || return 3
    case "$vpath" in
    /project/version) return 0;;
    /project/parent/version) return 1;;
    *) return 2;;
    esac
}

function pver() {
    local DEFAULT_FILE=VERSION.txt
    local DEFAULT_POM=pom.xml

    local -a args
    local action=auto
    local source=auto
    local file git version operator oversion
    local setversion incversion
    local setpr setprelease setsnapshot setalpha setbeta setrc setrelease
    local setmd resetmetadata setmetadata addmetadata vcsmetadata
    local vpath setmapfile mapfile allow_empty convert=auto maven_update
    parse_opts "${PRETTYOPTS[@]}" \
        --help '$exit_with pver_display_help' \
        -w:,--w:,--fw:,--auto-file: '$set@ file; source=auto-file' \
        --sw:,--auto-string: '$set@ file; source=auto-string' \
        --gw:,--auto-git-string: '$set@ git; source=auto-git-string' \
        -e:,--e:,--pom:,--maven: '$set@ file; source=pom' \
        -E:,--E:,--pom-string:,--maven-string: '$set@ file; source=pom-string' \
        -f:,--f:,--file: '$set@ file; source=file' \
        -F:,--F:,--file-string: '$set@ file; source=file-string' \
        -g:,--g:,--git-file-string:,--git-string: '$set@ git; source=git-file-string' \
        -G:,--G:,--git-pom-string: '$set@ git; source=git-pom-string' \
        --git-prel-string source=git-prel-string \
        -s:,--s:,--string: '$set@ version; source=string' \
        --show action=show \
        --show-source action=show-source \
        --check action=check \
        --eq: '$action=compare; operator=eq; set@ oversion' \
        --ne: '$action=compare; operator=ne; set@ oversion' \
        --lt: '$action=compare; operator=lt; set@ oversion' \
        --le: '$action=compare; operator=le; set@ oversion' \
        --gt: '$action=compare; operator=gt; set@ oversion' \
        --ge: '$action=compare; operator=ge; set@ oversion' \
        -u,--update '$action=update; [ -z "$incversion" ] && incversion=auto' \
        --menu '$action=update; incversion=menu' \
        -v:,--set-version: '$action=update; set@ setversion; incversion=' \
        --prel '$action=update; setversion=prel; incversion=' \
        -x,--major '$action=update; incversion=major' \
        -z,--minor '$action=update; incversion=minor' \
        -p,--patchlevel '$action=update; incversion=patchlevel' \
        -k,--keep '$action=update; incversion=' \
        -l:,--prelease:,--prerelease: '$action=update; setpr=1; setsnapshot=; setalpha=; setbeta=; setrc=; setrelease=; set@ setprelease; [ -z "$setprelease" ] && setrelease=1' \
        -S,--snapshot '$action=update; setpr=1; setsnapshot=1; setalpha=; setbeta=; setrc=; setrelease=' \
        -a,--alpha '$action=update; setpr=1; setsnapshot=; setalpha=1; setbeta=; setrc=; setrelease=' \
        -b,--beta '$action=update; setpr=1; setsnapshot=; setalpha=; setbeta=1; setrc=; setrelease=' \
        -r,--rc '$action=update; setpr=1; setsnapshot=; setalpha=; setbeta=; setrc=1; setrelease=' \
        -R,--release,--final '$action=update; setpr=1; setsnapshot=; setalpha=; setbeta=; setrc=; setrelease=1' \
        -m:,--metadata:,--set-metadata: '$action=update; setmd=1; resetmetadata=1; set@ setmetadata' \
        --add-metadata: '$action=update; setmd=1; set@ addmetadata' \
        -M,--vcs-metadata '$action=update; setmd=1; vcsmetadata=1' \
        --vpath: vpath= \
        --map: '$setmapfile=1; set@ mapfile' \
        --allow-empty allow_empty=1 \
        --convert convert=1 \
        --no-convert convert= \
        -t,--maven-update maven_update=1 \
        @ args -- "$@" && set -- "${args[@]}" || { eerror "$args"; return 1; }

    # Calculer la source
    if [ "$source" == auto-file -o "$source" == auto-string ]; then
        [ -n "$file" ] || file=.
        if [ -d "$file" ]; then
            if [ -f "$file/$DEFAULT_POM" ]; then
                file="$file/$DEFAULT_POM"
            elif [ -f "$file/$DEFAULT_FILE" ]; then
                file="$file/$DEFAULT_FILE"
            elif [ -f "$file/version.txt" ]; then
                file="$file/version.txt"
            else
                file="$file/$DEFAULT_FILE"
            fi
        fi
        if [ "$source" == auto-file ]; then
            if [[ "$file" == *.xml ]]; then source=pom
            else source=file
            fi
        elif [ "$source" == auto-string ]; then
            if [[ "$file" == *.xml ]]; then source=pom-string
            else source=file-string
            fi
        fi
        edebug "Auto-sélection de $(ppath "$file")"

    elif [ "$source" == auto-git-string ]; then
        git_check_gitvcs || return 2
        splitfsep2 "$git" : branch name
        [ -n "$branch" ] || branch=master
        if [ "$(git cat-file -t "$branch:$name" 2>/dev/null)" == tree ]; then
            if git rev-parse --verify --quiet "$branch:${name:+$name/}$DEFAULT_POM" >/dev/null; then
                name="${name:+$name/}$DEFAULT_POM"
            elif git rev-parse --verify --quiet "$branch:${name:+$name/}$DEFAULT_FILE" >/dev/null; then
                name="${name:+$name/}$DEFAULT_FILE"
            elif git rev-parse --verify --quiet "$branch:${name:+$name/}version.txt" >/dev/null; then
                name="${name:+$name/}version.txt"
            fi
        fi
        if git rev-parse --verify --quiet "$branch:$name" >/dev/null; then
            if [[ "$name" == *.xml ]]; then source=git-pom-string
            else source=git-file-string
            fi
            git="$branch:$name"
            edebug "Auto-sélection de $git"
        else
            eerror "$name: fichier introuvable sur la branche $branch"
            return 1
        fi
    fi

    if [ "$source" == auto ]; then
        source=file
        for i in "$DEFAULT_POM" "$DEFAULT_FILE" version.txt; do
            if [ -f "$i" ]; then
                case "$i" in
                "$DEFAULT_POM") source=pom; file="$i"; break;;
                *) source=file; file="$i"; break;;
                esac
            fi
        done
    elif [ "$source" == file -o "$source" == pom ]; then
        [ "$action" == auto ] && action=update
    fi
    [ "$source" == file -a -z "$file" ] && file="$DEFAULT_FILE"
    [ "$source" == pom -a -z "$file" ] && file="$DEFAULT_POM"
    [ "$action" == auto ] && action=show

    if [[ "$source" == auto* ]]; then
        eerror "bug: impossible de déterminer la source"
        return 1
    fi

    if [ "$action" == show-source ]; then
        echo "$source"
        return 0
    fi

    # Lire la version
    local -a maprules
    if [ "$source" == file -o "$source" == pom ]; then
        local mapdir="$(dirname -- "$file")"
        if [ -z "$setmapfile" ]; then
            local tmpfile
            tmpfile="$mapdir/.pver-map"
            [ -f "$tmpfile" ] && mapfile="$tmpfile"
        fi
        if [ -n "$mapfile" ]; then
            __pver_unless -f "$mapfile" "$mapfile: fichier introuvable" || return

            mapdir="$(dirname -- "$mapfile")"
            array_from_lines maprules "$(<"$mapfile" filter_conf)"
            local maprule filespec filevpath filename
            local -a filenames
            for maprule in "${maprules[@]}"; do
                splitpair "$maprule" filespec filevpath
                [ "$filevpath" != - ] || continue
                array_lsfiles filenames "$mapdir" "$filespec"
                [ ${#filenames[*]} -gt 0 ] || continue
                file="${filenames[0]}"
                if [[ "$file" == *.xml ]]; then source=pom
                else source=file
                fi
                edebug "Sélection de $file comme fichier de référence"
                break
            done
        fi
    fi
    [ "$source" == pom ] && maven_update=1

    if [ "$source" == file ]; then
        [ -f "$file" ] && version="$(<"$file")"

    elif [ "$source" == file-string ]; then
        if [ -z "$file" ]; then
            file="$DEFAULT_FILE"
        elif [ -d "$file" ]; then
            file="$file/$DEFAULT_FILE"
        fi
        [ -f "$file" ] && version="$(<"$file")"
        file=

    elif [ "$source" == git-file-string ]; then
        git_check_gitvcs || return 2
        splitfsep2 "$git" : branch name
        [ -n "$branch" ] || branch=master
        [ -n "$name" ] || name="$DEFAULT_FILE"
        if git rev-parse --verify --quiet "$branch:$name" >/dev/null; then
            version="$(git cat-file blob "$branch:$name" 2>/dev/null)"
        fi

    elif [ "$source" == pom ]; then
        __pver_unless -f "$file" "$file: fichier introuvable" || return
        [ -n "$vpath" ] || vpath="$(__pver_pom_get_vpath "$file")"
        version="$(__pver_pom_get_version "$file" "$vpath")"

    elif [ "$source" == pom-string ]; then
        if [ -z "$file" ]; then file="$DEFAULT_POM"
        elif [ -d "$file" ]; then file="$file/$DEFAULT_POM"
        fi
        __pver_unless -f "$file" "$file: fichier introuvable" || return

        [ -n "$vpath" ] || vpath="$(__pver_pom_get_vpath "$file")"
        version="$(__pver_pom_get_version "$file" "$vpath")"
        file=

    elif [ "$source" == git-pom-string ]; then
        git_check_gitvcs || return 2
        splitfsep2 "$git" : branch name
        [ -n "$branch" ] || branch=master
        [ -n "$name" ] || name="$DEFAULT_POM"
        if git rev-parse --verify --quiet "$branch:$name" >/dev/null; then
            local tmpfile; ac_set_tmpfile tmpfile
            git cat-file blob "$branch:$name" >"$tmpfile" 2>/dev/null
            [ -n "$vpath" ] || vpath="$(__pver_pom_get_vpath "$tmpfile")"
            version="$(__pver_pom_get_version "$tmpfile" "$vpath")"
            ac_clean "$tmpfile"
        else
            eerror "$name: fichier introuvable sur la branche $branch"
            return 1
        fi

    elif [ "$source" == git-prel-string ]; then
        version="$(__pver_get_prel_version)" || return
    fi

    [ -n "$version" -o -n "$allow_empty" ] || version=0.0.0

    # Conversion éventuelle du numéro de version
    psemver_parse "$version"
    [ -n "$valid" ] && convert=
    if [ "$convert" == auto ]; then
        [ -z "$valid" ] && convert=1
    fi
    if [ -n "$convert" -a -n "$version" ]; then
        mversion="$(awkrun version="$version" '
function nbdot(s) {
  gsub(/[^.]/, "", s)
  return length(s)
}
BEGIN {
  ### utools, legacy
  if (version ~ /[0-9]+(\.[0-9]+)*(-r[0-9][0-9]\/[0-9][0-9]\/[0-9][0-9][0-9][0-9])?$/) {
    metadata = ""
    # traiter release date
    pos = length(version) - 12
    if (pos > 0) {
      rdate = substr(version, pos + 3)
      metadata = substr(rdate, 7, 4) substr(rdate, 4, 2) substr(rdate, 1, 2)
      version = substr(version, 1, pos)
    }
    # traiter metadata
    match(version, /[0-9]+(\.[0-9]+(\.[0-9]+)?)?/)
    pos = RLENGTH
    if (pos < length(version)) {
      if (metadata != "") metadata = metadata "."
      metadata = metadata substr(version, pos + 2)
    }
    version = substr(version, 1, pos)
    # ajouter les éléments manquants
    while (nbdot(version) < 2) {
      version = version ".0"
    }
    # afficher la version migrée au format semver
    if (metadata != "") print version "+r" metadata
    else print version

  ### maven, pom.xml
  } else if (version ~ /[0-9]+(\.[0-9]+)*(-[sS][nN][aA][pP][sS][hH][oO][tT])?$/) {

    prerelease = ""
    # traiter prerelease
    pos = length(version) - 9
    if (pos > 0) {
      prerelease = substr(version, pos + 2)
      version = substr(version, 1, pos)
    }
    # traiter prerelease
    match(version, /[0-9]+(\.[0-9]+(\.[0-9]+)?)?/)
    pos = RLENGTH
    if (pos < length(version)) {
      if (prerelease != "") prerelease = prerelease "."
      prerelease = prerelease substr(version, pos + 2)
    }
    version = substr(version, 1, pos)
    # ajouter les éléments manquants
    while (nbdot(version) < 2) {
      version = version ".0"
    }
    # afficher la version migrée au format semver
    if (prerelease != "") print version "-" prerelease
    else print version
  }
}')"
        if [ -n "$mversion" ]; then
            version="$mversion"
            psemver_parse "$version"
        fi
    fi

    # Actions
    if [ "$action" == show ]; then
        if [ -n "$version" ]; then
            if isatty; then
                estepi "La version actuelle est $version"
            else
                echo "$version"
            fi
            return 0
        else
            if isatty; then
                estepi "Il n'y a pas de version définie"
            fi
            return 1
        fi
    fi

    if [ "$action" == check ]; then
        __pver_unless -n "$valid" "Numéro de version invalide: $version" || return

    elif [ "$action" == compare ]; then
        psemver_parse "$oversion" o

        case "$operator" in
        eq|same)
            for var in valid major minor patchlevel; do
                ovar="o$var"
                [ "${!var}" == "${!ovar}" ] || return 1
            done
            array_eq prelease oprelease || return 1
            if [ "$operator" == same ]; then
                array_eq metadata ometadata || return 1
            fi
            return 0
            ;;
        ne|diff)
            for var in valid major minor patchlevel; do
                ovar="o$var"
                [ "${!var}" != "${!ovar}" ] && return 0
            done
            ! array_eq prelease oprelease && return 0
            if [ "$operator" == diff ]; then
                ! array_eq metadata ometadata && return 0
            fi
            return 1
            ;;
        lt)
            [ -z "$valid" -a -z "$ovalid" ] && return 1
            [ "$major" -lt "$omajor" ] && return 0
            [ "$major" -gt "$omajor" ] && return 1
            [ "$minor" -lt "$ominor" ] && return 0
            [ "$minor" -gt "$ominor" ] && return 1
            [ "$patchlevel" -lt "$opatchlevel" ] && return 0
            [ "$patchlevel" -gt "$opatchlevel" ] && return 1
            case "$(psemver_compare_prelease "" o)" in
            lt) return 0;;
            esac
            return 1
            ;;
        le)
            [ -z "$valid" -a -z "$ovalid" ] && return 1
            [ "$major" -lt "$omajor" ] && return 0
            [ "$major" -gt "$omajor" ] && return 1
            [ "$minor" -lt "$ominor" ] && return 0
            [ "$minor" -gt "$ominor" ] && return 1
            [ "$patchlevel" -lt "$opatchlevel" ] && return 0
            [ "$patchlevel" -gt "$opatchlevel" ] && return 1
            case "$(psemver_compare_prelease "" o)" in
            lt|eq) return 0;;
            esac
            return 1
            ;;
        gt)
            [ -z "$valid" -a -z "$ovalid" ] && return 1
            [ "$major" -lt "$omajor" ] && return 1
            [ "$major" -gt "$omajor" ] && return 0
            [ "$minor" -lt "$ominor" ] && return 1
            [ "$minor" -gt "$ominor" ] && return 0
            [ "$patchlevel" -lt "$opatchlevel" ] && return 1
            [ "$patchlevel" -gt "$opatchlevel" ] && return 0
            case "$(psemver_compare_prelease "" o)" in
            gt) return 0;;
            esac
            return 1
            ;;
        ge)
            [ -z "$valid" -a -z "$ovalid" ] && return 1
            [ "$major" -lt "$omajor" ] && return 1
            [ "$major" -gt "$omajor" ] && return 0
            [ "$minor" -lt "$ominor" ] && return 1
            [ "$minor" -gt "$ominor" ] && return 0
            [ "$patchlevel" -lt "$opatchlevel" ] && return 1
            [ "$patchlevel" -gt "$opatchlevel" ] && return 0
            case "$(psemver_compare_prelease "" o)" in
            gt|eq) return 0;;
            esac
            return 1
            ;;
        esac

    elif  [ "$action" == update ]; then
        [ -z "$version" -a -n "$allow_empty" ] && return 1
        __pver_unless -n "$valid" "Numéro de version invalide: $version" || return

        if [ -n "$file" ]; then
            if [ -f "$file" ]; then
                isatty && estepi "La version actuelle est $version"
            elif [ "$source" == pom ]; then
                eerror "$file: fichier introuvable"
                return 1
            elif isatty; then
                ask_yesno "Le fichier $(ppath "$file") n'existe pas. Faut-il le créer?" O || return 1
            fi
        fi

        # forcer le numéro de version
        if [ -n "$setversion" ]; then
            if [ "$setversion" == prel ]; then
                setversion="$(__pver_get_prel_version)"
                __pver_perror $? \
                              "$(git_get_branch): n'est pas une release branch" \
                              "Dépôt git introuvable" || return
            fi
            psemver_setversion "$setversion" "" || {
                eerror "Numéro de version invalide: $setversion"
                return 1
            }
        fi

        # Calculer metadata
        if [ -n "$vcsmetadata" ]; then
            resetmetadata=1
            setmetadata="$(git rev-parse --short HEAD)" || return 1
        fi

        # incrémenter les numéros de version
        if [ -n "$maven_update" -a -n "$incversion" ]; then
            # il y a des règles particulières pour maven
            if [ -n "$setrelease" -a -z "$prelease" ]; then
                # on est déjà en release, faire le traitement normal
                maven_update=
            elif [ -n "$setsnapshot" -a "$prelease" == SNAPSHOT ]; then
                # on est déjà en snapshot, faire le traitement normal, mais garder le préfixe SNAPSHOT
                maven_update=
                if [ "$incversion" == auto ]; then
                    [ -n "$setmd" ] && incversion= || incversion=menu
                fi
            elif [ -z "$prelease" ]; then
                # on est en release, passer en snapshot
                setsnapshot=1
                setrelease=
                if [ "$incversion" == auto ]; then
                    [ -n "$setmd" ] && incversion= || incversion=menu
                fi
            elif [ "$prelease" == SNAPSHOT ]; then
                # on est en snapshot, passer en release
                setsnapshot=
                setrelease=1
                if [ "$incversion" == auto ]; then
                    [ -n "$setmd" ] && incversion= || incversion=menu
                fi
            fi
        fi
        if [ "$incversion" == auto ]; then
            [ -n "$setpr" -o -n "$setmd" ] && incversion= || incversion=menu
        fi
        if [ -z "$incversion" -a -n "$maven_update" ]; then
            # on doit incrémenter avec les règles maven, mais aucune des options
            # -[xzp] n'est spécifiée
            if [ -n "$setrelease" ]; then
                incversion=patchlevel
            elif [ -n "$setsnapshot" ]; then
                incversion=patchlevel
            fi
        fi

        if [ -n "$setrelease" ]; then setprelease=
        elif [ -n "$setsnapshot" ]; then setprelease=SNAPSHOT
        fi
        if [ "$incversion" == menu ]; then
            psemver_copy x
            psemver_incsetprmd major x "$setprelease" 1 "$setmetadata" "$addmetadata" "$maven_update"
            psemver_setvar versionx x
            psemver_copy z
            psemver_incsetprmd minor z "$setprelease" 1 "$setmetadata" "$addmetadata" "$maven_update"
            psemver_setvar versionz z
            psemver_copy p
            psemver_incsetprmd patchlevel p "$setprelease" 1 "$setmetadata" "$addmetadata" "$maven_update"
            psemver_setvar versionp p
            psemver_copy k
            psemver_incsetprmd "" k "$setprelease" "$resetmetadata" "$setmetadata" "$addmetadata" "$maven_update"
            psemver_setvar versionk k
            nextvs=(
                "$versionx : maj incompatibles de l'API (-x)"
                "$versionz : maj compatibles de l'API (-z)"
                "$versionp : correction de bugs (-p)"
                "$versionk : ne pas incrémenter la version"
            )
            if [ -z "$maven_update" ]; then
                nextv="${nextvs[1]}"
            else
                nextv="${nextvs[2]}"
            fi
            simple_menu nextv nextvs \
                -t "Incrémenter le numéro de version" \
                -m "Veuillez choisir la prochaine version"
            case "${nextv%)}" in
            *-x) incversion=major;;
            *-z) incversion=minor;;
            *-p) incversion=patchlevel;;
            *) incversion=;;
            esac
        fi

        local r
        if [ -n "$incversion" ]; then
            psemver_incsetprmd "$incversion" "" "$setprelease" 1 "$setmetadata" "$addmetadata" "$maven_update"
            r=$?
        else
            psemver_setprmd "" "$setprelease" "$resetmetadata" "$setmetadata" "$addmetadata"
            r=$?
        fi
        case $r in
        2) eerror "Identifiant de pre-release invalide: $setprelease"; return 1;;
        3) eerror "Identifiant de build invalide: $setmetadata"; return 1;;
        4) eerror "Identifiant de build invalide: $addmetadata"; return 1;;
        esac

        # afficher le résultat final
        local -a depfiles regfiles
        psemver_setvar version
        if [ -n "$file" ]; then
            if [ "$source" == file ]; then
                echo "$version" >"$file"
            elif [ "$source" == pom ]; then
                __pver_pom_set_version "$file" "$version"
                [ $? -eq 3 ] && return 1
            fi
            if [ ${#maprules[*]} -gt 0 ]; then
                # mettre à jour les fichiers mentionnés dans mapfile
                local -a donefiles
                for maprule in "${maprules[@]}"; do
                    splitpair "$maprule" filespec filevpath
                    array_lsfiles filenames "$mapdir" "$filespec"
                    for file in "${filenames[@]}"; do
                        file="$(abspath "$file")"
                        edebug "Examen de $file"
                        # si c'est un wildcard, ne traiter que si le fichier n'a
                        # pas encore été traité
                        case "$filespec" in *\**|*\?*) array_contains donefiles "$file" && break;; esac
                        if [ "$filevpath" != - ]; then
                            if [[ "$file" == *.xml ]]; then
                                edebug "Maj version de $file au chemin XPATH ${filevpath:-par défaut}"
                                __pver_pom_set_version "$file" "$version" "$filevpath"
                                case $? in
                                0|1) array_addu regfiles "$file";;
                                2) array_addu depfiles "$file";;
                                *) return 1;;
                                esac
                            else
                                edebug "Maj version de $file"
                                echo "$version" >"$file"
                            fi
                        else
                            edebug "Fichier $file ignoré"
                        fi
                        array_addu donefiles "$file"
                    done
                done
            fi
        fi
        if isatty; then
            estepn "La nouvelle version est $version"
            if [ ${#depfiles[*]} -gt 0 ]; then
                local msg
                for file in "${depfiles[@]}"; do
                    array_contains regfiles "$file" && continue
                    if [ -z "$msg" ]; then
                        msg="Les fichiers suivants ont été modifiés, et leur version doit être mise à jour:"
                    fi
                    msg="$msg
    $(qvals pver -uw "$file" -R -p)"
                done
                [ -n "$msg" ] && eimportant "$msg"
            fi
        else
            echo "$version"
        fi
    fi

    return 0
}
