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

Change-Id: Ie55283acdc40a095b80b2631a55310072883ad0d

Ian Wienand authored on 2015/11/12 11:52:36
Showing 3 changed files
... ...
@@ -527,12 +527,58 @@ function vercmp_numbers {
527 527
     typeset v1=$1 v2=$2 sep
528 528
     typeset -a ver1 ver2
529 529
 
530
+    deprecated "vercmp_numbers is deprecated for more generic vercmp"
531
+
530 532
     IFS=. read -ra ver1 <<< "$v1"
531 533
     IFS=. read -ra ver2 <<< "$v2"
532 534
 
533 535
     _vercmp_r "${#ver1[@]}" "${ver1[@]}" "${ver2[@]}"
534 536
 }
535 537
 
538
+# vercmp ver1 op ver2
539
+#  Compare VER1 to VER2
540
+#   - op is one of < <= == >= >
541
+#   - returns true if satisified
542
+#  e.g.
543
+#  if vercmp 1.0 "<" 2.0; then
544
+#    ...
545
+#  fi
546
+function vercmp {
547
+    local v1=$1
548
+    local op=$2
549
+    local v2=$3
550
+    local result
551
+
552
+    # sort the two numbers with sort's "-V" argument.  Based on if v2
553
+    # swapped places with v1, we can determine ordering.
554
+    result=$(echo -e "$v1\n$v2" | sort -V | head -1)
555
+
556
+    case $op in
557
+        "==")
558
+            [ "$v1" = "$v2" ]
559
+            return
560
+            ;;
561
+        ">")
562
+            [ "$v1" != "$v2" ] && [ "$result" = "$v2" ]
563
+            return
564
+            ;;
565
+        "<")
566
+            [ "$v1" != "$v2" ] && [ "$result" = "$v1" ]
567
+            return
568
+            ;;
569
+        ">=")
570
+            [ "$result" = "$v2" ]
571
+            return
572
+            ;;
573
+        "<=")
574
+            [ "$result" = "$v1" ]
575
+            return
576
+            ;;
577
+        *)
578
+            die $LINENO "unrecognised op: $op"
579
+            ;;
580
+    esac
581
+}
536 582
 
537 583
 # This function sets log formatting options for colorizing log
538 584
 # output to stdout. It is meant to be called by lib modules.
539 585
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
... ...
@@ -92,6 +92,51 @@ function assert_empty {
92 92
     fi
93 93
 }
94 94
 
95
+# assert the arguments evaluate to true
96
+#  assert_true "message" arg1 arg2
97
+function assert_true {
98
+    local lineno
99
+    lineno=`caller 0 | awk '{print $1}'`
100
+    local function
101
+    function=`caller 0 | awk '{print $2}'`
102
+    local msg=$1
103
+    shift
104
+
105
+    $@
106
+    if [ $? -eq 0 ]; then
107
+        PASS=$((PASS+1))
108
+        echo "PASS: $function:L$lineno - $msg"
109
+    else
110
+        FAILED_FUNCS+="$function:L$lineno\n"
111
+        echo "ERROR: test failed in $function:L$lineno!"
112
+        echo "  $msg"
113
+        ERROR=$((ERROR+1))
114
+    fi
115
+}
116
+
117
+# assert the arguments evaluate to false
118
+#  assert_false "message" arg1 arg2
119
+function assert_false {
120
+    local lineno
121
+    lineno=`caller 0 | awk '{print $1}'`
122
+    local function
123
+    function=`caller 0 | awk '{print $2}'`
124
+    local msg=$1
125
+    shift
126
+
127
+    $@
128
+    if [ $? -eq 0 ]; then
129
+        FAILED_FUNCS+="$function:L$lineno\n"
130
+        echo "ERROR: test failed in $function:L$lineno!"
131
+        echo "  $msg"
132
+        ERROR=$((ERROR+1))
133
+    else
134
+        PASS=$((PASS+1))
135
+        echo "PASS: $function:L$lineno - $msg"
136
+    fi
137
+}
138
+
139
+
95 140
 # Print a summary of passing and failing tests and exit
96 141
 # (with an error if we have failed tests)
97 142
 #  usage: report_results