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 30 # Collection of common shell functions for 'run-checks.sh' et 'test-shell.sh' 31 32 # All internal variables and functions use an underscore as a prefix 33 # (e.g. _VERBOSE, _ALL_CLEANUPS, etc..). 34 35 # Sanitize the environment 36 export LANG=C 37 export LC_ALL=C 38 39 if [ "$BASH_VERSION" ]; then 40 set -o posix 41 fi 42 43 # Utility functions 44 45 _ALL_CLEANUPS= 46 47 # Register a function to be called when the script exits, even in case of 48 # Ctrl-C, logout, etc. 49 # $1: function name. 50 atexit () { 51 if [ -z "$_ALL_CLEANUPS" ]; then 52 _ALL_CLEANUPS=$1 53 # Ensure a clean exit when the script is: 54 # - Exiting normally (EXIT) 55 # - Interrupted by Ctrl-C (INT) 56 # - Interrupted by log out (HUP) 57 # - Being asked to quit nicely (TERM) 58 # - Being asked to quit and dump core (QUIT) 59 trap "_exit_cleanups \$?" EXIT INT HUP QUIT TERM 60 else 61 _ALL_CLEANUPS="$_ALL_CLEANUPS $1" 62 fi 63 } 64 65 # Called on exit if at least one function was registered with atexit 66 # $1: final exit status code 67 _exit_cleanups () { 68 local CLEANUP CLEANUPS 69 # Ignore calls to atexit during cleanups 70 CLEANUPS=$_ALL_CLEANUPS 71 _ALL_CLEANUPS= 72 for CLEANUP in $CLEANUPS; do 73 ($CLEANUP) 74 done 75 exit "$@" 76 } 77 78 79 80 81 # Dump a panic message then exit. 82 # $1+: message 83 panic () { 84 echo "ERROR: $@" >&2 85 exit 1 86 } 87 88 # If the previous command failed, dump a panic message then exit. 89 # $1+: message. 90 fail_panic () { 91 if [ $? != 0 ]; then 92 panic "$@" 93 fi; 94 } 95 96 _VERBOSE=0 97 98 # Increase verbosity for dump/log/run/run2 functions 99 increase_verbosity () { 100 _VERBOSE=$(( $_VERBOSE + 1 )) 101 } 102 103 # Decrease verbosity 104 decrease_verbosity () { 105 _VERBOSE=$(( $_VERBOSE - 1 )) 106 } 107 108 # Returns success iff verbosity level is higher than a specific value 109 # $1: verbosity level 110 verbosity_is_higher_than () { 111 [ "$_VERBOSE" -gt "$1" ] 112 } 113 114 # Returns success iff verbosity level is lower than a specific value 115 # $1: verbosity level 116 verbosity_is_lower_than () { 117 [ "$_VERBOSE" -le "$1" ] 118 } 119 120 # Dump message to stdout, unless verbosity is < 0, i.e. --quiet was called 121 # $1+: message 122 dump () { 123 if [ "$_VERBOSE" -ge 0 ]; then 124 printf "%s\n" "$*" 125 fi 126 } 127 128 # If --verbose was used, dump a message to stdout. 129 # $1+: message 130 log () { 131 if [ "$_VERBOSE" -ge 1 ]; then 132 printf "%s\n" "$*" 133 fi 134 } 135 136 _RUN_LOG= 137 138 # Set a run log file that can be used to collect the output of commands that 139 # are not displayed. 140 set_run_log () { 141 _RUN_LOG=$1 142 } 143 144 # Run a command. Output depends on $_VERBOSE: 145 # $_VERBOSE <= 0: Run command, store output into the run log 146 # $_VERBOSE >= 1: Dump command, run it, output goest to stdout 147 # Note: Ideally, the command's output would go to the run log for $_VERBOSE >= 1 148 # but the 'tee' tool doesn't preserve the status code of its input pipe 149 # in case of error. 150 run () { 151 local LOGILE 152 if [ "$_RUN_LOG" ]; then 153 LOGFILE=$_RUN_LOG 154 else 155 LOGFILE=/dev/null 156 fi 157 158 if [ "$_VERBOSE" -ge 1 ]; then 159 echo "COMMAND: $@" 160 "$@" 161 else 162 "$@" >>$LOGFILE 2>&1 163 fi 164 } 165 166 # Same as run(), but only dump command output for $_VERBOSE >= 2 167 run2 () { 168 local LOGILE 169 if [ "$_RUN_LOG" ]; then 170 LOGFILE=$_RUN_LOG 171 else 172 LOGFILE=/dev/null 173 fi 174 175 if [ "$_VERBOSE" -ge 1 ]; then 176 echo "COMMAND: $@" 177 fi 178 if [ "$_VERBOSE" -ge 2 ]; then 179 "$@" 180 else 181 "$@" >>$LOGFILE 2>&1 182 fi 183 } 184 185 # Extract number of cores to speed up the builds 186 # Out: number of CPU cores 187 get_core_count () { 188 case $(uname -s) in 189 Linux) 190 grep -c -e '^processor' /proc/cpuinfo 191 ;; 192 Darwin) 193 sysctl -n hw.ncpu 194 ;; 195 CYGWIN*|*_NT-*) 196 echo $NUMBER_OF_PROCESSORS 197 ;; 198 *) 199 echo 1 200 ;; 201 esac 202 } 203 204 205 # Check for the Android ADB program. 206 # 207 # On success, return nothing, but updates internal variables so later calls to 208 # adb_shell, adb_push, etc.. will work. You can get the path to the ADB program 209 # with adb_get_program if needed. 210 # 211 # On failure, returns 1, and updates the internal adb error message, which can 212 # be retrieved with adb_get_error. 213 # 214 # $1: optional ADB program path. 215 # Return: success or failure. 216 _ADB= 217 _ADB_STATUS= 218 _ADB_ERROR= 219 220 adb_check () { 221 # First, try to find the executable in the path, or the SDK install dir. 222 _ADB=$1 223 if [ -z "$_ADB" ]; then 224 _ADB=$(which adb 2>/dev/null) 225 if [ -z "$_ADB" -a "$ANDROID_SDK_ROOT" ]; then 226 _ADB=$ANDROID_SDK_ROOT/platform-tools/adb 227 if [ ! -f "$_ADB" ]; then 228 _ADB= 229 fi 230 fi 231 if [ -z "$_ADB" ]; then 232 _ADB_STATUS=1 233 _ADB_ERROR="The Android 'adb' tool is not in your path." 234 return 1 235 fi 236 fi 237 238 log "Found ADB program: $_ADB" 239 240 # Check that it works correctly 241 local ADB_VERSION 242 ADB_VERSION=$("$_ADB" version 2>/dev/null) 243 case $ADB_VERSION in 244 "Android Debug Bridge "*) # Pass 245 log "Found ADB version: $ADB_VERSION" 246 ;; 247 *) # Fail 248 _ADB_ERROR="Your ADB binary reports a bad version ($ADB_VERSION): $_ADB" 249 _ADB_STATUS=1 250 return 1 251 esac 252 253 _ADB_STATUS=0 254 return 0 255 } 256 257 258 # Return the path to the Android ADB program, if correctly detected. 259 # On failure, return the empty string. 260 # Out: ADB program path (or empty on failure) 261 # Return: success or failure. 262 adb_get_program () { 263 # Return cached value as soon as possible. 264 if [ -z "$_ADB_STATUS" ]; then 265 adb_check $1 266 fi 267 echo "$_ADB" 268 return $_ADB_STATUS 269 } 270 271 # Return the error corresponding to the last ADB function failure. 272 adb_get_error () { 273 echo "$_ADB_ERROR" 274 } 275 276 # Check that there is one device connected through ADB. 277 # In case of failure, use adb_get_error to know why this failed. 278 # $1: Optional adb program path 279 # Return: success or failure. 280 _ADB_DEVICE= 281 _ADB_DEVICE_STATUS= 282 adb_check_device () { 283 if [ "$_ADB_DEVICE_STATUS" ]; then 284 return $_ADB_DEVICE_STATUS 285 fi 286 287 # Check for ADB. 288 if ! adb_check $1; then 289 _ADB_DEVICE_STATUS=$_ADB_STATUS 290 return 1 291 fi 292 293 local ADB_DEVICES NUM_DEVICES FINGERPRINT 294 295 # Count the number of connected devices. 296 ADB_DEVICES=$("$_ADB" devices 2>/dev/null | awk '$2 == "device" { print $1; }') 297 NUM_DEVICES=$(echo "$ADB_DEVICES" | wc -l) 298 case $NUM_DEVICES in 299 0) 300 _ADB_ERROR="No Android device connected. Please connect one to your machine." 301 _ADB_DEVICE_STATUS=1 302 return 1 303 ;; 304 1) # Pass 305 # Ensure the same device will be called in later adb_shell calls. 306 export ANDROID_SERIAL=$ADB_DEVICES 307 ;; 308 *) # 2 or more devices. 309 if [ "$ANDROID_SERIAL" ]; then 310 ADB_DEVICES=$ANDROID_SERIAL 311 NUM_DEVICES=1 312 else 313 _ADB_ERROR="More than one Android device connected. \ 314 Please define ANDROID_SERIAL in your environment" 315 _ADB_DEVICE_STATUS=1 316 return 1 317 fi 318 ;; 319 esac 320 321 _ADB_DEVICE_STATUS=0 322 _ADB_DEVICE=$ADB_DEVICES 323 324 FINGERPRINT=$(adb_shell getprop ro.build.fingerprint) 325 log "Using ADB device: $ANDROID_SERIAL ($FINGERPRINT)" 326 return 0 327 } 328 329 # The 'adb shell' command is pretty hopeless, try to make sense of it by: 330 # 1/ Removing trailing \r from line endings. 331 # 2/ Ensuring the function returns the command's status code. 332 # 333 # $1+: Command 334 # Out: command output (stdout + stderr combined) 335 # Return: command exit status 336 adb_shell () { 337 local RET ADB_LOG 338 # Check for ADB device. 339 adb_check_device || return 1 340 ADB_LOG=$(mktemp "${TMPDIR:-/tmp}/adb-XXXXXXXX") 341 "$_ADB" shell "$@" ";" echo \$? > "$ADB_LOG" 2>&1 342 sed -i -e 's![[:cntrl:]]!!g' "$ADB_LOG" # Remove \r. 343 RET=$(sed -e '$!d' "$ADB_LOG") # Last line contains status code. 344 sed -e '$d' "$ADB_LOG" # Print everything except last line. 345 rm -f "$ADB_LOG" 346 return $RET 347 } 348 349 # Push a file to a device. 350 # $1: source file path 351 # $2: device target file path 352 # Return: success or failure. 353 adb_push () { 354 adb_check_device || return 1 355 run "$_ADB" push "$1" "$2" 356 } 357 358 # Pull a file from a device 359 # $1: device file path 360 # $2: target host file path 361 # Return: success or failure. 362 adb_pull () { 363 adb_check_device || return 1 364 run "$_ADB" pull "$1" "$2" 365 } 366 367 # Same as adb_push, but will panic if the operations didn't succeed. 368 adb_install () { 369 adb_push "$@" 370 fail_panic "Failed to install $1 to the Android device at $2" 371 } 372 373