Browse code

Add vercmp function

The existing vercmp_numbers function only handles, as the name says,
numbers. I noticed that "sort" has had a version sort for a long time
[1] and, rather than re-implement it badly, use this as a version of
vercmp that works a bit more naturally.

This is intended to be used in an "if" statement as in

prog_ver=$(prog_ver --version | grep ...)
if vercmp $prog_ver "<" 2.0; then
...
fi

A test-case is added to test the basic features and some edge-cases.

[1] http://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=commitdiff;h=4c9fae4e97d95a9f89d1399a8aeb03051f0fec96

Conflicts:
tests/unittest.sh

Change-Id: Ie55283acdc40a095b80b2631a55310072883ad0d
(cherry picked from commit 2ba36cda7940d630514a7864132837191d8c561f)

Ian Wienand authored on 2015/11/12 11:52:36
Showing 3 changed files
... ...
@@ -524,12 +524,58 @@ function vercmp_numbers {
524 524
     typeset v1=$1 v2=$2 sep
525 525
     typeset -a ver1 ver2
526 526
 
527
+    deprecated "vercmp_numbers is deprecated for more generic vercmp"
528
+
527 529
     IFS=. read -ra ver1 <<< "$v1"
528 530
     IFS=. read -ra ver2 <<< "$v2"
529 531
 
530 532
     _vercmp_r "${#ver1[@]}" "${ver1[@]}" "${ver2[@]}"
531 533
 }
532 534
 
535
+# vercmp ver1 op ver2
536
+#  Compare VER1 to VER2
537
+#   - op is one of < <= == >= >
538
+#   - returns true if satisified
539
+#  e.g.
540
+#  if vercmp 1.0 "<" 2.0; then
541
+#    ...
542
+#  fi
543
+function vercmp {
544
+    local v1=$1
545
+    local op=$2
546
+    local v2=$3
547
+    local result
548
+
549
+    # sort the two numbers with sort's "-V" argument.  Based on if v2
550
+    # swapped places with v1, we can determine ordering.
551
+    result=$(echo -e "$v1\n$v2" | sort -V | head -1)
552
+
553
+    case $op in
554
+        "==")
555
+            [ "$v1" = "$v2" ]
556
+            return
557
+            ;;
558
+        ">")
559
+            [ "$v1" != "$v2" ] && [ "$result" = "$v2" ]
560
+            return
561
+            ;;
562
+        "<")
563
+            [ "$v1" != "$v2" ] && [ "$result" = "$v1" ]
564
+            return
565
+            ;;
566
+        ">=")
567
+            [ "$result" = "$v2" ]
568
+            return
569
+            ;;
570
+        "<=")
571
+            [ "$result" = "$v1" ]
572
+            return
573
+            ;;
574
+        *)
575
+            die $LINENO "unrecognised op: $op"
576
+            ;;
577
+    esac
578
+}
533 579
 
534 580
 # This function sets log formatting options for colorizing log
535 581
 # output to stdout. It is meant to be called by lib modules.
