require_tool.sh 4.3 KB

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