common-functions.sh 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. # Copyright 2012 Google LLC
  2. #
  3. # Redistribution and use in source and binary forms, with or without
  4. # modification, are permitted provided that the following conditions are
  5. # met:
  6. #
  7. # * Redistributions of source code must retain the above copyright
  8. # notice, this list of conditions and the following disclaimer.
  9. # * Redistributions in binary form must reproduce the above
  10. # copyright notice, this list of conditions and the following disclaimer
  11. # in the documentation and/or other materials provided with the
  12. # distribution.
  13. # * Neither the name of Google LLC nor the names of its
  14. # contributors may be used to endorse or promote products derived from
  15. # this software without specific prior written permission.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  20. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  21. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  22. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  23. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  27. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. # Collection of common shell functions for 'run-checks.sh' et 'test-shell.sh'
  29. # All internal variables and functions use an underscore as a prefix
  30. # (e.g. _VERBOSE, _ALL_CLEANUPS, etc..).
  31. # Sanitize the environment
  32. export LANG=C
  33. export LC_ALL=C
  34. if [ "$BASH_VERSION" ]; then
  35. set -o posix
  36. fi
  37. # Utility functions
  38. _ALL_CLEANUPS=
  39. # Register a function to be called when the script exits, even in case of
  40. # Ctrl-C, logout, etc.
  41. # $1: function name.
  42. atexit () {
  43. if [ -z "$_ALL_CLEANUPS" ]; then
  44. _ALL_CLEANUPS=$1
  45. # Ensure a clean exit when the script is:
  46. # - Exiting normally (EXIT)
  47. # - Interrupted by Ctrl-C (INT)
  48. # - Interrupted by log out (HUP)
  49. # - Being asked to quit nicely (TERM)
  50. # - Being asked to quit and dump core (QUIT)
  51. trap "_exit_cleanups \$?" EXIT INT HUP QUIT TERM
  52. else
  53. _ALL_CLEANUPS="$_ALL_CLEANUPS $1"
  54. fi
  55. }
  56. # Called on exit if at least one function was registered with atexit
  57. # $1: final exit status code
  58. _exit_cleanups () {
  59. local CLEANUP CLEANUPS
  60. # Ignore calls to atexit during cleanups
  61. CLEANUPS=$_ALL_CLEANUPS
  62. _ALL_CLEANUPS=
  63. for CLEANUP in $CLEANUPS; do
  64. ($CLEANUP)
  65. done
  66. exit "$@"
  67. }
  68. # Dump a panic message then exit.
  69. # $1+: message
  70. panic () {
  71. echo "ERROR: $@" >&2
  72. exit 1
  73. }
  74. # If the previous command failed, dump a panic message then exit.
  75. # $1+: message.
  76. fail_panic () {
  77. if [ $? != 0 ]; then
  78. panic "$@"
  79. fi;
  80. }
  81. _VERBOSE=0
  82. # Increase verbosity for dump/log/run/run2 functions
  83. increase_verbosity () {
  84. _VERBOSE=$(( $_VERBOSE + 1 ))
  85. }
  86. # Decrease verbosity
  87. decrease_verbosity () {
  88. _VERBOSE=$(( $_VERBOSE - 1 ))
  89. }
  90. # Returns success iff verbosity level is higher than a specific value
  91. # $1: verbosity level
  92. verbosity_is_higher_than () {
  93. [ "$_VERBOSE" -gt "$1" ]
  94. }
  95. # Returns success iff verbosity level is lower than a specific value
  96. # $1: verbosity level
  97. verbosity_is_lower_than () {
  98. [ "$_VERBOSE" -le "$1" ]
  99. }
  100. # Dump message to stdout, unless verbosity is < 0, i.e. --quiet was called
  101. # $1+: message
  102. dump () {
  103. if [ "$_VERBOSE" -ge 0 ]; then
  104. printf "%s\n" "$*"
  105. fi
  106. }
  107. # If --verbose was used, dump a message to stdout.
  108. # $1+: message
  109. log () {
  110. if [ "$_VERBOSE" -ge 1 ]; then
  111. printf "%s\n" "$*"
  112. fi
  113. }
  114. _RUN_LOG=
  115. # Set a run log file that can be used to collect the output of commands that
  116. # are not displayed.
  117. set_run_log () {
  118. _RUN_LOG=$1
  119. }
  120. # Run a command. Output depends on $_VERBOSE:
  121. # $_VERBOSE <= 0: Run command, store output into the run log
  122. # $_VERBOSE >= 1: Dump command, run it, output goest to stdout
  123. # Note: Ideally, the command's output would go to the run log for $_VERBOSE >= 1
  124. # but the 'tee' tool doesn't preserve the status code of its input pipe
  125. # in case of error.
  126. run () {
  127. local LOGILE
  128. if [ "$_RUN_LOG" ]; then
  129. LOGFILE=$_RUN_LOG
  130. else
  131. LOGFILE=/dev/null
  132. fi
  133. if [ "$_VERBOSE" -ge 1 ]; then
  134. echo "COMMAND: $@"
  135. "$@"
  136. else
  137. "$@" >>$LOGFILE 2>&1
  138. fi
  139. }
  140. # Same as run(), but only dump command output for $_VERBOSE >= 2
  141. run2 () {
  142. local LOGILE
  143. if [ "$_RUN_LOG" ]; then
  144. LOGFILE=$_RUN_LOG
  145. else
  146. LOGFILE=/dev/null
  147. fi
  148. if [ "$_VERBOSE" -ge 1 ]; then
  149. echo "COMMAND: $@"
  150. fi
  151. if [ "$_VERBOSE" -ge 2 ]; then
  152. "$@"
  153. else
  154. "$@" >>$LOGFILE 2>&1
  155. fi
  156. }
  157. # Extract number of cores to speed up the builds
  158. # Out: number of CPU cores
  159. get_core_count () {
  160. case $(uname -s) in
  161. Linux)
  162. grep -c -e '^processor' /proc/cpuinfo
  163. ;;
  164. Darwin)
  165. sysctl -n hw.ncpu
  166. ;;
  167. CYGWIN*|*_NT-*)
  168. echo $NUMBER_OF_PROCESSORS
  169. ;;
  170. *)
  171. echo 1
  172. ;;
  173. esac
  174. }
  175. # Check for the Android ADB program.
  176. #
  177. # On success, return nothing, but updates internal variables so later calls to
  178. # adb_shell, adb_push, etc.. will work. You can get the path to the ADB program
  179. # with adb_get_program if needed.
  180. #
  181. # On failure, returns 1, and updates the internal adb error message, which can
  182. # be retrieved with adb_get_error.
  183. #
  184. # $1: optional ADB program path.
  185. # Return: success or failure.
  186. _ADB=
  187. _ADB_STATUS=
  188. _ADB_ERROR=
  189. adb_check () {
  190. # First, try to find the executable in the path, or the SDK install dir.
  191. _ADB=$1
  192. if [ -z "$_ADB" ]; then
  193. _ADB=$(which adb 2>/dev/null)
  194. if [ -z "$_ADB" -a "$ANDROID_SDK_ROOT" ]; then
  195. _ADB=$ANDROID_SDK_ROOT/platform-tools/adb
  196. if [ ! -f "$_ADB" ]; then
  197. _ADB=
  198. fi
  199. fi
  200. if [ -z "$_ADB" ]; then
  201. _ADB_STATUS=1
  202. _ADB_ERROR="The Android 'adb' tool is not in your path."
  203. return 1
  204. fi
  205. fi
  206. log "Found ADB program: $_ADB"
  207. # Check that it works correctly
  208. local ADB_VERSION
  209. ADB_VERSION=$("$_ADB" version 2>/dev/null)
  210. case $ADB_VERSION in
  211. "Android Debug Bridge "*) # Pass
  212. log "Found ADB version: $ADB_VERSION"
  213. ;;
  214. *) # Fail
  215. _ADB_ERROR="Your ADB binary reports a bad version ($ADB_VERSION): $_ADB"
  216. _ADB_STATUS=1
  217. return 1
  218. esac
  219. _ADB_STATUS=0
  220. return 0
  221. }
  222. # Return the path to the Android ADB program, if correctly detected.
  223. # On failure, return the empty string.
  224. # Out: ADB program path (or empty on failure)
  225. # Return: success or failure.
  226. adb_get_program () {
  227. # Return cached value as soon as possible.
  228. if [ -z "$_ADB_STATUS" ]; then
  229. adb_check $1
  230. fi
  231. echo "$_ADB"
  232. return $_ADB_STATUS
  233. }
  234. # Return the error corresponding to the last ADB function failure.
  235. adb_get_error () {
  236. echo "$_ADB_ERROR"
  237. }
  238. # Check that there is one device connected through ADB.
  239. # In case of failure, use adb_get_error to know why this failed.
  240. # $1: Optional adb program path
  241. # Return: success or failure.
  242. _ADB_DEVICE=
  243. _ADB_DEVICE_STATUS=
  244. adb_check_device () {
  245. if [ "$_ADB_DEVICE_STATUS" ]; then
  246. return $_ADB_DEVICE_STATUS
  247. fi
  248. # Check for ADB.
  249. if ! adb_check $1; then
  250. _ADB_DEVICE_STATUS=$_ADB_STATUS
  251. return 1
  252. fi
  253. local ADB_DEVICES NUM_DEVICES FINGERPRINT
  254. # Count the number of connected devices.
  255. ADB_DEVICES=$("$_ADB" devices 2>/dev/null | awk '$2 == "device" { print $1; }')
  256. NUM_DEVICES=$(echo "$ADB_DEVICES" | wc -l)
  257. case $NUM_DEVICES in
  258. 0)
  259. _ADB_ERROR="No Android device connected. Please connect one to your machine."
  260. _ADB_DEVICE_STATUS=1
  261. return 1
  262. ;;
  263. 1) # Pass
  264. # Ensure the same device will be called in later adb_shell calls.
  265. export ANDROID_SERIAL=$ADB_DEVICES
  266. ;;
  267. *) # 2 or more devices.
  268. if [ "$ANDROID_SERIAL" ]; then
  269. ADB_DEVICES=$ANDROID_SERIAL
  270. NUM_DEVICES=1
  271. else
  272. _ADB_ERROR="More than one Android device connected. \
  273. Please define ANDROID_SERIAL in your environment"
  274. _ADB_DEVICE_STATUS=1
  275. return 1
  276. fi
  277. ;;
  278. esac
  279. _ADB_DEVICE_STATUS=0
  280. _ADB_DEVICE=$ADB_DEVICES
  281. FINGERPRINT=$(adb_shell getprop ro.build.fingerprint)
  282. log "Using ADB device: $ANDROID_SERIAL ($FINGERPRINT)"
  283. return 0
  284. }
  285. # The 'adb shell' command is pretty hopeless, try to make sense of it by:
  286. # 1/ Removing trailing \r from line endings.
  287. # 2/ Ensuring the function returns the command's status code.
  288. #
  289. # $1+: Command
  290. # Out: command output (stdout + stderr combined)
  291. # Return: command exit status
  292. adb_shell () {
  293. local RET ADB_LOG
  294. # Check for ADB device.
  295. adb_check_device || return 1
  296. ADB_LOG=$(mktemp "${TMPDIR:-/tmp}/adb-XXXXXXXX")
  297. "$_ADB" shell "$@" ";" echo \$? > "$ADB_LOG" 2>&1
  298. sed -i -e 's![[:cntrl:]]!!g' "$ADB_LOG" # Remove \r.
  299. RET=$(sed -e '$!d' "$ADB_LOG") # Last line contains status code.
  300. sed -e '$d' "$ADB_LOG" # Print everything except last line.
  301. rm -f "$ADB_LOG"
  302. return $RET
  303. }
  304. # Push a file to a device.
  305. # $1: source file path
  306. # $2: device target file path
  307. # Return: success or failure.
  308. adb_push () {
  309. adb_check_device || return 1
  310. run "$_ADB" push "$1" "$2"
  311. }
  312. # Pull a file from a device
  313. # $1: device file path
  314. # $2: target host file path
  315. # Return: success or failure.
  316. adb_pull () {
  317. adb_check_device || return 1
  318. run "$_ADB" pull "$1" "$2"
  319. }
  320. # Same as adb_push, but will panic if the operations didn't succeed.
  321. adb_install () {
  322. adb_push "$@"
  323. fail_panic "Failed to install $1 to the Android device at $2"
  324. }