From 0d4a8c22f05f89a465f012e5952ef52cb1ac5deb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ulrich=20M=C3=BCller?= Date: Thu, 21 Sep 2017 09:34:19 +0200 Subject: [PATCH] eapi7-ver.eclass: New algorithm for ver_test(). MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 2644832574a3..5ca8b8143af6 100644 --- a/eclass/eapi7-ver.eclass +++ b/eclass/eapi7-ver.eclass @@ -174,79 +174,92 @@ ver_rs() { echo "${comp[*]}" } -# @FUNCTION: _ver_validate -# @USAGE: ... +# @FUNCTION: _ver_compare +# @USAGE: +# @RETURN: 1 if < , 2 if = , 3 if > +# @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 and . If is less than, equal to, +# or greater than , 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 } -- 2.26.2