| 1 | __require_tool_version_compare () |
| 2 | { |
| 3 | ( |
| 4 | |
| 5 | |
| 6 | set +e |
| 7 | |
| 8 | awk_strverscmp=' |
| 9 | # Use only awk features that work with 7th edition Unix awk (1978). |
| 10 | # My, what an old awk you have, Mr. Solaris! |
| 11 | END { |
| 12 | while (length(v1) || length(v2)) { |
| 13 | # Set d1 to be the next thing to compare from v1, and likewise for d2. |
| 14 | # Normally this is a single character, but if v1 and v2 contain digits, |
| 15 | # compare them as integers and fractions as strverscmp does. |
| 16 | if (v1 ~ /^[0-9]/ && v2 ~ /^[0-9]/) { |
| 17 | # Split v1 and v2 into their leading digit string components d1 and d2, |
| 18 | # and advance v1 and v2 past the leading digit strings. |
| 19 | for (len1 = 1; substr(v1, len1 + 1) ~ /^[0-9]/; len1++) continue |
| 20 | for (len2 = 1; substr(v2, len2 + 1) ~ /^[0-9]/; len2++) continue |
| 21 | d1 = substr(v1, 1, len1); v1 = substr(v1, len1 + 1) |
| 22 | d2 = substr(v2, 1, len2); v2 = substr(v2, len2 + 1) |
| 23 | if (d1 ~ /^0/) { |
| 24 | if (d2 ~ /^0/) { |
| 25 | # Compare two fractions. |
| 26 | while (d1 ~ /^0/ && d2 ~ /^0/) { |
| 27 | d1 = substr(d1, 2); len1-- |
| 28 | d2 = substr(d2, 2); len2-- |
| 29 | } |
| 30 | if (len1 != len2 && ! (len1 && len2 && substr(d1, 1, 1) == substr(d2, 1, 1))) { |
| 31 | # The two components differ in length, and the common prefix |
| 32 | # contains only leading zeros. Consider the longer to be less. |
| 33 | d1 = -len1 |
| 34 | d2 = -len2 |
| 35 | } else { |
| 36 | # Otherwise, compare as strings. |
| 37 | d1 = "x" d1 |
| 38 | d2 = "x" d2 |
| 39 | } |
| 40 | } else { |
| 41 | # A fraction is less than an integer. |
| 42 | exit 1 |
| 43 | } |
| 44 | } else { |
| 45 | if (d2 ~ /^0/) { |
| 46 | # An integer is greater than a fraction. |
| 47 | exit 2 |
| 48 | } else { |
| 49 | # Compare two integers. |
| 50 | d1 += 0 |
| 51 | d2 += 0 |
| 52 | } |
| 53 | } |
| 54 | } else { |
| 55 | # The normal case, without worrying about digits. |
| 56 | if (v1 == "") d1 = v1; else { d1 = substr(v1, 1, 1); v1 = substr(v1,2) } |
| 57 | if (v2 == "") d2 = v2; else { d2 = substr(v2, 1, 1); v2 = substr(v2,2) } |
| 58 | } |
| 59 | if (d1 < d2) exit 1 |
| 60 | if (d1 > d2) exit 2 |
| 61 | } |
| 62 | } |
| 63 | ' |
| 64 | awk "$awk_strverscmp" v1="$1" v2="$2" /dev/null |
| 65 | case $? in |
| 66 | 1) echo '<';; |
| 67 | 0) echo '=';; |
| 68 | 2) echo '>';; |
| 69 | esac |
| 70 | ) |
| 71 | } |
| 72 | |
| 73 | |
| 74 | __require_tool_fatal () |
| 75 | { |
| 76 | echo $@ >/dev/stderr |
| 77 | return 1 |
| 78 | } |
| 79 | |
| 80 | |
| 81 | |
| 82 | |
| 83 | |
| 84 | |
| 85 | |
| 86 | |
| 87 | require_tool () |
| 88 | { |
| 89 | envvar_name=$(echo $1 | tr '[:lower:]' '[:upper:]') |
| 90 | tool=$(printenv $envvar_name || echo $1) |
| 91 | local version=$($tool --version 2>/dev/null| \ |
| 92 | sed -n 's/.*[^0-9.]\([0-9]*\.[0-9.]*\).*/\1/p;q') |
| 93 | if test x"$version" = x ; then |
| 94 | echo "$tool is required" >/dev/stderr |
| 95 | return 1 |
| 96 | fi |
| 97 | case $(__require_tool_version_compare "$2" "$version") in |
| 98 | '>') |
| 99 | echo "$1 $2 or better is required: this is $tool $version" >/dev/stderr |
| 100 | return 1 |
| 101 | ;; |
| 102 | esac |
| 103 | } |
| 104 | |
| 105 | usage() { |
| 106 | cat <<EOF |
| 107 | NAME |
| 108 | require_tool.sh - Ensure version of a tool is greater than the one expected |
| 109 | |
| 110 | SYNOPSIS |
| 111 | require_tool.sh [ -h ] |
| 112 | [ --help ] |
| 113 | [ TOOL MIN_VERSION ] |
| 114 | |
| 115 | DESCRIPTION |
| 116 | TOOL is the name or path of the program to check. If the name is specified, its |
| 117 | path is deduced from PATH environment variable. If environment variable TOOL |
| 118 | (in upper-case characters) is defined, considers its value as path to the tool. |
| 119 | |
| 120 | MIN_VERSION is a string representing the minimum required version. |
| 121 | |
| 122 | BEHAVIOR |
| 123 | * locate path to the program. |
| 124 | * execute $ TOOL_PATH --version |
| 125 | * extract version from standard output. |
| 126 | * compare this version to the expected one. |
| 127 | |
| 128 | OPTIONS |
| 129 | -h --help |
| 130 | Display this message and exit 0 |
| 131 | |
| 132 | ERRORS |
| 133 | if program is not found or its version is prior to expected version, |
| 134 | a message is written to error output. |
| 135 | |
| 136 | EXIT VALUE |
| 137 | returns 0 if program version if greater equals than expected version, |
| 138 | returns 1 otherwise. |
| 139 | |
| 140 | EXAMPLE |
| 141 | $ require_tool.sh emacs 23 |
| 142 | $ CC=g++ require_tool.sh cc 4.6 |
| 143 | $ require_tool.sh zsh 4.5 |
| 144 | |
| 145 | EOF |
| 146 | } |
| 147 | |
| 148 | for arg in $@; do |
| 149 | case $arg in |
| 150 | -h|--help) |
| 151 | usage |
| 152 | exit 0 |
| 153 | ;; |
| 154 | esac |
| 155 | done |
| 156 | if [ $# -gt 2 ] ; then |
| 157 | echo "ERROR: expecting 2 parameters. Please see option --help" |
| 158 | exit 1 |
| 159 | fi |
| 160 | |
| 161 | require_tool $@ |