commit:     0d4a8c22f05f89a465f012e5952ef52cb1ac5deb
Author:     Ulrich Müller <ulm <AT> gentoo <DOT> org>
AuthorDate: Thu Sep 21 07:34:19 2017 +0000
Commit:     Ulrich Müller <ulm <AT> gentoo <DOT> org>
CommitDate: Tue Sep 26 18:46:27 2017 +0000
URL:        https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=0d4a8c22

eapi7-ver.eclass: New algorithm for ver_test().

Use a regular expression for version validation and splitting, which
turns out to be even faster than the previous "ultra-fast" approach.

Thanks to Michał Górny for several optimisations.

 eclass/eapi7-ver.eclass | 289 ++++++++++++++----------------------------------
 1 file changed, 82 insertions(+), 207 deletions(-)

diff --git a/eclass/eapi7-ver.eclass b/eclass/eapi7-ver.eclass
index 2644832574a..5ca8b8143af 100644
--- a/eclass/eapi7-ver.eclass
+++ b/eclass/eapi7-ver.eclass
@@ -174,79 +174,92 @@ ver_rs() {
        echo "${comp[*]}"
 }
 
-# @FUNCTION: _ver_validate
-# @USAGE: <comp[0]>...
+# @FUNCTION: _ver_compare
+# @USAGE: <va> <vb>
+# @RETURN: 1 if <va> < <vb>, 2 if <va> = <vb>, 3 if <va> > <vb>
+# @INTERNAL
 # @DESCRIPTION:
