#!/usr/bin/env bash # Bootstrap a fresh Mac from nothing. # curl -fsSL bootstrap.azohra.com | bash # # Published by seed/worker via `just seed`. World-readable by design. # Overrides: CONFIG_REPO (default azohra/config), CONFIG_DEST (default ~/Development/config) set -euo pipefail REPO="${CONFIG_REPO:-azohra/config}" DEST="${CONFIG_DEST:-$HOME/Development/config}" say() { printf '\n\033[1m==> %s\033[0m\n' "$1"; } die() { printf '\033[31merror:\033[0m %s\n' "$1" >&2 exit 1 } [[ $(uname -s) == Darwin ]] || die "This script is for macOS." # Xcode CLT — provides git if xcode-select -p &>/dev/null; then say "Xcode Command Line Tools already installed" else say "Installing Xcode Command Line Tools (accept the GUI prompt)" xcode-select --install || true until xcode-select -p &>/dev/null; do sleep 5; done fi # Homebrew if ! command -v brew &>/dev/null; then say "Installing Homebrew" NONINTERACTIVE=1 /bin/bash -c \ "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" fi for candidate in /opt/homebrew/bin/brew /usr/local/bin/brew; do [[ -x $candidate ]] && eval "$("$candidate" shellenv)" && break done command -v brew &>/dev/null || die "Homebrew installed but 'brew' is not on PATH." # gh if ! command -v gh &>/dev/null; then say "Installing GitHub CLI" brew install gh fi # Auth. Piped into bash, stdin is the pipe, not the terminal — an interactive # prompt would read EOF and fail, so reconnect to /dev/tty when possible. if gh auth status &>/dev/null; then say "Already authenticated with GitHub" else say "Authenticating with GitHub (a browser will open; type the code shown)" if [[ -t 0 ]]; then gh auth login --hostname github.com --git-protocol https --web elif [[ -e /dev/tty ]]; then gh auth login --hostname github.com --git-protocol https --web /dev/null || die "GitHub authentication did not complete." fi # HTTPS, not SSH: no key exists yet — 1Password is installed later by phase 1. # Testing for .git is not enough; an interrupted clone leaves one behind. if git -C "$DEST" rev-parse --is-inside-work-tree &>/dev/null; then origin_url=$(git -C "$DEST" remote get-url origin 2>/dev/null || true) case "$origin_url" in *"$REPO"*) say "$REPO already cloned at $DEST" ;; *) die "$DEST is a clone of ${origin_url:-no remote}, not $REPO. Move it aside, or set CONFIG_DEST." ;; esac elif [[ -n $(ls -A "$DEST" 2>/dev/null) ]]; then die "$DEST exists and is not a usable clone. Remove it and re-run: rm -rf \"$DEST\"" else say "Cloning $REPO into $DEST" mkdir -p "$(dirname "$DEST")" gh repo clone "$REPO" "$DEST" -- --config credential.helper='!gh auth git-credential' || die "Could not clone $REPO. Check the account has access." fi [[ -x $DEST/bootstrap.sh ]] || die "$DEST/bootstrap.sh missing — incomplete checkout." say "Handing off to $REPO" exec "$DEST/bootstrap.sh"