run-demo.sh (6518B)
1 #!/bin/bash 2 # Builds Crossmate and launches it with the `--crossmate-seed-demo` flag, which 3 # brings the app up against a throwaway in-memory store pre-filled with a couple 4 # of shared, in-progress games and a few crossmates. Lets you eyeball the Game 5 # List colour strips, the friends list, and the puzzle scoreboard without iCloud 6 # or a real opponent. The real on-disk store is untouched. 7 # 8 # Runs on a dedicated demo simulator — created on first run, reused thereafter — 9 # so it never collides with whatever device Xcode has open. iPhone and iPad each 10 # get their own demo device, so the two can coexist. 11 # 12 # Usage: bash Scripts/run-demo.sh [iOS-major] (iPhone, default major 26) 13 # bash Scripts/run-demo.sh --ipad [iOS-major] (iPad mini) 14 # bash Scripts/run-demo.sh [--ipad] --delete (remove the demo simulator) 15 # bash Scripts/run-demo.sh --v4-notice (also show the v4 reset notice) 16 set -euo pipefail 17 18 SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" 19 REPO_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" 20 source "${SCRIPT_DIR}/select-simulator.sh" 21 22 # Parse arguments in any order: --ipad picks the iPad demo device, --delete tears 23 # the resolved device down, and a bare number overrides the iOS major version. 24 DEVICE_KIND="iphone" 25 DELETE=false 26 MAJOR=26 27 SHOW_V4_NOTICE=false 28 for arg in "$@"; do 29 case "$arg" in 30 --ipad) DEVICE_KIND="ipad" ;; 31 --iphone) DEVICE_KIND="iphone" ;; 32 --delete) DELETE=true ;; 33 --v4-notice) SHOW_V4_NOTICE=true ;; 34 [0-9]*) MAJOR="$arg" ;; 35 *) echo "Unknown argument: $arg" >&2; exit 1 ;; 36 esac 37 done 38 39 if [ "$DEVICE_KIND" = "ipad" ]; then 40 DEMO_NAME="Crossmate Demo iPad" 41 else 42 DEMO_NAME="Crossmate Demo" 43 fi 44 BUNDLE_ID="net.inqk.crossmate" 45 # Keep the two demo products separate. Besides allowing iPhone and iPad builds 46 # to run independently, this avoids Xcode reusing a hollow folder-resource 47 # output from the other destination. 48 DERIVED_DATA="/tmp/crossmate-demo-${DEVICE_KIND}-derived" 49 50 # Look up the demo device (empty if it doesn't exist yet). `|| true` keeps a 51 # no-match grep (the expected first-run case) from tripping `set -o pipefail`. 52 UDID=$(xcrun simctl list devices \ 53 | grep -F "${DEMO_NAME} (" \ 54 | head -1 \ 55 | sed -E 's/.*\(([0-9A-Fa-f-]{36})\).*/\1/' || true) 56 57 # `--delete` tears the demo simulator down and exits. 58 if [ "$DELETE" = true ]; then 59 if [ -n "$UDID" ]; then 60 xcrun simctl shutdown "$UDID" 2>/dev/null || true 61 xcrun simctl delete "$UDID" 62 echo "Deleted '${DEMO_NAME}' (${UDID})." 63 else 64 echo "No '${DEMO_NAME}' simulator to delete." 65 fi 66 exit 0 67 fi 68 69 if [ -n "$UDID" ]; then 70 echo "Reusing '${DEMO_NAME}' (${UDID})" 71 else 72 # Create it on the newest available iOS <major> runtime. select_simulator picks 73 # the runtime (and an iPhone model); for iPad we swap in the newest iPad mini. 74 # Resolve the device type and runtime as CoreSimulator identifiers, which is 75 # what `simctl create` expects. 76 select_simulator "$MAJOR" 77 if [ "$DEVICE_KIND" = "ipad" ]; then 78 # Pick the newest iPad mini without trusting the list's order: tag each one 79 # with the first number in its name — the chip ("A17") or generation ("6th"), 80 # whichever the model uses — then sort numerically and take the largest. Chip 81 # numbers dwarf generation numbers, so chip-named models always win. 82 DEVICE_TYPE_LINE=$(xcrun simctl list devicetypes \ 83 | grep -F "iPad mini" \ 84 | sed -E 's/^iPad mini[^0-9]*([0-9]+).*/\1 &/' \ 85 | sort -rn -k1,1 \ 86 | head -1 \ 87 | cut -f2- || true) 88 else 89 DEVICE_TYPE_LINE=$(xcrun simctl list devicetypes \ 90 | grep -E "^${DEVICE} \(" \ 91 | head -1 || true) 92 fi 93 # The display name is the line minus its trailing "(com.apple…)" identifier; 94 # the identifier is that parenthesised tail. Parse both from the one line so 95 # iPad names that themselves contain parens — "iPad mini (A17 Pro)" — survive. 96 DEVICE=$(sed -E 's/ \(com\.apple[^)]*\)$//' <<<"$DEVICE_TYPE_LINE") 97 DEVICE_TYPE_ID=$(sed -E 's/.*\((com\.apple[^)]*)\)$/\1/' <<<"$DEVICE_TYPE_LINE") 98 RUNTIME_ID=$(xcrun simctl list runtimes available \ 99 | grep "iOS ${RUNTIME} (" \ 100 | head -1 \ 101 | sed -E 's/.* - (com\.apple[^ ]*).*/\1/' || true) 102 if [ -z "$DEVICE_TYPE_ID" ] || [ -z "$RUNTIME_ID" ]; then 103 echo "Couldn't resolve a device type / runtime to create '${DEMO_NAME}'." >&2 104 exit 1 105 fi 106 echo "Creating '${DEMO_NAME}' (${DEVICE}, iOS ${RUNTIME})" 107 UDID=$(xcrun simctl create "${DEMO_NAME}" "${DEVICE_TYPE_ID}" "${RUNTIME_ID}") 108 fi 109 110 # Bring the Simulator app forward, then boot the demo device into it. 111 open -a Simulator 112 xcrun simctl boot "$UDID" 2>/dev/null || true 113 xcrun simctl bootstatus "$UDID" -b 114 115 build_app() { 116 xcodebuild build \ 117 -scheme "Crossmate" \ 118 -project "${REPO_DIR}/Crossmate.xcodeproj" \ 119 -destination "id=${UDID}" \ 120 -derivedDataPath "$DERIVED_DATA" \ 121 2>&1 122 } 123 124 build_app 125 126 APP_PATH="${DERIVED_DATA}/Build/Products/Debug-iphonesimulator/Crossmate.app" 127 if [ ! -d "$APP_PATH" ]; then 128 echo "Built app not found at ${APP_PATH}" >&2 129 exit 1 130 fi 131 132 # Xcode's incremental build tracks the Puzzles folder reference as one output. 133 # If that output directory survives while its children disappear, it can report 134 # success without restoring them. The seed then silently skips every game 135 # because PuzzleCatalog has no manifest to read. Recover once with a clean build 136 # and refuse to launch if the required resource is still absent. 137 PUZZLE_MANIFEST="${APP_PATH}/Puzzles/cm-starter/manifest.json" 138 if [ ! -f "$PUZZLE_MANIFEST" ]; then 139 echo "Puzzle resources are missing from the cached build; rebuilding cleanly." 140 xcodebuild clean \ 141 -scheme "Crossmate" \ 142 -project "${REPO_DIR}/Crossmate.xcodeproj" \ 143 -destination "id=${UDID}" \ 144 -derivedDataPath "$DERIVED_DATA" \ 145 2>&1 146 build_app 147 fi 148 if [ ! -f "$PUZZLE_MANIFEST" ]; then 149 echo "Puzzle resources are missing from ${APP_PATH}; refusing to launch an empty demo." >&2 150 exit 1 151 fi 152 153 xcrun simctl install "$UDID" "$APP_PATH" 154 # `--v4-notice` appends the launch flag that pops the one-time v4 reset notice 155 # over the seeded library so it can be eyeballed. Empty otherwise. 156 V4_NOTICE_FLAG="" 157 if [ "$SHOW_V4_NOTICE" = true ]; then V4_NOTICE_FLAG="--crossmate-show-v4-notice"; fi 158 xcrun simctl launch --terminate-running-process "$UDID" "$BUNDLE_ID" \ 159 --crossmate-seed-demo $V4_NOTICE_FLAG 160 161 # Bring the Simulator back to the front now the app is up. 162 open -a Simulator 163 164 echo "" 165 echo "Launched ${BUNDLE_ID} with --crossmate-seed-demo on '${DEMO_NAME}' (${UDID})."