Skip to content

Commit

Permalink
eapi7-ver.eclass: Initial implementation of ver_test().
Browse files Browse the repository at this point in the history
This should strictly follow Algorithms 3.1 to 3.7 specified in PMS:
https://projects.gentoo.org/pms/6/pms.html#x1-310003.3
  • Loading branch information
ulm committed Sep 26, 2017
1 parent 6c1c7d8 commit 8a8ce07
Show file tree
Hide file tree
Showing 3 changed files with 269 additions and 3 deletions.
126 changes: 123 additions & 3 deletions eclass/eapi7-ver.eclass
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
#
# https://bugs.gentoo.org/482170
#
# Note: version comparison function is not included currently.
#
# @ROFF .SS
# Version strings
#
Expand Down Expand Up @@ -185,5 +183,127 @@ ver_rs() {
# revision parts), and the comparison is performed according to
# the algorithm specified in the PMS.
ver_test() {
die "${FUNCNAME}: not implemented"
local v1 v2 op i tail result
local -a v1comp v2comp
local match=(
"+([0-9])*(.+([0-9]))" # numeric components
"[a-z]" # letter component
"*(@(_alpha|_beta|_pre|_rc|_p)*([0-9]))" # suffixes
"-r+([0-9])" # revision
)

local LC_ALL=C shopt_save=$(shopt -p extglob)
shopt -s extglob

if [[ $# -eq 2 ]]; then
v1=${PVR}
elif [[ $# -eq 3 ]]; then
v1=$1; shift
else
die "${FUNCNAME}: bad number of arguments"
fi
op=$1
v2=$2

case ${op} in
-eq|-ne|-lt|-le|-gt|-ge) ;;
*) die "${FUNCNAME}: invalid operator: ${op}" ;;
esac

# Test for both versions being valid, and split them into parts
for (( i=0; i<4; i++ )); do
tail=${v1##${match[i]}}
v1comp[i]=${v1%"${tail}"}
v1=${tail}
tail=${v2##${match[i]}}
v2comp[i]=${v2%"${tail}"}
v2=${tail}
done
# There must not be any remaining tail, and the numeric part
# must be non-empty. All other parts are optional.
[[ -z ${v1} && -z ${v2} && -n ${v1comp[0]} && -n ${v2comp[0]} ]] \
|| die "${FUNCNAME}: invalid version"

# Compare numeric components (PMS algorithm 3.2)
_ver_cmp_num() {
local a=(${1//./ }) b=(${2//./ })
local an=${#a[@]} bn=${#b[@]}
local i
# First component
[[ 10#${a[0]} -gt 10#${b[0]} ]] && return 2
[[ 10#${a[0]} -lt 10#${b[0]} ]] && return 1
for (( i=1; i<an && i<bn; i++ )); do
# Other components (PMS algorithm 3.3)
if [[ ${a[i]} == 0* || ${b[i]} == 0* ]]; then
local ap=${a[i]%%*(0)} bp=${b[i]%%*(0)}
[[ ${ap} > ${bp} ]] && return 2
[[ ${ap} < ${bp} ]] && return 1
else
[[ ${a[i]} -gt ${b[i]} ]] && return 2
[[ ${a[i]} -lt ${b[i]} ]] && return 1
fi
done
[[ ${an} -gt ${bn} ]] && return 2
[[ ${an} -lt ${bn} ]] && return 1
return 0
}

# Compare letter components (PMS algorithm 3.4)
_ver_cmp_let() {
local a=$1 b=$2
[[ ${a} > ${b} ]] && return 2
[[ ${a} < ${b} ]] && return 1
return 0
}

# Compare suffixes (PMS algorithm 3.5)
_ver_cmp_suf() {
local a=(${1//_/ }) b=(${2//_/ })
local an=${#a[@]} bn=${#b[@]}
local i
for (( i=0; i<an && i<bn; i++ )); do
# Compare each suffix (PMS algorithm 3.6)
if [[ ${a[i]%%*([0-9])} == "${b[i]%%*([0-9])}" ]]; then
[[ 10#${a[i]##*([a-z])} -gt 10#${b[i]##*([a-z])} ]] && return 2
[[ 10#${a[i]##*([a-z])} -lt 10#${b[i]##*([a-z])} ]] && return 1
else
# Check for p first
[[ ${a[i]} == p*([0-9]) ]] && return 2
[[ ${b[i]} == p*([0-9]) ]] && return 1
# Hack: Use that alpha < beta < pre < rc alphabetically
[[ ${a[i]} > ${b[i]} ]] && return 2 || return 1
fi
done
if [[ ${an} -gt ${bn} ]]; then
[[ ${a[bn]} == p*([0-9]) ]] && return 2 || return 1
elif [[ ${an} -lt ${bn} ]]; then
[[ ${b[an]} == p*([0-9]) ]] && return 1 || return 2
fi
return 0
}

# Compare revision components (PMS algorithm 3.7)
_ver_cmp_rev() {
local a=${1#-r} b=${2#-r}
[[ 10#${a} -gt 10#${b} ]] && return 2
[[ 10#${a} -lt 10#${b} ]] && return 1
return 0
}

# Version comparison top-level logic (PMS algorithm 3.1)
_ver_cmp_num "${v1comp[0]}" "${v2comp[0]}" &&
_ver_cmp_let "${v1comp[1]}" "${v2comp[1]}" &&
_ver_cmp_suf "${v1comp[2]}" "${v2comp[2]}" &&
_ver_cmp_rev "${v1comp[3]}" "${v2comp[3]}"

case $? in
0) result=0 ;; # a = b
1) result=-1 ;; # a < b
2) result=1 ;; # a > b
*) die "${FUNCNAME}: invalid return code: $?" ;;
esac

${shopt_save}

test "${result}" "${op}" 0
}
112 changes: 112 additions & 0 deletions eclass/tests/eapi7-ver.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ teq() {
tend ${?} "returned: ${got}"
}

teqr() {
local expected=$1; shift
tbegin "$* -> ${expected}"
"$@"
local ret=$?
[[ ${ret} -eq ${expected} ]]
tend $? "returned: ${ret}"
}

txf() {
tbegin "XFAIL: ${*}"
local got=$("${@}" 2>&1)
Expand Down Expand Up @@ -63,3 +72,106 @@ teq 1.2.3 ver_rs 3-5 . 1.2.3
txf ver_cut foo 1.2.3
txf ver_rs -3 _ a1b2c3d4e5
txf ver_rs 5-3 _ a1b2c3d4e5

# Tests from Portage's test_vercmp.py
teqr 0 ver_test 6.0 -gt 5.0
teqr 0 ver_test 5.0 -gt 5
teqr 0 ver_test 1.0-r1 -gt 1.0-r0
teqr 0 ver_test 999999999999999999 -gt 999999999999999998 # 18 digits
teqr 0 ver_test 1.0.0 -gt 1.0
teqr 0 ver_test 1.0.0 -gt 1.0b
teqr 0 ver_test 1b -gt 1
teqr 0 ver_test 1b_p1 -gt 1_p1
teqr 0 ver_test 1.1b -gt 1.1
teqr 0 ver_test 12.2.5 -gt 12.2b
teqr 0 ver_test 4.0 -lt 5.0
teqr 0 ver_test 5 -lt 5.0
teqr 0 ver_test 1.0_pre2 -lt 1.0_p2
teqr 0 ver_test 1.0_alpha2 -lt 1.0_p2
teqr 0 ver_test 1.0_alpha1 -lt 1.0_beta1
teqr 0 ver_test 1.0_beta3 -lt 1.0_rc3
teqr 0 ver_test 1.001000000000000001 -lt 1.001000000000000002
teqr 0 ver_test 1.00100000000 -lt 1.001000000000000001
teqr 0 ver_test 999999999999999998 -lt 999999999999999999
teqr 0 ver_test 1.01 -lt 1.1
teqr 0 ver_test 1.0-r0 -lt 1.0-r1
teqr 0 ver_test 1.0 -lt 1.0-r1
teqr 0 ver_test 1.0 -lt 1.0.0
teqr 0 ver_test 1.0b -lt 1.0.0
teqr 0 ver_test 1_p1 -lt 1b_p1
teqr 0 ver_test 1 -lt 1b
teqr 0 ver_test 1.1 -lt 1.1b
teqr 0 ver_test 12.2b -lt 12.2.5
teqr 0 ver_test 4.0 -eq 4.0
teqr 0 ver_test 1.0 -eq 1.0
teqr 0 ver_test 1.0-r0 -eq 1.0
teqr 0 ver_test 1.0 -eq 1.0-r0
teqr 0 ver_test 1.0-r0 -eq 1.0-r0
teqr 0 ver_test 1.0-r1 -eq 1.0-r1
teqr 1 ver_test 1 -eq 2
teqr 1 ver_test 1.0_alpha -eq 1.0_pre
teqr 1 ver_test 1.0_beta -eq 1.0_alpha
teqr 1 ver_test 1 -eq 0.0
teqr 1 ver_test 1.0-r0 -eq 1.0-r1
teqr 1 ver_test 1.0-r1 -eq 1.0-r0
teqr 1 ver_test 1.0 -eq 1.0-r1
teqr 1 ver_test 1.0-r1 -eq 1.0
teqr 1 ver_test 1.0 -eq 1.0.0
teqr 1 ver_test 1_p1 -eq 1b_p1
teqr 1 ver_test 1b -eq 1
teqr 1 ver_test 1.1b -eq 1.1
teqr 1 ver_test 12.2b -eq 12.2

# A subset of tests from Paludis
teqr 0 ver_test 1.0_alpha -gt 1_alpha
teqr 0 ver_test 1.0_alpha -gt 1
teqr 0 ver_test 1.0_alpha -lt 1.0
teqr 0 ver_test 1.2.0.0_alpha7-r4 -gt 1.2_alpha7-r4
teqr 0 ver_test 0001 -eq 1
teqr 0 ver_test 01 -eq 001
teqr 0 ver_test 0001.1 -eq 1.1
teqr 0 ver_test 01.01 -eq 1.01
teqr 0 ver_test 1.010 -eq 1.01
teqr 0 ver_test 1.00 -eq 1.0
teqr 0 ver_test 1.0100 -eq 1.010
teqr 0 ver_test 1-r00 -eq 1-r0

# Additional tests
teqr 0 ver_test 0_rc99 -lt 0
teqr 0 ver_test 011 -eq 11
teqr 0 ver_test 019 -eq 19
teqr 0 ver_test 1.2 -eq 001.2
teqr 0 ver_test 1.2 -gt 1.02
teqr 0 ver_test 1.2a -lt 1.2b
teqr 0 ver_test 1.2_pre1 -gt 1.2_pre1_beta2
teqr 0 ver_test 1.2_pre1 -lt 1.2_pre1_p2
teqr 0 ver_test 1.00 -lt 1.0.0
teqr 0 ver_test 1.010 -eq 1.01
teqr 0 ver_test 1.01 -lt 1.1
teqr 0 ver_test 1.2_pre08-r09 -eq 1.2_pre8-r9
teqr 0 ver_test 0 -lt 576460752303423488 # 2**59
#teqr 0 ver_test 0 -lt 9223372036854775808 # 2**63 fails, integer rollover

# Bad number or ordering of arguments
txf ver_test 1
txf ver_test 1 -lt 2 3
txf ver_test -lt 1 2

# Bad operators
txf ver_test 1 "<" 2
txf ver_test 1 lt 2
txf ver_test 1 -foo 2

# Malformed versions
txf ver_test "" -ne 1
txf ver_test 1. -ne 1
txf ver_test 1ab -ne 1
txf ver_test b -ne 1
txf ver_test 1-r1_pre -ne 1
txf ver_test 1-pre1 -ne 1
txf ver_test 1_foo -ne 1
txf ver_test 1_pre1.1 -ne 1
txf ver_test 1-r1.0 -ne 1
txf ver_test cvs.9999 -ne 9999

texit
34 changes: 34 additions & 0 deletions eclass/tests/eapi7-ver_benchmark.sh
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,38 @@ replacing_versionator() {
done >/dev/null
}

comparing() {
local x
for x in {1..1000}; do
ver_test 1b_p1 -le 1_p1
ver_test 1.1b -le 1.1
ver_test 12.2.5 -le 12.2b
ver_test 4.0 -le 5.0
ver_test 5 -le 5.0
ver_test 1.0_pre2 -le 1.0_p2
ver_test 1.0_alpha2 -le 1.0_p2
ver_test 1.0_alpha1 -le 1.0_beta1
ver_test 1.0_beta3 -le 1.0_rc3
ver_test 1.001000000000000001 -le 1.001000000000000002
done
}

comparing_versionator() {
local x
for x in {1..100}; do
version_is_at_least 1b_p1 1_p1
version_is_at_least 1.1b 1.1
version_is_at_least 12.2.5 12.2b
version_is_at_least 4.0 5.0
version_is_at_least 5 5.0
version_is_at_least 1.0_pre2 1.0_p2
version_is_at_least 1.0_alpha2 1.0_p2
version_is_at_least 1.0_alpha1 1.0_beta1
version_is_at_least 1.0_beta3 1.0_rc3
version_is_at_least 1.001000000000000001 1.001000000000000002
done
}

get_times() {
local factor=${1}; shift
echo "${*}"
Expand Down Expand Up @@ -111,3 +143,5 @@ get_times 1 cutting
get_times 10 cutting_versionator
get_times 1 replacing
get_times 10 replacing_versionator
get_times 1 comparing
get_times 10 comparing_versionator

0 comments on commit 8a8ce07

Please sign in to comment.