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