#!/bin/sh # mac.sh - fresh-Mac bootstrap for 759705.cc # # Purpose : Get a new Mac to a usable baseline - Xcode Command Line Tools, # Homebrew, and a short list of everyday CLI tools. # Usage : curl -fsSL https://759705.cc/mac.sh | sh # Idempotent: yes. Every step checks whether it is already done and skips it, # so running this on an existing machine changes nothing. # Dry run : HUB_DRY_RUN=1 prints each command instead of running it. # HUB_DRY_RUN=1 sh mac.sh # Local test: HUB_BASE overrides the base URL used in printed links. # # Installs only; never uninstalls, never deletes, never edits dotfiles. # Contains no secrets and no internal hostnames; safe to serve publicly. set -eu # --------------------------------------------------------------------------- # Edit this ONE line to change which Homebrew formulae get installed. HUB_BREW_FORMULAE="git jq ripgrep fd tree" # --------------------------------------------------------------------------- HUB_BASE="${HUB_BASE:-https://759705.cc}" HUB_DRY_RUN="${HUB_DRY_RUN:-0}" log() { printf '==> %s\n' "$*"; } ok() { printf 'ok %s\n' "$*"; } note() { printf ' %s\n' "$*"; } warn() { printf '!! %s\n' "$*" >&2; } # run - execute it, or print it when HUB_DRY_RUN=1. run() { if [ "$HUB_DRY_RUN" = "1" ]; then printf 'DRY %s\n' "$*" else log "$*" sh -c "$*" fi } # Summary counters, printed at the end. HUB_CHANGED=0 HUB_PENDING="" step_xcode_clt() { log "Step 1/3 - Xcode Command Line Tools" if xcode-select -p >/dev/null 2>&1; then ok "already installed at $(xcode-select -p)" return 0 fi run "xcode-select --install" HUB_CHANGED=$((HUB_CHANGED + 1)) if [ "$HUB_DRY_RUN" = "1" ]; then note "(dry run) the installer window would open here" return 0 fi note "A macOS installer window has opened." note "Wait for it to finish, then re-run this script to continue:" note " curl -fsSL ${HUB_BASE}/mac.sh | sh" HUB_PENDING="xcode-clt" return 0 } step_homebrew() { log "Step 2/3 - Homebrew" if command -v brew >/dev/null 2>&1; then ok "already installed - $(brew --version 2>/dev/null | head -n 1)" return 0 fi brew_cmd='/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' if [ ! -t 0 ]; then # This script was piped into `sh`, so stdin is not a terminal and the # Homebrew installer cannot prompt for confirmation. Tell it not to. brew_cmd="NONINTERACTIVE=1 ${brew_cmd}" fi run "$brew_cmd" HUB_CHANGED=$((HUB_CHANGED + 1)) if [ "$HUB_DRY_RUN" = "1" ]; then printf 'DRY eval "$(/opt/homebrew/bin/brew shellenv)" # Apple Silicon\n' return 0 fi # Put brew on PATH for the rest of THIS run. for candidate in /opt/homebrew/bin/brew /usr/local/bin/brew; do if [ -x "$candidate" ]; then eval "$("$candidate" shellenv)" note "Add this to ~/.zprofile so brew stays on PATH in new shells:" note " echo 'eval \"\$(${candidate} shellenv)\"' >> ~/.zprofile" break fi done if ! command -v brew >/dev/null 2>&1; then warn "Homebrew installed but 'brew' is still not on PATH. Open a new shell and re-run." HUB_PENDING="homebrew-path" fi return 0 } step_formulae() { log "Step 3/3 - default formulae: ${HUB_BREW_FORMULAE}" if ! command -v brew >/dev/null 2>&1; then if [ "$HUB_DRY_RUN" = "1" ]; then printf 'DRY brew install %s\n' "$HUB_BREW_FORMULAE" note "(dry run) brew is not on PATH here, so nothing could be compared" return 0 fi warn "Skipping: brew is not available yet. Re-run after step 2 completes." HUB_PENDING="formulae" return 0 fi installed="$(brew list --formula 2>/dev/null || true)" missing="" for formula in $HUB_BREW_FORMULAE; do if printf '%s\n' "$installed" | grep -qx "$formula"; then ok "${formula} already installed" else missing="${missing} ${formula}" fi done if [ -z "$missing" ]; then ok "nothing to install" return 0 fi run "brew install${missing}" HUB_CHANGED=$((HUB_CHANGED + 1)) return 0 } summary() { printf '\n' log "Summary" if [ "$HUB_DRY_RUN" = "1" ]; then note "Dry run - nothing was installed or modified." elif [ "$HUB_CHANGED" -eq 0 ]; then note "Everything was already in place. No changes made." else note "${HUB_CHANGED} step(s) made changes." fi if [ -n "$HUB_PENDING" ]; then note "Unfinished: ${HUB_PENDING}. Re-run this script once it is resolved." fi note "Cheatsheet: ${HUB_BASE}/commands/mac/" } main() { log "hub mac bootstrap - $(sw_vers -productVersion 2>/dev/null || echo 'macOS')" if [ "$HUB_DRY_RUN" = "1" ]; then note "DRY RUN: commands are printed, not executed." fi printf '\n' step_xcode_clt printf '\n' step_homebrew printf '\n' step_formulae summary } main "$@"