--- /var/portage/eclass/versionator.eclass 2010-07-23 20:04:42.000000000 -0400 +++ versionator.eclass 2011-06-30 06:40:19.102864662 -0400 @@ -315,67 +315,91 @@ version_is_at_least() { version_compare() { eshopts_push -s extglob local ver_a=${1} ver_b=${2} parts_a parts_b cur_idx_a=0 cur_idx_b=0 + local cur_tok_a cur_tok_b num_part_a num_part_b prev_idx_a prev_idx_b parts_a=( $(get_all_version_components "${ver_a}" ) ) parts_b=( $(get_all_version_components "${ver_b}" ) ) ### compare number parts. local inf_loop=0 while true ; do - inf_loop=$(( ${inf_loop} + 1 )) - [[ ${inf_loop} -gt 20 ]] && \ + (( inf_loop++ )) + (( inf_loop > 20 )) && \ die "versionator compare bug [numbers, ${ver_a}, ${ver_b}]" + # Store the current index to test later + prev_idx_a=$cur_idx_a + prev_idx_b=$cur_idx_b + # grab the current number components - local cur_tok_a=${parts_a[${cur_idx_a}]} - local cur_tok_b=${parts_b[${cur_idx_b}]} + cur_tok_a=${parts_a[cur_idx_a]} + cur_tok_b=${parts_b[cur_idx_b]} # number? if [[ -n ${cur_tok_a} ]] && [[ -z ${cur_tok_a//[[:digit:]]} ]] ; then - cur_idx_a=$(( ${cur_idx_a} + 1 )) - [[ ${parts_a[${cur_idx_a}]} == "." ]] \ - && cur_idx_a=$(( ${cur_idx_a} + 1 )) + (( cur_idx_a++ )) + [[ ${parts_a[cur_idx_a]} == "." ]] \ + && (( cur_idx_a++ )) else cur_tok_a="" fi if [[ -n ${cur_tok_b} ]] && [[ -z ${cur_tok_b//[[:digit:]]} ]] ; then - cur_idx_b=$(( ${cur_idx_b} + 1 )) - [[ ${parts_b[${cur_idx_b}]} == "." ]] \ - && cur_idx_b=$(( ${cur_idx_b} + 1 )) + (( cur_idx_b++ )) + [[ ${parts_b[cur_idx_b]} == "." ]] \ + && (( cur_idx_b++ )) else cur_tok_b="" fi # done with number components? - [[ -z ${cur_tok_a} ]] && [[ -z ${cur_tok_b} ]] && break + [[ -z ${cur_tok_a} && -z ${cur_tok_b} ]] && break - # to avoid going into octal mode, strip any leading zeros. otherwise - # bash will throw a hissy fit on versions like 6.3.068. - cur_tok_a=${cur_tok_a##+(0)} - cur_tok_b=${cur_tok_b##+(0)} - - # if a component is blank, make it zero. - [[ -z ${cur_tok_a} ]] && cur_tok_a=0 - [[ -z ${cur_tok_b} ]] && cur_tok_b=0 - - # compare - [[ ${cur_tok_a} -lt ${cur_tok_b} ]] && eshopts_pop && return 1 - [[ ${cur_tok_a} -gt ${cur_tok_b} ]] && eshopts_pop && return 3 + # if a component is blank, then it is the lesser value + [[ -z ${cur_tok_a} ]] && eshopts_pop && return 1 + [[ -z ${cur_tok_b} ]] && eshopts_pop && return 3 + + # According to PMS, if we are *not* in the first number part, and either + # token begins with "0", then we use a different algorithm (that + # effectively does floating point comparison) + if [[ ${prev_idx_a} != 0 && ${prev_idx_b} != 0 ]] \ + && [[ ${cur_tok_a} == 0* || ${cur_tok_b} == 0* ]] ; then + + # strip trailing zeros + cur_tok_a=${cur_tok_a%%+(0)} + cur_tok_b=${cur_tok_b%%+(0)} + + # do a *string* comparison of the resulting values: 2 > 11 + [[ ${cur_tok_a} < ${cur_tok_b} ]] && eshopts_pop && return 1 + [[ ${cur_tok_a} > ${cur_tok_b} ]] && eshopts_pop && return 3 + else + # to avoid going into octal mode, strip any leading zeros. otherwise + # bash will throw a hissy fit on versions like 6.3.068. + cur_tok_a=${cur_tok_a##+(0)} + cur_tok_b=${cur_tok_b##+(0)} + + # now if a component is blank, it was originally 0 -- make it so + : ${cur_tok_a:=0} + : ${cur_tok_b:=0} + + # compare + (( cur_tok_a < cur_tok_b )) && eshopts_pop && return 1 + (( cur_tok_a > cur_tok_b )) && eshopts_pop && return 3 + fi done ### number parts equal. compare letter parts. local letter_a= - letter_a=${parts_a[${cur_idx_a}]} + letter_a=${parts_a[cur_idx_a]} if [[ ${#letter_a} -eq 1 ]] && [[ -z ${letter_a/[a-z]} ]] ; then - cur_idx_a=$(( ${cur_idx_a} + 1 )) + (( cur_idx_a++ )) else letter_a="@" fi local letter_b= - letter_b=${parts_b[${cur_idx_b}]} + letter_b=${parts_b[cur_idx_b]} if [[ ${#letter_b} -eq 1 ]] && [[ -z ${letter_b/[a-z]} ]] ; then - cur_idx_b=$(( ${cur_idx_b} + 1 )) + (( cur_idx_b++ )) else letter_b="@" fi @@ -385,38 +409,74 @@ version_compare() { [[ ${letter_a} > ${letter_b} ]] && eshopts_pop && return 3 ### letter parts equal. compare suffixes in order. - local suffix rule part r_lt r_gt - for rule in "alpha=1" "beta=1" "pre=1" "rc=1" "p=3" "r=3" ; do - suffix=${rule%%=*} - r_lt=${rule##*=} - [[ ${r_lt} -eq 1 ]] && r_gt=3 || r_gt=1 - - local suffix_a= - for part in ${parts_a[@]} ; do - [[ ${part#${suffix}} != ${part} ]] && \ - [[ -z ${part##${suffix}*([[:digit:]])} ]] && \ - suffix_a=${part#${suffix}}0 - done + inf_loop=0 + while true ; do + (( inf_loop++ )) + (( inf_loop > 20 )) && \ + die "versionator compare bug [numbers, ${ver_a}, ${ver_b}]" + [[ ${parts_a[cur_idx_a]} == "_" ]] && (( cur_idx_a++ )) + [[ ${parts_b[cur_idx_b]} == "_" ]] && (( cur_idx_b++ )) - local suffix_b= - for part in ${parts_b[@]} ; do - [[ ${part#${suffix}} != ${part} ]] && \ - [[ -z ${part##${suffix}*([[:digit:]])} ]] && \ - suffix_b=${part#${suffix}}0 - done + cur_tok_a=${parts_a[cur_idx_a]} + cur_tok_b=${parts_b[cur_idx_b]} + local num_part_a=0 + local num_part_b=0 + + if has ${cur_tok_a%%+([0-9])} "alpha" "beta" "pre" "rc" "p"; then + (( cur_idx_a++)) + num_part_a=${cur_tok_a##+([a-z])} + # I don't like octal + num_part_a=${num_part_a##+(0)} + : ${num_part_a:=0} + cur_tok_a=${cur_tok_a%%+([0-9])} + else + cur_tok_a="" + fi + + if has ${cur_tok_b%%+([0-9])} alpha beta pre rc p; then + (( cur_idx_b++)) + num_part_b=${cur_tok_b##+([a-z])} + # I still don't like octal + num_part_b=${num_part_b##+(0)} + : ${num_part_b:=0} + cur_tok_b=${cur_tok_b%%+([0-9])} + else + cur_tok_b="" + fi - [[ -z ${suffix_a} ]] && [[ -z ${suffix_b} ]] && continue + if [[ ${cur_tok_a} != ${cur_tok_b} ]]; then + local suffix + for suffix in alpha beta pre rc "" p; do + [[ ${cur_tok_a} == ${suffix} ]] && eshopts_pop && return 1 + [[ ${cur_tok_b} == ${suffix} ]] && eshopts_pop && return 3 + done + elif [[ -z ${cur_tok_a} && -z ${cur_tok_b} ]]; then + break + else + (( num_part_a < num_part_b )) && eshopts_pop && return 1 + (( num_part_a > num_part_b )) && eshopts_pop && return 3 + fi + done - [[ -z ${suffix_a} ]] && eshopts_pop && return ${r_gt} - [[ -z ${suffix_b} ]] && eshopts_pop && return ${r_lt} + # At this point, the only thing that should be left is the -r# part + [[ ${parts_a[cur_idx_a]} == "-" ]] && (( cur_idx_a++ )) + [[ ${parts_b[cur_idx_b]} == "-" ]] && (( cur_idx_b++ )) + + # Sanity check + if [[ -n ${parts_a[cur_idx_a]} && ${parts_a[cur_idx_a]} != r+([0-9]) ]] || \ + [[ -n ${parts_b[cur_idx_b]} && ${parts_b[cur_idx_b]} != r+([0-9]) ]]; then + die "versionator compare bug [numbers ${ver_a}, ${ver_b}]" + fi - # avoid octal problems - suffix_a=${suffix_a##+(0)} ; suffix_a=${suffix_a:-0} - suffix_b=${suffix_b##+(0)} ; suffix_b=${suffix_b:-0} + num_part_a=${parts_a[cur_idx_a]#r} + num_part_a=${num_part_a##+(0)} + : ${num_part_a:=0} + num_part_b=${parts_b[cur_idx_b]#r} + num_part_b=${num_part_b##+(0)} + : ${num_part_b:=0} - [[ ${suffix_a} -lt ${suffix_b} ]] && eshopts_pop && return 1 - [[ ${suffix_a} -gt ${suffix_b} ]] && eshopts_pop && return 3 - done + (( num_part_a < num_part_b )) && eshopts_pop && return 1 + (( num_part_a > num_part_b )) && eshopts_pop && return 3 ### no differences. eshopts_pop @@ -470,6 +530,7 @@ version_format_string() { __versionator__test_version_compare() { eshopts_push -s extglob + local lt=1 eq=2 gt=3 p q __versionator__test_version_compare_t() { @@ -507,7 +568,7 @@ __versionator__test_version_compare() { 1.2.3 $lt 1.2.4 1.2.4 $gt 1.2.3 - 1.2.0 $eq 1.2 + 1.2.0 $gt 1.2 1.2.1 $gt 1.2 1.2 $lt 1.2.1 @@ -531,7 +592,7 @@ __versionator__test_version_compare() { 1.0_alpha6-r1 $gt 1.0_alpha6 1.0_beta6-r1 $gt 1.0_alpha6-r2 - 1.0_pre1 $lt 1.0-p1 + 1.0_pre1 $lt 1.0_p1 1.0p $gt 1.0_p1 1.0r $gt 1.0-r1 @@ -544,7 +605,7 @@ __versionator__test_version_compare() { done - for q in "alpha beta pre rc=${lt};${gt}" "p r=${gt};${lt}" ; do + for q in "alpha beta pre rc=${lt};${gt}" "p=${gt};${lt}" ; do for p in ${q%%=*} ; do local c=${q##*=} local alt=${c%%;*} agt=${c##*;} @@ -564,6 +625,14 @@ __versionator__test_version_compare() { __versionator__test_version_compare_t "1_${p}7" $eq "1_${p}7" __versionator__test_version_compare_t "1_${p}7" $gt "1_${p}6" __versionator__test_version_compare_t "1_${p}09" $eq "1_${p}9" + + __versionator__test_version_compare_t "1_${p}7-r0" $eq "1_${p}7" + __versionator__test_version_compare_t "1_${p}7-r0" $lt "1_${p}7-r1" + __versionator__test_version_compare_t "1_${p}7-r0" $lt "1_${p}7-r01" + __versionator__test_version_compare_t "1_${p}7-r01" $eq "1_${p}7-r1" + __versionator__test_version_compare_t "1_${p}8-r1" $gt "1_${p}7-r100" + + __versionator__test_version_compare_t "1_${p}_alpha" $lt "1_${p}_beta" done done @@ -573,5 +642,78 @@ __versionator__test_version_compare() { __versionator__test_version_compare_t "7.2${p}3" $gt "7.2${p}2" __versionator__test_version_compare_t "7.2${p}2" $lt "7.2${p}3" done + + # The following tests all come from portage's test cases: + __versionator__test_version_compare_t "6.0" $gt "5.0" + __versionator__test_version_compare_t "5.0" $gt "5" + __versionator__test_version_compare_t "1.0-r1" $gt "1.0-r0" + __versionator__test_version_compare_t "1.0-r1" $gt "1.0" + __versionator__test_version_compare_t "999999999999999999999999999999" $gt "999999999999999999999999999998" + __versionator__test_version_compare_t "1.0.0" $gt "1.0" + __versionator__test_version_compare_t "1.0.0" $gt "1.0b" + __versionator__test_version_compare_t "1b" $gt "1" + __versionator__test_version_compare_t "1b_p1" $gt "1_p1" + __versionator__test_version_compare_t "1.1b" $gt "1.1" + __versionator__test_version_compare_t "12.2.5" $gt "12.2b" + + __versionator__test_version_compare_t "4.0" $lt "5.0" + __versionator__test_version_compare_t "5" $lt "5.0" + __versionator__test_version_compare_t "1.0_pre2" $lt "1.0_p2" + __versionator__test_version_compare_t "1.0_alpha2" $lt "1.0_p2" + __versionator__test_version_compare_t "1.0_alpha1" $lt "1.0_beta1" + __versionator__test_version_compare_t "1.0_beta3" $lt "1.0_rc3" + __versionator__test_version_compare_t "1.001000000000000000001" $lt "1.001000000000000000002" + __versionator__test_version_compare_t "1.00100000000" $lt "1.0010000000000000001" + __versionator__test_version_compare_t "999999999999999999999999999998" $lt "999999999999999999999999999999" + __versionator__test_version_compare_t "1.01" $lt "1.1" + __versionator__test_version_compare_t "1.0-r0" $lt "1.0-r1" + __versionator__test_version_compare_t "1.0" $lt "1.0-r1" + __versionator__test_version_compare_t "1.0" $lt "1.0.0" + __versionator__test_version_compare_t "1.0b" $lt "1.0.0" + __versionator__test_version_compare_t "1_p1" $lt "1b_p1" + __versionator__test_version_compare_t "1" $lt "1b" + __versionator__test_version_compare_t "1.1" $lt "1.1b" + __versionator__test_version_compare_t "12.2b" $lt "12.2.5" + + __versionator__test_version_compare_t "4.0" $eq "4.0" + __versionator__test_version_compare_t "1.0" $eq "1.0" + __versionator__test_version_compare_t "1.0-r0" $eq "1.0" + __versionator__test_version_compare_t "1.0" $eq "1.0-r0" + __versionator__test_version_compare_t "1.0-r0" $eq "1.0-r0" + __versionator__test_version_compare_t "1.0-r1" $eq "1.0-r1" + + # The following were just tests for != in portage, we need something a bit + # more precise + __versionator__test_version_compare_t "1" $lt "2" + __versionator__test_version_compare_t "1.0_alpha" $lt "1.0_pre" + __versionator__test_version_compare_t "1.0_beta" $gt "1.0_alpha" + __versionator__test_version_compare_t "0" $lt "0.0" + __versionator__test_version_compare_t "1.0-r0" $lt "1.0-r1" + __versionator__test_version_compare_t "1.0-r1" $gt "1.0-r0" + __versionator__test_version_compare_t "1.0" $lt "1.0-r1" + __versionator__test_version_compare_t "1.0-r1" $gt "1.0" + __versionator__test_version_compare_t "1_p1" $lt "1b_p1" + __versionator__test_version_compare_t "1b" $gt "1" + __versionator__test_version_compare_t "1.1b" $gt "1.1" + __versionator__test_version_compare_t "12.2b" $gt "12.2" + + # The following tests all come from paludis's test cases: + __versionator__test_version_compare_t "1.0" $gt "1" + __versionator__test_version_compare_t "1" $lt "1.0" + __versionator__test_version_compare_t "1.0_alpha" $gt "1_alpha" + __versionator__test_version_compare_t "1.0_alpha" $gt "1" + __versionator__test_version_compare_t "1.0_alpha" $lt "1.0" + __versionator__test_version_compare_t "1.2.0.0_alpha7-r4" $gt "1.2_alpha7-r4" + + __versionator__test_version_compare_t "0001" $eq "1" + __versionator__test_version_compare_t "01" $eq "001" + __versionator__test_version_compare_t "0001.1" $eq "1.1" + __versionator__test_version_compare_t "01.01" $eq "1.01" + __versionator__test_version_compare_t "1.010" $eq "1.01" + __versionator__test_version_compare_t "1.00" $eq "1.0" + __versionator__test_version_compare_t "1.0100" $eq "1.010" + __versionator__test_version_compare_t "1" $eq "1-r0" + __versionator__test_version_compare_t "1-r00" $eq "1-r0" + eshopts_pop }