#!/bin/bash set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" source "$ROOT/scripts/common.sh" DEVICE="${TARNAX_DEVICE:-}" IPA='' APP='' LAUNCH=YES LIST=NO while (($#)); do case "$1" in --device|--ipa|--app) [[ $# -ge 2 ]] || { echo "$1 needs a value" >&2; exit 2; } case "$1" in --device) DEVICE="$2" ;; --ipa) IPA="$2" ;; --app) APP="$2" ;; esac shift ;; --no-launch) LAUNCH=NO ;; --list) LIST=YES ;; -h|--help) echo 'Usage: scripts/deploy.sh [--device ID_OR_NAME] [--ipa FILE | --app BUNDLE] [--no-launch]' echo ' scripts/deploy.sh --list' echo 'Default: build signed Release, install on the single paired physical iPhone and launch.' exit 0 ;; *) echo "Unknown option: $1" >&2; exit 2 ;; esac shift done [[ -z "$IPA" || -z "$APP" ]] || { echo 'Choose --ipa or --app, not both.' >&2; exit 2; } if [[ "$LIST" == YES ]]; then exec xcrun devicectl list devices; fi SCRATCH="$(mktemp -d "$TARNAX_SCRATCH_ROOT/deploy.XXXXXX")" trap 'rm -rf "$SCRATCH"' EXIT xcrun devicectl list devices --json-output "$SCRATCH/devices.json" >/dev/null SELECTION="$(python3 - "$SCRATCH/devices.json" "$DEVICE" <<'PY' import json,sys with open(sys.argv[1]) as f:devices=json.load(f)['result']['devices'] requested=sys.argv[2] candidates=[] for d in devices: p=d.get('properties',{}) h=p.get('hardware',d.get('hardwareProperties',{})) c=p.get('connection',d.get('connectionProperties',{})) state=p.get('state',d.get('deviceProperties',{})) if h.get('reality')!='physical' or h.get('deviceType')!='iPhone':continue if c.get('pairingState')!='paired':continue identifiers=[d.get('identifier'),h.get('udid'),state.get('name')] if requested and requested not in identifiers:continue candidates.append((d['identifier'],h['udid'])) if len(candidates)!=1: sys.exit('Select one paired physical iPhone with --device. Run scripts/deploy.sh --list; connect, unlock and trust your iPhone in Xcode if needed.') print('\t'.join(candidates[0])) PY )" IFS=$'\t' read -r DEVICE_ID DEVICE_UDID <<< "$SELECTION" if [[ -n "$IPA" ]]; then [[ -f "$IPA" ]] || { echo "IPA not found: $IPA" >&2; exit 1; } unzip -q "$IPA" -d "$SCRATCH/unpacked" APP="$SCRATCH/unpacked/Payload/Tarnax.app" elif [[ -z "$APP" ]]; then BUILD_OUTPUT_DIR="$ROOT/build/Deploy" bash "$ROOT/scripts/build.sh" --release --signed APP="$ROOT/build/Deploy/Tarnax.app" fi [[ -d "$APP" ]] || { echo "App bundle not found: $APP" >&2; exit 1; } codesign --verify --deep --strict "$APP" security cms -D -i "$APP/embedded.mobileprovision" > "$SCRATCH/profile.plist" python3 "$ROOT/scripts/verify_profile.py" "$APP/Info.plist" "$SCRATCH/profile.plist" --device "$DEVICE_UDID" xcrun devicectl device install app --device "$DEVICE_ID" "$APP" --timeout 120 echo 'Tarnax installed successfully.' if [[ "$LAUNCH" == YES ]]; then if ! xcrun devicectl device process launch --device "$DEVICE_ID" --terminate-existing net.absdev.Tarnax --timeout 60; then echo 'Installation succeeded, but launch failed. Unlock your iPhone and open Tarnax, or rerun with --no-launch.' >&2 exit 1 fi fi