• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
36export LANG=C
37export LC_ALL=C
38
39if [ "$BASH_VERSION" ]; then
40  set -o posix
41fi
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.
50atexit () {
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
83panic () {
84  echo "ERROR: $@" >&2
85  exit 1
86}
87
88# If the previous command failed, dump a panic message then exit.
89# $1+: message.
90fail_panic () {
91  if [ $? != 0 ]; then
92    panic "$@"
93  fi;
94}
95
96_VERBOSE=0
97
98# Increase verbosity for dump/log/run/run2 functions
99increase_verbosity () {
100  _VERBOSE=$(( $_VERBOSE + 1 ))
101}
102
103# Decrease verbosity
104decrease_verbosity () {
105  _VERBOSE=$(( $_VERBOSE - 1 ))
106}
107
108# Returns success iff verbosity level is higher than a specific value
109# $1: verbosity level
110verbosity_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
116verbosity_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
122dump () {
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
130log () {
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.
140set_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.
150run () {
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
167run2 () {
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
187get_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
220adb_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.
262adb_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.
272adb_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=
282adb_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. \
314Please 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
336adb_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.
353adb_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.
362adb_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.
368adb_install () {
369  adb_push "$@"
370  fail_panic "Failed to install $1 to the Android device at $2"
371}
372
373