-# Verify that the version component array passed as the argument
-# validates according to the PMS version rules. Returns 0 if it does,
-# 1 otherwise.
-_ver_validate() {
-       local prev=start
-
-       while [[ ${1} || ${2} ]]; do
-               local s=${1}
-               local c=${2}
-
-               if [[ -z ${s} ]]; then
-                       if [[ ${c} == [0-9]* ]]; then
-                               # number without preceding sep may be either:
-                               case ${prev} in
-                                       # a. 1st version number
-                                       start) prev=numeric;;
-                                       # b. _foo suffix number
-                                       suffix) prev=suffix_num;;
-                                       # c. -rN revision number
-                                       revision) prev=revision_num;;
-                                       *) return 1;;
-                               esac
-                       elif [[ -n ${c} ]]; then
-                               # letter without preceding sep = letter after 
version
-                               [[ ${prev} == numeric ]] || return 1
-                               [[ ${#c} -eq 1 ]] || return 1
-                               prev=letter
-                       fi
-               elif [[ -z ${c} ]]; then
-                       # trailing suffix?
-                       return 1
-               elif [[ ${s} == . ]]; then
-                       # number preceded by dot = numeric component
-                       [[ ${prev} == numeric ]] || return 1
-               elif [[ ${s} == _ ]]; then
-                       # _ implies _foo suffix
-                       case ${prev} in
-                               numeric|letter|suffix|suffix_num) ;;
-                               *) return 1;;
-                       esac
-
-                       case ${c} in
-                               alpha) ;;
-                               beta) ;;
-                               rc) ;;
-                               pre) ;;
-                               p) ;;
-                               *) return 1;;
-                       esac
-                       prev=suffix
-               elif [[ ${s} == - ]]; then
-                       # - implies revision
-                       case ${prev} in
-                               numeric|letter|suffix|suffix_num) ;;
-                               *) return 1;;
-                       esac
-
-                       [[ ${c} == r ]] || return 1
-                       prev=revision
+# Compare two versions <va> and <vb>.  If <va> is less than, equal to,
+# or greater than <vb>, return 1, 2, or 3 as exit status, respectively.
+_ver_compare() {
+       local va=${1} vb=${2} a an al as ar b bn bl bs br re LC_ALL=C
+
+       
re="^([0-9]+(\.[0-9]+)*)([a-z]?)((_(alpha|beta|pre|rc|p)[0-9]*)*)(-r[0-9]+)?$"
+
+       [[ ${va} =~ ${re} ]] || die "${FUNCNAME}: invalid version: ${va}"
+       an=${BASH_REMATCH[1]}
+       al=${BASH_REMATCH[3]}
+       as=${BASH_REMATCH[4]}
+       ar=${BASH_REMATCH[7]}
+
+       [[ ${vb} =~ ${re} ]] || die "${FUNCNAME}: invalid version: ${vb}"
+       bn=${BASH_REMATCH[1]}
+       bl=${BASH_REMATCH[3]}
+       bs=${BASH_REMATCH[4]}
+       br=${BASH_REMATCH[7]}
+
+       # Compare numeric components (PMS algorithm 3.2)
+       # First component
+       a=${an%%.*}
+       b=${bn%%.*}
+       [[ 10#${a} -gt 10#${b} ]] && return 3
+       [[ 10#${a} -lt 10#${b} ]] && return 1
+
+       while [[ ${an} == *.* && ${bn} == *.* ]]; do
+               # Other components (PMS algorithm 3.3)
+               an=${an#*.}
+               bn=${bn#*.}
+               a=${an%%.*}
+               b=${bn%%.*}
+               if [[ ${a} == 0* || ${b} == 0* ]]; then
+                       # Remove any trailing zeros
+                       [[ ${a} =~ 0+$ ]] && a=${a%"${BASH_REMATCH[0]}"}
+                       [[ ${b} =~ 0+$ ]] && b=${b%"${BASH_REMATCH[0]}"}
+                       [[ ${a} > ${b} ]] && return 3
+                       [[ ${a} < ${b} ]] && return 1
                else
-                       return 1
+                       [[ ${a} -gt ${b} ]] && return 3
+                       [[ ${a} -lt ${b} ]] && return 1
                fi
-
-               shift 2
        done
+       [[ ${an} == *.* ]] && return 3
+       [[ ${bn} == *.* ]] && return 1
+
+       # Compare letter components (PMS algorithm 3.4)
+       [[ ${al} > ${bl} ]] && return 3
+       [[ ${al} < ${bl} ]] && return 1
+
+       # Compare suffixes (PMS algorithm 3.5)
+       as=${as#_}${as:+_}
+       bs=${bs#_}${bs:+_}
+       while [[ -n ${as} && -n ${bs} ]]; do
+               # Compare each suffix (PMS algorithm 3.6)
+               a=${as%%_*}
+               b=${bs%%_*}
+               if [[ ${a%%[0-9]*} == "${b%%[0-9]*}" ]]; then
+                       [[ 10#${a##*[a-z]} -gt 10#${b##*[a-z]} ]] && return 3
+                       [[ 10#${a##*[a-z]} -lt 10#${b##*[a-z]} ]] && return 1
+               else
+                       # Check for p first
+                       [[ ${a%%[0-9]*} == p ]] && return 3
+                       [[ ${b%%[0-9]*} == p ]] && return 1
+                       # Hack: Use that alpha < beta < pre < rc alphabetically
+                       [[ ${a} > ${b} ]] && return 3 || return 1
+               fi
+               as=${as#*_}
+               bs=${bs#*_}
+       done
+       if [[ -n ${as} ]]; then
+               [[ ${as} == p[_0-9]* ]] && return 3 || return 1
+       elif [[ -n ${bs} ]]; then
+               [[ ${bs} == p[_0-9]* ]] && return 1 || return 3
+       fi
 
-       # empty version string?
-       [[ ${prev} != start ]] || return 1
+       # Compare revision components (PMS algorithm 3.7)
+       [[ 10#${ar#-r} -gt 10#${br#-r} ]] && return 3
+       [[ 10#${ar#-r} -lt 10#${br#-r} ]] && return 1
 
-       return 0
+       return 2
 }
 
 # @FUNCTION: ver_test
@@ -258,7 +271,6 @@ _ver_validate() {
 # revision parts), and the comparison is performed according to
 # the algorithm specified in the PMS.
 ver_test() {
-       local LC_ALL=C
        local va op vb
 
        if [[ $# -eq 3 ]]; then
@@ -278,143 +290,6 @@ ver_test() {
                *) die "${FUNCNAME}: invalid operator: ${op}" ;;
        esac
 
-       # explicitly strip -r0[00000...] to avoid overcomplexifying the algo
-       [[ ${va} == *-r0* && 10#${va#*-r} -eq 0 ]] && va=${va%-r*}
-       [[ ${vb} == *-r0* && 10#${vb#*-r} -eq 0 ]] && vb=${vb%-r*}
-
-       local comp compb
-       _ver_split "${vb}"
-       compb=( "${comp[@]}" )
-       _ver_split "${va}"
-
-       _ver_validate "${comp[@]}" || die "${FUNCNAME}: invalid version: ${va}"
-       _ver_validate "${compb[@]}" || die "${FUNCNAME}: invalid version: ${vb}"
-
-       local i sa sb ca cb wa wb result=0
-       for (( i = 0;; i += 2 )); do
-               sa=${comp[i]}
-               ca=${comp[i+1]}
-               sb=${compb[i]}
-               cb=${compb[i+1]}
-
-               # 1. determine the component type for Ca
-               if [[ -z ${sa} ]]; then
-                       if [[ ${ca} == [0-9]* ]]; then
-                               # number without preceding sep may be either:
-                               # a. 1st version number
-                               # b. _foo suffix number
-                               # c. -rN revision number
-                               # weight is irrelevant since (a) occurs 
simultaneously,
-                               # and (b)/(c) use weight of preceding component
-                               wa=0
-                               # method: plain numeric
-                               m=pn
-                       elif [[ -n ${ca} ]]; then
-                               # letter without preceding sep = letter after 
version
-                               # weight below numeric, lexical method
-                               wa=9
-                               m=l
-                       else
-                               # empty == end of version string
-                               # weight below all positive stuff but above 
negative
-                               wa=6
-                               m=
-                       fi
-               elif [[ ${sa} == . ]]; then
-                       # number preceded by dot = numeric component
-                       # highest weight, weird PMS 2+ component comparison
-                       wa=10
-                       m=wn
-               elif [[ ${sa} == _ ]]; then
-                       # _ implies _foo suffix
-                       # weights differ, comparison by weight
-                       case ${ca} in
-                               alpha) wa=2 ;;
-                               beta) wa=3 ;;
-                               rc) wa=4 ;;
-                               pre) wa=5 ;;
-                               p) wa=8 ;;
-                               *) die "Invalid version suffix: _${ca}";;
-                       esac
-                       m=
-               elif [[ ${sa} == - ]]; then
-                       # - implies revision
-                       # weight below positive suffixes, no comparison
-                       [[ ${ca} == r ]] || die "Invalid version part: -${ca}"
-                       wa=7
-                       m=
-               fi
-
-               # 2. determine the component type for Cb
-               if [[ -z ${sb} ]]; then
-                       if [[ ${cb} == [0-9]* ]]; then
-                               wb=0
-                       elif [[ -n ${cb} ]]; then
-                               wb=9
-                       else
-                               wb=6
-                       fi
-               elif [[ ${sb} == . ]]; then
-                       wb=10
-               elif [[ ${sb} == _ ]]; then
-                       case ${cb} in
-                               alpha) wb=2 ;;
-                               beta) wb=3 ;;
-                               rc) wb=4 ;;
-                               pre) wb=5 ;;
-                               p) wb=8 ;;
-                               *) die "Invalid version suffix: _${cb}";;
-                       esac
-               elif [[ ${sb} == - ]]; then
-                       [[ ${cb} == r ]] || die "Invalid version part: -${cb}"
-                       wb=7
-               fi
-
-               # DEBUG
-               #echo "$sa $ca [$wa] <$m> $sb $cb [$wb]" >&2
-
-               # 3. compare weights, we can proceed further only if weights 
match
-               if [[ ${wa} -ne ${wb} ]]; then
-                       result=$(( wa - wb ))
-                       break
-               fi
-
-               # 4. both empty maybe?
-               [[ -z ${ca} && -z ${cb} ]] && break
-
-               # 5. compare components according to the algo
-
-               # weird numeric is weird and reuses pn/l, so do it first
-               # (PMS algo 3.3)
-               if [[ ${m} == wn ]]; then
-                       if [[ ${ca} != 0* && ${cb} != 0* ]]; then
-                               # if neither of them starts with 0, use normal 
numeric
-                               m=pn
-                       else
-                               # strip trailing zeros
-                               while [[ ${ca} == *0 ]]; do ca=${ca::-1}; done
-                               while [[ ${cb} == *0 ]]; do cb=${cb::-1}; done
-                               m=l
-                       fi
-               fi
-
-               case ${m} in
-                       pn) # plain numeric
-                               if [[ 10#${ca} -ne 10#${cb} ]]; then
-                                       result=$(( 10#${ca} - 10#${cb} ))
-                                       break
-                               fi
-                               ;;
-                       l) # lexical
-                               if [[ ${ca} != ${cb} ]]; then
-                                       [[ ${ca} > ${cb} ]] && result=1 || 
result=-1
-                                       break
-                               fi
-                               ;;
-                       '') ;;
-                       *) die "Unexpected comparison method m=${m}";;
-               esac
-       done
-
-       test "${result}" "${op}" 0
+       _ver_compare "${va}" "${vb}"
+       test $? "${op}" 2
 }

Reply via email to