536 582
new file mode 100755
... ...
@@ -0,0 +1,47 @@
0
+#!/usr/bin/env bash
1
+
2
+# Tests for DevStack vercmp functionality
3
+
4
+TOP=$(cd $(dirname "$0")/.. && pwd)
5
+
6
+# Import common functions
7
+source $TOP/functions
8
+source $TOP/tests/unittest.sh
9
+
10
+assert_true "numeric gt"  vercmp 2.0 ">" 1.0
11
+assert_true "numeric gte" vercmp 2.0 ">=" 1.0
12
+assert_true "numeric gt"  vercmp 1.0.1 ">" 1.0
13
+assert_true "numeric gte" vercmp 1.0.1 ">=" 1.0
14
+assert_true "alpha gt"    vercmp 1.0.1b ">" 1.0.1a
15
+assert_true "alpha gte"   vercmp 1.0.1b ">=" 1.0.1a
16
+assert_true "alpha gt"    vercmp b ">" a
17
+assert_true "alpha gte"   vercmp b ">=" a
18
+assert_true "alpha gt"    vercmp 2.0-rc3 ">" 2.0-rc1
19
+assert_true "alpha gte"   vercmp 2.0-rc3 ">=" 2.0-rc1
20
+
21
+assert_false "numeric gt fail"  vercmp 1.0 ">" 1.0
22
+assert_true  "numeric gte"      vercmp 1.0 ">=" 1.0
23
+assert_false "numeric gt fail"  vercmp 0.9 ">" 1.0
24
+assert_false "numeric gte fail" vercmp 0.9 ">=" 1.0
25
+assert_false "numeric gt fail"  vercmp 0.9.9 ">" 1.0
26
+assert_false "numeric gte fail" vercmp 0.9.9 ">=" 1.0
27
+assert_false "numeric gt fail"  vercmp 0.9a.9 ">" 1.0.1
28
+assert_false "numeric gte fail" vercmp 0.9a.9 ">=" 1.0.1
29
+
30
+assert_false "numeric lt"  vercmp 1.0 "<" 1.0
31
+assert_true  "numeric lte" vercmp 1.0 "<=" 1.0
32
+assert_true "numeric lt"   vercmp 1.0 "<" 1.0.1
33
+assert_true "numeric lte"  vercmp 1.0 "<=" 1.0.1
34
+assert_true "alpha lt"     vercmp 1.0.1a "<" 1.0.1b
35
+assert_true "alpha lte"    vercmp 1.0.1a "<=" 1.0.1b
36
+assert_true "alpha lt"     vercmp a "<" b
37
+assert_true "alpha lte"    vercmp a "<=" b
38
+assert_true "alpha lt"     vercmp 2.0-rc1 "<" 2.0-rc3
39
+assert_true "alpha lte"    vercmp 2.0-rc1 "<=" 2.0-rc3
40
+
41
+assert_true "eq"       vercmp 1.0 "==" 1.0
42
+assert_true "eq"       vercmp 1.0.1 "==" 1.0.1
43
+assert_false "eq fail" vercmp 1.0.1 "==" 1.0.2
44
+assert_false "eq fail" vercmp 2.0-rc1 "==" 2.0-rc2
45
+
46
+report_results
... ...
@@ -84,6 +84,51 @@ function assert_empty {
84 84
     fi
85 85
 }
86 86
 
87
+# assert the arguments evaluate to true
88
+#  assert_true "message" arg1 arg2
89
+function assert_true {
90
+    local lineno
91
+    lineno=`caller 0 | awk '{print $1}'`
92
+    local function
93
+    function=`caller 0 | awk '{print $2}'`
94
+    local msg=$1
95
+    shift
96
+
97
+    $@
98
+    if [ $? -eq 0 ]; then
99
+        PASS=$((PASS+1))
100
+        echo "PASS: $function:L$lineno - $msg"
101
+    else
102
+        FAILED_FUNCS+="$function:L$lineno\n"
103
+        echo "ERROR: test failed in $function:L$lineno!"
104
+        echo "  $msg"
105
+        ERROR=$((ERROR+1))
106
+    fi
107
+}
108
+
109
+# assert the arguments evaluate to false
110
+#  assert_false "message" arg1 arg2
111
+function assert_false {
112
+    local lineno
113
+    lineno=`caller 0 | awk '{print $1}'`
114
+    local function
115
+    function=`caller 0 | awk '{print $2}'`
116
+    local msg=$1
117
+    shift
118
+
119
+    $@
120
+    if [ $? -eq 0 ]; then
121
+        FAILED_FUNCS+="$function:L$lineno\n"
122
+        echo "ERROR: test failed in $function:L$lineno!"
123
+        echo "  $msg"
124
+        ERROR=$((ERROR+1))
125
+    else
126
+        PASS=$((PASS+1))
127
+        echo "PASS: $function:L$lineno - $msg"
128
+    fi
129
+}
130
+
131
+
87 132
 # print a summary of passing and failing tests, exiting
88 133
 # with an error if we have failed tests
89 134
 #  usage: report_results