crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

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})."