421b802467
- Corrected the backup path in the `_in_backup` function to reflect the new structure under `mackup/`. - Improved error handling in `ssr::mackup::configure` to skip restore if the configuration file is not updated, providing user feedback. - Updated `ssr::sync` to conditionally execute backup based on configuration validity, enhancing robustness. - Revised documentation in configuration examples to clarify the new Mackup directory structure and its implications for users.
161 lines
5.8 KiB
Bash
Executable File
161 lines
5.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ssr-restore — restore brew packages, mackup data, macOS defaults.
|
|
#
|
|
# Flags:
|
|
# --resume Skip steps already marked 'ok' in the previous run's state.
|
|
# -h|--help Show usage.
|
|
|
|
set -euo pipefail
|
|
SSR_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
# shellcheck source=../lib/common.sh
|
|
source "$SSR_ROOT/lib/common.sh"
|
|
# shellcheck source=../lib/cloud.sh
|
|
source "$SSR_ROOT/lib/cloud.sh"
|
|
# shellcheck source=../lib/brew.sh
|
|
source "$SSR_ROOT/lib/brew.sh"
|
|
# shellcheck source=../lib/mackup.sh
|
|
source "$SSR_ROOT/lib/mackup.sh"
|
|
# shellcheck source=../lib/macos.sh
|
|
source "$SSR_ROOT/lib/macos.sh"
|
|
# shellcheck source=../lib/macos-prefs.sh
|
|
source "$SSR_ROOT/lib/macos-prefs.sh"
|
|
# shellcheck source=../lib/restore-state.sh
|
|
source "$SSR_ROOT/lib/restore-state.sh"
|
|
# shellcheck source=../lib/icloud.sh
|
|
source "$SSR_ROOT/lib/icloud.sh"
|
|
# shellcheck source=../lib/shell.sh
|
|
source "$SSR_ROOT/lib/shell.sh"
|
|
# shellcheck source=../lib/installers.sh
|
|
source "$SSR_ROOT/lib/installers.sh"
|
|
|
|
ssr::require_macos
|
|
ssr::load_config
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: ssr restore [--resume] [BREWFILE]
|
|
|
|
Restores Homebrew packages, Mackup dotfiles and macOS settings.
|
|
|
|
--resume Skip steps already completed in a previous (aborted) run.
|
|
State is read from: \$SSR_STATE_DIR/restore-state
|
|
|
|
If BREWFILE is omitted, the latest cloud backup is used:
|
|
<cloud>/BACKUP/<host> - <uuid>/Brewfile
|
|
EOF
|
|
}
|
|
|
|
# --- Argument parsing --------------------------------------------------------
|
|
SSR_RESTORE_RESUME=false
|
|
BREWFILE_ARG=""
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--resume) SSR_RESTORE_RESUME=true; shift ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
-*) ssr::die "Unknown flag: $1" ;;
|
|
*) BREWFILE_ARG="$1"; shift ;;
|
|
esac
|
|
done
|
|
export SSR_RESTORE_RESUME
|
|
|
|
# --- Cloud + Brewfile --------------------------------------------------------
|
|
ssr::log "ssr restore starting${SSR_RESTORE_RESUME:+ (--resume mode)}"
|
|
|
|
_cloud_dir="$(ssr::cloud::resolve_dir 2>/dev/null)" || true
|
|
if [[ -z "$_cloud_dir" || ! -d "$_cloud_dir" ]]; then
|
|
ssr::warn "Cloud directory not yet accessible: ${_cloud_dir:-<unknown>}"
|
|
ssr::warn "Sign in to ${SSR_CLOUD_PROVIDER:-iCloud} and ensure the drive is mounted, then press Enter."
|
|
ssr::confirm "Cloud drive ready — proceed with restore?" 120 \
|
|
|| ssr::die "Aborted by user"
|
|
fi
|
|
|
|
ssr::cloud::ensure_available
|
|
backup_dir="$(ssr::cloud::backup_dir)"
|
|
mackup_dir="$(ssr::cloud::mackup_dir)"
|
|
|
|
brewfile="${BREWFILE_ARG:-$backup_dir/Brewfile}"
|
|
[[ -f "$brewfile" ]] || ssr::die "Brewfile not found: $brewfile"
|
|
ssr::log "Using Brewfile: $brewfile"
|
|
|
|
# Initialise state (archives previous state file if present).
|
|
ssr::rs::init "$brewfile"
|
|
|
|
# Trigger async iCloud prefetch for the Mackup folder as early as possible
|
|
# so files have time to download while brew bundle install runs.
|
|
ssr::icloud::prefetch "$mackup_dir"
|
|
|
|
# --- Step helpers ------------------------------------------------------------
|
|
|
|
# Groups mackup install + configure + restore into a single resumable step.
|
|
# ssr::mackup::restore already calls ssr::icloud::wait internally.
|
|
_ssr_mackup_restore_step() {
|
|
ssr::mackup::ensure_installed
|
|
ssr::mackup::configure "$mackup_dir" || {
|
|
ssr::warn "Skipping mackup restore — ~/.mackup.cfg was not updated (see messages above)."
|
|
return 1
|
|
}
|
|
ssr::mackup::restore
|
|
}
|
|
|
|
# --- Steps -------------------------------------------------------------------
|
|
|
|
ssr::rs::run brew_install "Homebrew install" ssr::brew::ensure_installed
|
|
ssr::rs::run brew_restore "Brew bundle install" ssr::brew::restore "$brewfile"
|
|
ssr::rs::run mackup_restore "Mackup restore" _ssr_mackup_restore_step
|
|
|
|
# Restart UI services so Dock/Finder/menubar pick up the plists restored
|
|
# by Mackup (com.apple.dock.plist etc.) without requiring a logout.
|
|
ssr::macos::restart_ui
|
|
|
|
# After dotfiles are in place, install any shell frameworks / version
|
|
# managers they reference that aren't already present (e.g. Oh My Zsh).
|
|
if [[ "${SSR_SHELL_DEPS_ENABLED:-true}" == "true" ]]; then
|
|
ssr::rs::run shell_deps "Shell framework deps" ssr::shell::detect_and_install
|
|
else
|
|
ssr::rs::set "step_shell_deps" "skipped"
|
|
fi
|
|
|
|
# Extra installers: DMG / PKG / ZIP not available via Homebrew or MAS.
|
|
# List file is backed up to <backup_dir>/extra-installers.txt by `ssr sync`.
|
|
_extra_installers_file="$backup_dir/extra-installers.txt"
|
|
if [[ -f "$_extra_installers_file" ]]; then
|
|
ssr::rs::run extra_installers "Extra installers" \
|
|
ssr::installers::install_from_file "$_extra_installers_file"
|
|
else
|
|
ssr::rs::set "step_extra_installers" "skipped"
|
|
fi
|
|
|
|
ssr::rs::run macos_defaults "macOS defaults" ssr::macos::apply_defaults
|
|
|
|
if [[ "${SSR_SNAPSHOT_MACOS_PREFS:-true}" == "true" ]]; then
|
|
ssr::rs::run prefs_import "Prefs snapshot import" ssr::macos::prefs_import "$backup_dir"
|
|
else
|
|
ssr::rs::set "step_prefs_import" "skipped"
|
|
fi
|
|
|
|
# Optional: open installed cask apps for first-run config (not tracked as a
|
|
# resumable step — it's side-effect-only and always safe to re-run).
|
|
ssr::macos::open_installed_casks
|
|
|
|
# --- User-defined post-restore hook --------------------------------------
|
|
# Sources ~/.config/ssr/post-restore.sh when present.
|
|
# Copy config/post-restore.sh.example from the repo as a starting point.
|
|
_user_hook="${SSR_CONFIG_DIR:-$HOME/.config/ssr}/post-restore.sh"
|
|
if [[ -f "$_user_hook" ]]; then
|
|
ssr::log "Running post-restore hook: $_user_hook"
|
|
# shellcheck source=/dev/null
|
|
source "$_user_hook" \
|
|
&& ssr::ok "post-restore hook completed" \
|
|
|| ssr::warn "post-restore hook exited with errors (non-fatal)"
|
|
else
|
|
ssr::log "No post-restore hook found (optional: $_user_hook)"
|
|
fi
|
|
|
|
# Mark overall completion time.
|
|
ssr::rs::set "finished" "$(ssr::ts)"
|
|
|
|
# --- Final report ------------------------------------------------------------
|
|
ssr::rs::report
|
|
|
|
ssr::ok "ssr restore completed"
|