common-functions.sh 9.4 KB

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