aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/objc
diff options
context:
space:
mode:
authorGravatar Googler <noreply@google.com>2016-07-07 20:04:34 +0000
committerGravatar Klaus Aehlig <aehlig@google.com>2016-07-08 08:43:39 +0000
commit4be7fdbf74d91acf54300678ced0aac3c878a3df (patch)
treea0d604b90e8c7e01441821f4d571cafe602c3723 /tools/objc
parent3348513de992b5a3ab7d22dea9ad265d288c93b6 (diff)
RELNOTES: use xcrun simctl instead of iossim to launch the app for "blaze run".
-- MOS_MIGRATED_REVID=126837234
Diffstat (limited to 'tools/objc')
-rw-r--r--tools/objc/ios_runner.sh.mac_template170
1 files changed, 157 insertions, 13 deletions
diff --git a/tools/objc/ios_runner.sh.mac_template b/tools/objc/ios_runner.sh.mac_template
index e5fb23d942..d7141dc9f1 100644
--- a/tools/objc/ios_runner.sh.mac_template
+++ b/tools/objc/ios_runner.sh.mac_template
@@ -14,31 +14,175 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-set -e
+# This script is to:
+# 1. create a new simulator by running "xcrun simctl create ..."
+# 2. launch the created simulator by passing the ID to the simulator app,
+# like: "/Applications/Xcode.app/Contents/Developer/Applications/Simulator.app/Contents/MacOS/Simulator" -CurrentDeviceUDID "B647C213-110F-4A6B-827D-BD25313C2D1F"
+# 3. install the target app on the created simulator by running
+# "xcrun simctl install ..."
+# 4. launch the target app on the created simulator by running
+# "xcrun simctl launch <device> <app identifier> <args>", and get its PID. We
+# pass in the env vars to the app by exporting the env vars adding the prefix
+# "SIMCTL_CHILD_" in the calling environment.
+# 5. check the app's PID periodically, exit the script when the app is not
+# running.
+# 6. when exit, will shutdown and delete the new created simulator.
+#
+# Note: the command "xcrun simctl launch ..." cannot return the app's output,
+# so we pass in the StdRedirect.dylib as an $DYLD_INSERT_LIBRARIES, which
+# could redirect the output to $GSTDERR and $GSTDOUT. Then we "tail -f" the
+# file with the redirected content to show it on the console.
+
+set -eu
if [[ "$(uname)" != Darwin ]]; then
echo "Cannot run iOS targets on a non-mac machine."
exit 1
fi
-# Note: SDK_VERSION and SIM_DEVICE might contain spaces, but they are already
+# Note: the sim_device and sdk_version might contain spaces, but they are already
# provided in quoted form in the template variables, so we should not quote them
# again here.
-readonly SDK_VERSION=%sdk_version%
-readonly SIM_DEVICE=%sim_device%
-readonly APP_DIR=$(mktemp -d -t extracted_app)
+TEST_DEVICE_ID=$(xcrun simctl create TestDevice %sim_device% %sdk_version%)
+
+function KillAllDevices() {
+ # Kill all running simulators.under Xcode 7+. The error message "No matching
+ # processes belonging to you were found" is expected when there's no running
+ # simulator.
+ pkill Simulator 2> /dev/null || true
+}
+
+# Kill the tail process (we redirect the app's output to a file and use tail to
+# stream the file) when the app is not running.
+# Default timeout is 600 secs. User could change it by running
+# "export TIME_OUT=<new_timeout_in_secs>" before invoking "blaze run" command.
+# $1: the PID of the app process
+# $2: the PID of the tail process
+function exit_when_app_not_running() {
+ local time_out=${TIME_OUT:-600}
+ local end_time=$(($(date +%s)+${time_out}))
+ while kill -0 "$1" &> /dev/null; do
+ if [[ $(date +%s) -gt $end_time ]]; then
+ break
+ fi
+ sleep 1
+ done
+ kill -9 "$2" &> /dev/null
+}
+
+# Wait until the given simualtor is booted.
+# $1: the simulator ID to boot
+function wait_for_sim_to_boot() {
+ i=0
+ while [ "${i}" -lt 10 ]; do
+ # The expected output of "xcrun simctl list" is like:
+ # -- iOS 8.4 --
+ # iPhone 5s (E946FA1C-26AB-465C-A7AC-24750D520BEA) (Shutdown)
+ # TestDevice (8491C4BC-B18E-4E2D-934A-54FA76365E48) (Booted)
+ # So if there's any booted simulator, $booted_device will not be empty.
+ local booted_device=$(xcrun simctl list devices | grep "$1" | grep "Booted" || true)
+ if [ -n "${booted_device}" ]; then
+ # Simulator is booted.
+ return
+ fi
+ sleep 1
+ i=$(($i+1))
+ done
+ echo "Failed to launch the simulator"
+ exit 1
+}
+
+# Clean up the given simulator.
+# $1: the simulator ID
+function CleanupSimulator() {
+ # Device may not have started up, so no guarantee shutdown is going to be good.
+ xcrun simctl shutdown "$1" 2> /dev/null || true
+ xcrun simctl delete "$1"
+}
+
+trap "CleanupSimulator ${TEST_DEVICE_ID}" EXIT
+
+readonly STD_REDIRECT_DYLIB="$PWD/%std_redirect_dylib_path%"
+
+readonly TEMP_DIR=$(mktemp -d -t bazel_temp)
+readonly APP_DIR="${TEMP_DIR}/extracted_app"
+mkdir "${APP_DIR}"
+
+KillAllDevices
+
+# Get the xcode version number, like: 6.4.
+# The expected output of "xcodebuild -version" is like:
+# Xcode 6.4
+# Build version 6E35b
+#
+# So the expected output of "xcodebuild -version|grep \"Xcode\"" is like:
+# Xcode 6.4
+#
+# awk will pull out the version number, e.g. "6.4".
+readonly XCODE_VERSION=$(xcodebuild -version | grep "Xcode" | awk '{ print $2 }')
+if [[ "${XCODE_VERSION}" == 6.* ]]; then
+ simulator_name="iOS Simulator"
+else
+ simulator_name="Simulator"
+fi
+
+# Get the developer path, like: /Applications/Xcode.app/Contents/Developer
+readonly DEVELOPER_PATH=$(xcode-select -p)
+
+# Launch the simulator.
+"${DEVELOPER_PATH}/Applications/${simulator_name}.app/Contents/MacOS/${simulator_name}" -CurrentDeviceUDID "${TEST_DEVICE_ID}" &
+wait_for_sim_to_boot "${TEST_DEVICE_ID}"
-args=()
-# Pass environment variables prefixed with IOS_ to the simulator, stripping
-# the prefix.
+# Pass environment variables prefixed with "IOS_" to the simulator, replace the
+# prefix with "SIMCTL_CHILD_". blaze/bazel adds "IOS_" to the env vars which
+# will be passed to the app as prefix to differentiate from other env vars. We
+# replace the prefix "IOS_" with "SIMCTL_CHILD_" here, because "simctl" only
+# pass the env vars prefixed with "SIMCTL_CHILD_" to the app.
+libs_to_insert="${STD_REDIRECT_DYLIB}"
while read -r envvar; do
if [[ "${envvar}" == IOS_* ]]; then
- args+=(-e "${envvar#IOS_}")
+ if [[ "${envvar}" == IOS_DYLD_INSERT_LIBRARIES=* ]]; then
+ libs_to_insert=SIMCTL_CHILD_"${envvar#IOS_}":"${libs_to_insert}"
+ else
+ export SIMCTL_CHILD_"${envvar#IOS_}"
+ fi
fi
done < <(env)
+export SIMCTL_CHILD_DYLD_INSERT_LIBRARIES="${libs_to_insert}"
+
+readonly RUN_LOG="${TEMP_DIR}/run.log"
+touch "${RUN_LOG}"
+export SIMCTL_CHILD_GSTDERR="${RUN_LOG}"
+export SIMCTL_CHILD_GSTDOUT="${RUN_LOG}"
unzip -qq '%ipa_file%' -d "${APP_DIR}"
-%iossim% -d "${SIM_DEVICE}" -s "${SDK_VERSION}" \
- "${args[@]}" \
- "${APP_DIR}/Payload/%app_name%.app" \
- "$@"
+
+xcrun simctl install "$TEST_DEVICE_ID" "${APP_DIR}/Payload/%app_name%.app"
+
+# Get the bundle ID of the app.
+readonly BUNDLE_INFO_PLIST="${APP_DIR}/Payload/%app_name%.app/Info.plist"
+readonly BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${BUNDLE_INFO_PLIST}")
+
+USER_NAME=${USER:-"$(logname)"}
+readonly SYSTEM_LOG="/Users/${USER_NAME}/Library/Logs/CoreSimulator/${TEST_DEVICE_ID}/system.log"
+rm -f "${SYSTEM_LOG}"
+
+# Launch the app. The expected output is:
+# <bundle name, e.g. example.PrenotCalculatorBinary>: <pid of the app process>
+IOS_PID=$(xcrun simctl launch "${TEST_DEVICE_ID}" "${BUNDLE_ID}" "$@")
+# The awk command will abstract the pid of the app process.
+IOS_PID=$(echo "${IOS_PID}" | awk '{ print $2 }')
+echo "Start the app ${BUNDLE_ID} on ${TEST_DEVICE_ID}."
+
+# Tail the file with the redirected outputs of the app.
+tail -f "${RUN_LOG}" &
+exit_when_app_not_running "${IOS_PID}" "$!"
+
+# Check the system.log to see if there was an abnormal exit.
+readonly ABNORMAL_EXIT_MSG=$(cat "${SYSTEM_LOG}" | \
+ grep "com.apple.CoreSimulator.SimDevice.${TEST_DEVICE_ID}.launchd_sim" | \
+ grep "Service exited with abnormal code")
+if [ -n "${ABNORMAL_EXIT_MSG}" ]; then
+ echo "The app exited abnormally: ${ABNORMAL_EXIT_MSG}"
+ exit 1
+fi