From 7dabcdd71e2f27bbbcbf3963ba3e878062e7cce0 Mon Sep 17 00:00:00 2001 From: "Oliver Surke (Gitea)" Date: Wed, 13 May 2026 20:11:41 +0200 Subject: [PATCH] Update README for clarity and structure - Revised the introduction to emphasize the workflow of the `ssr` tool. - Reformatted the backup and restore commands into a table for better readability. - Enhanced the documentation on installation and configuration steps. - Clarified the requirements section and streamlined the installation instructions. - Added a quick reference section for CLI commands to improve user accessibility. --- README.md | 338 +++++++----------------------------------------------- 1 file changed, 40 insertions(+), 298 deletions(-) diff --git a/README.md b/README.md index 97813e1..a5b0371 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,25 @@ # ssr — System Sync & Restore for macOS -Reproducible macOS setup in one command. `ssr` snapshots your Homebrew bundle and application configs to a cloud drive on a schedule, and can rebuild a fresh Mac from that snapshot. +Reproducible macOS setup in one workflow: snapshot your Homebrew bundle and application configs to a cloud drive on a schedule, then rebuild a fresh Mac from that snapshot. -- **Backup** (`ssr sync`): dumps `Brewfile` and runs `mackup backup` to the configured cloud directory (copy-based; no symlinks). -- **Restore** (`ssr restore`): installs Homebrew, replays the `Brewfile`, runs `mackup restore`, applies macOS defaults. -- **Legacy Mackup symlinks**: if a previous install used `mackup link`, run `ssr mackup unlink` once before relying on copy-based sync. -- **Scheduled sync**: native macOS `launchd` agent (daily by default). -- **Cloud storage**: iCloud Drive, Dropbox, Google Drive, OneDrive, or any custom path — selectable via config. -- **No secrets**: all state lives in your cloud drive; the repo only contains code and config templates. +| Action | Command | +|--------|---------| +| Backup | `ssr sync` — Brewfile + Mackup copy to cloud (no symlinks by default) | +| Restore | `ssr restore` — Homebrew, Brewfile, Mackup, macOS defaults | +| Schedule | `ssr schedule on` — daily `launchd` job | +| Legacy Mackup symlinks | Run `ssr mackup unlink` once if you previously used `mackup link` | -> Successor to the original `system_sync.sh` / `system_restore.sh`. Same intent, modernized tooling, modular, idempotent, scheduled by default. +**Full documentation (configuration tables, pref snapshots, logs, security, migration):** +**[Wiki → https://git.surke.de/osurke/system-sync-restore/wiki](https://git.surke.de/osurke/system-sync-restore/wiki)** + +> Successor to `system_sync.sh` / `system_restore.sh`. Same intent, modernized modular tooling. --- ## Requirements -- macOS (Apple Silicon or Intel) -- Bash 3.2+ (preinstalled) -- Network access for the initial Homebrew install -- A cloud drive folder you control (iCloud Drive is the default) +- macOS (Apple Silicon or Intel), Bash 3.2+, network for Homebrew bootstrap +- A cloud folder you control (iCloud is the default provider) --- @@ -30,13 +31,7 @@ cd ~/.ssr ./install.sh ``` -`install.sh` will: - -1. Symlink `bin/ssr` into `~/.local/bin` (override with `SSR_PREFIX`). -2. Seed `~/.config/ssr/ssr.conf` from `config/ssr.conf.example` (chmod 600). -3. Optionally enable the scheduled daily sync. - -If `~/.local/bin` is not on your `PATH`, add it to your shell rc: +Symlinks `ssr` into `~/.local/bin` (override with `SSR_PREFIX`), seeds `~/.config/ssr/ssr.conf`, optionally enables daily sync. If `~/.local/bin` is not on `PATH`: ```bash export PATH="$HOME/.local/bin:$PATH" @@ -44,302 +39,49 @@ export PATH="$HOME/.local/bin:$PATH" --- -## Usage +## CLI (quick reference) ```text -ssr install First-time install: link binary, seed config, schedule sync -ssr sync One-shot backup → cloud -ssr restore [Brewfile] Restore the machine; Brewfile defaults to the cloud copy -ssr update [--dry-run] Pull latest ssr code, refresh launchd if needed -ssr schedule on|off Enable/disable the daily launchd job -ssr config show|edit Show or edit the active config -ssr completions install Install zsh/bash/fish tab-completion -ssr status Show config, cloud target, last sync, schedule state -ssr version Print version +ssr install Link binary, seed config, optional schedule +ssr sync Backup → cloud +ssr restore [Brewfile] Restore; Brewfile defaults to cloud copy +ssr update [--dry-run] Git pull + launchd refresh when needed +ssr schedule on|off Daily launchd job +ssr config show|edit Config file +ssr completions install zsh / bash / fish +ssr status Summary +ssr version ``` -### First backup - -```bash -ssr sync -``` - -Output structure in the cloud drive: - -``` -/ -├── BACKUP/ -│ └── - / -│ ├── Brewfile -│ ├── Brewfile.bak -│ ├── unmanaged-apps.md # apps installed manually (not brew/MAS) -│ └── macos-prefs/ # pref-domain snapshots -│ ├── com.apple.dock.plist -│ ├── com.apple.finder.plist -│ └── … -└── Mackup/ - └── … (managed by mackup) -``` - -During each sync the unmanaged-apps scan compares every `.app` bundle in `/Applications` (and `~/Applications`) against: - -1. **Mac App Store** — bundle contains `Contents/_MASReceipt/receipt` -2. **Homebrew Cask** — bundle filename matches the `.app` artifact of any installed cask - -Anything not matched is written to `unmanaged-apps.md` (Markdown table, one row per app, with version, bundle id and a best-effort installer link) and printed to the sync log as a warning. Disable with `SSR_SCAN_UNMANAGED_APPS=false`. - -Link selection for each app uses, in order: - -1. **Sparkle feed** — `SUFeedURL` from the bundle's `Info.plist` → linked vendor homepage. -2. **Known vendor map** — bundle-id prefix maps to the official download page (Adobe, Microsoft, Docker, Cursor, Anthropic, JetBrains, GitKraken, Signal, Zoom, etc.). -3. **Web search** — DuckDuckGo query for ` macOS download`. - -### macOS preferences snapshot - -`ssr sync` also snapshots the live state of a curated set of macOS preference domains, writing one plist per domain to `/macos-prefs/`. During `ssr restore` these are replayed **after** `config/macos-defaults.sh`, so the snapshot is the last writer. - -Default domains: - -| Domain | What it covers | -|---|---| -| `com.apple.dock` | Dock position, app layout, hot corners | -| `com.apple.finder` | View options, sidebar, path bar | -| `com.apple.symbolichotkeys` | Global keyboard shortcuts (Spotlight, Mission Control, Screenshots…) | -| `com.apple.HIToolbox` | Input sources / keyboard layouts | -| `com.apple.spaces` | Spaces / Mission Control layout | -| `com.apple.menuextra.clock` | Menu-bar clock format | -| `NSGlobalDomain` | Global UI prefs, key-repeat speed, sound, language | - -**Conflict resolution during restore** - -When a snapshot domain overlaps with a domain that `config/macos-defaults.sh` also writes to, `ssr restore` warns and asks interactively: - -``` -[WARN] Pref-snapshot overlaps with declarative defaults for 2 domain(s): - com.apple.dock, com.apple.finder - -Domain `com.apple.dock`: - Snapshot from last sync (2026-05-11T17:30:00+0200) will OVERRIDE values - set by macos-defaults.sh. - [A]ccept snapshot / [r]eject (keep declarative)? [A/r]: -``` - -Default = `Accept` (press Enter). Reply `r` to keep the declarative value for that domain. In non-interactive contexts (launchd, CI) the decision falls back to `SSR_PREFS_CONFLICT_DEFAULT` (default `accept`). Set `SSR_ASSUME_YES=true` to skip all prompts. - -Extend the domain set in `~/.config/ssr/ssr.conf`: - -```bash -SSR_MACOS_PREF_DOMAINS_EXTRA="com.apple.universalaccess com.apple.Spotlight" -``` - -> **Mackup overlap:** if you also configure mackup to sync `com.apple.dock` or similar domains, two mechanisms will compete. Pick one. - -### Restore on a new machine - -```bash -git clone https://git.surke.de/osurke/system-sync-restore.git ~/.ssr -cd ~/.ssr && ./install.sh -ssr restore -``` - -By default `ssr restore` picks the Brewfile from `/BACKUP/ - /Brewfile`. To restore from a different machine's snapshot, pass an explicit path: - -```bash -ssr restore "$HOME/Library/Mobile Documents/com~apple~CloudDocs/BACKUP/oldhost - ABCD-1234/Brewfile" -``` +**New machine:** clone → `./install.sh` → `ssr restore`. Details: [Quick-start](https://git.surke.de/osurke/system-sync-restore/wiki/Quick-start), [Backup-structure-and-sync](https://git.surke.de/osurke/system-sync-restore/wiki/Backup-structure-and-sync). --- -## Configuration +## Wiki index -Config lives in `~/.config/ssr/ssr.conf` (override with `--config` or `$SSR_CONFIG`). The file is sourced by bash but only recognised `KEY=VALUE` lines are accepted; anything else causes `ssr` to abort. - -| Key | Default | Purpose | -|-----|---------|---------| -| `SSR_CLOUD_PROVIDER` | `icloud` | `icloud`\|`dropbox`\|`googledrive`\|`onedrive`\|`custom` | -| `SSR_CLOUD_PATH` | — | Absolute path; only used when provider is `custom` | -| `SSR_BACKUP_SUBDIR` | `BACKUP` | Subfolder for per-host backups | -| `SSR_MACKUP_SUBDIR` | `Mackup` | Subfolder used by mackup | -| `SSR_BREW_UPGRADE` | `true` | Run `brew upgrade` during sync | -| `SSR_BREW_CLEANUP` | `true` | Run `brew cleanup` after sync | -| `SSR_SCAN_UNMANAGED_APPS` | `true` | List `.app` bundles not from brew/MAS during sync | -| `SSR_APP_DIRS` | `/Applications:~/Applications` | Colon-separated dirs scanned for unmanaged apps | -| `SSR_SNAPSHOT_MACOS_PREFS` | `true` | Snapshot macOS pref domains during sync | -| `SSR_MACOS_PREF_DOMAINS` | _(see below)_ | Full override of snapshotted domains (space-separated) | -| `SSR_MACOS_PREF_DOMAINS_EXTRA` | — | Extra domains appended to the default set | -| `SSR_PREFS_CONFLICT_DEFAULT` | `accept` | Non-TTY conflict resolution: `accept` or `reject` | -| `SSR_ASSUME_YES` | `false` | Auto-accept all pref-snapshot conflicts on restore | -| `SSR_DISABLE_GATEKEEPER` | `false` | Run `spctl --global-disable` during restore (security trade-off) | -| `SSR_OPEN_CASKS` | `false` | Open every installed cask after restore for first-run config | -| `SSR_MACOS_DEFAULTS` | repo's `config/macos-defaults.sh` | Override path to your own defaults script | -| `SSR_LAUNCHD_LABEL` | `de.surke.ssr.sync` | launchd job label | -| `SSR_SCHEDULE_HOUR` | `9` | Daily run hour (0–23, local time) | -| `SSR_SCHEDULE_MINUTE` | `0` | Daily run minute | -| `SSR_PREFIX` | `$HOME/.local/bin` | Install prefix for the `ssr` symlink | -| `SSR_STATE_DIR` | `$HOME/.local/state/ssr` | Internal state directory | -| `SSR_LOG_DIR` | `$HOME/.local/state/ssr/logs` | launchd log directory | - -### Cloud provider paths resolved automatically - -| Provider | Resolved root | -|----------|---------------| -| `icloud` | `~/Library/Mobile Documents/com~apple~CloudDocs` | -| `dropbox` | `~/Library/CloudStorage/Dropbox*` (fallback `~/Dropbox`) | -| `googledrive` | `~/Library/CloudStorage/GoogleDrive-*` | -| `onedrive` | `~/Library/CloudStorage/OneDrive-*` | -| `custom` | Value of `SSR_CLOUD_PATH` | +| Topic | Wiki | +|--------|------| +| Install & first steps | [Quick-start](https://git.surke.de/osurke/system-sync-restore/wiki/Quick-start) | +| Command list | [Commands](https://git.surke.de/osurke/system-sync-restore/wiki/Commands) | +| Cloud layout, unmanaged apps, macOS pref snapshots | [Backup-structure-and-sync](https://git.surke.de/osurke/system-sync-restore/wiki/Backup-structure-and-sync) | +| `ssr.conf` and cloud paths | [Configuration-reference](https://git.surke.de/osurke/system-sync-restore/wiki/Configuration-reference) | +| launchd, logs, `ssr update` | [Scheduling-logging-and-updates](https://git.surke.de/osurke/system-sync-restore/wiki/Scheduling-logging-and-updates) | +| Tab completions | [Shell-completions](https://git.surke.de/osurke/system-sync-restore/wiki/Shell-completions) | +| Security, uninstall, legacy scripts | [Security-Uninstall-and-Migration](https://git.surke.de/osurke/system-sync-restore/wiki/Security-Uninstall-and-Migration) | +| Repo tree | [Repository-layout](https://git.surke.de/osurke/system-sync-restore/wiki/Repository-layout) | --- -## Shell completions +## Contributing docs -`ssr install` offers to install completions automatically. To do it manually later: +Edit the **wiki** repository (`System-Sync-Restore.wiki`) for user-facing guides; keep this README as the short landing page and link hub. Example clone: ```bash -ssr completions install # detects $SHELL -ssr completions install --shell all # zsh + bash + fish -ssr completions status # show what's wired up -ssr completions uninstall --shell all +git clone https://git.surke.de/osurke/system-sync-restore.wiki.git ``` -Targets (user-scoped, no sudo): - -| Shell | Path | -|-------|------| -| zsh | `~/.zsh/completions/_ssr` | -| bash | `~/.local/share/bash-completion/completions/ssr` | -| fish | `~/.config/fish/completions/ssr.fish` | - -For zsh, ensure `~/.zsh/completions` is on `$fpath` (the installer prints the snippet for `~/.zshrc` if it isn't already). For bash, you need [`bash-completion@2`](https://github.com/scop/bash-completion) sourced from your shell rc — Homebrew install path is also printed. Fish needs no extra setup. - -After installation, open a fresh shell or `exec $SHELL` and `ssr ` lists the available commands. - ---- - -## Scheduled sync - -```bash -ssr schedule on # write & load ~/Library/LaunchAgents/