Improve schedule and mackup reliability

- bin/ssr-schedule: use `launchctl bootstrap`/`bootout` (modern API) with
  legacy `load -w` fallback. The previous `load -w`-only flow silently
  no-op'd on macOS 10.15+ in some configurations, leaving `ssr status`
  reporting `inactive` after a successful `ssr schedule on`.
- bin/ssr-status: query the service via `launchctl print`/`list <label>`
  for consistent active/inactive detection.
- lib/mackup.sh: pre-materialize iCloud placeholders via `brctl download`
  and retry `mackup -f backup` up to three times to dodge the recurring
  `OSError [Errno 66] Directory not empty` race between mackup's rmtree
  and iCloud's filesystem provider. Soft-fails so the rest of `ssr sync`
  still runs even if mackup never settles; logs actionable hints.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-11 18:02:31 +02:00
parent c1848f66e8
commit a4465f37c6
3 changed files with 103 additions and 8 deletions
+45 -6
View File
@@ -17,6 +17,20 @@ INTERVAL_HOUR="${SSR_SCHEDULE_HOUR:-9}"
INTERVAL_MIN="${SSR_SCHEDULE_MINUTE:-0}"
SSR_BIN="$SSR_ROOT/bin/ssr"
# Modern launchd target. `launchctl load -w` has been deprecated since 10.11
# and is a silent no-op on recent macOS — use bootstrap/bootout against the
# GUI domain of the current user.
GUI_DOMAIN="gui/$(id -u)"
SERVICE_TARGET="${GUI_DOMAIN}/${LABEL}"
# ssr::schedule::is_loaded — exit 0 iff launchd knows the job.
# `launchctl print` is the modern check; `launchctl list <label>` is the
# legacy fallback that still works on every macOS we care about.
is_loaded() {
launchctl print "$SERVICE_TARGET" >/dev/null 2>&1 \
|| launchctl list "$LABEL" >/dev/null 2>&1
}
render_plist() {
ssr::ensure_dir "$LOG_DIR"
ssr::ensure_dir "$(dirname "$PLIST_DST")"
@@ -31,18 +45,43 @@ render_plist() {
chmod 600 "$PLIST_DST"
}
# Boot the agent into the user's GUI domain, captures stderr for diagnostics.
# Falls back to the legacy `load -w` only if bootstrap fails entirely.
load_agent() {
local err
# Always bootout first so re-runs pick up plist changes.
launchctl bootout "$SERVICE_TARGET" >/dev/null 2>&1 || true
err="$(launchctl bootstrap "$GUI_DOMAIN" "$PLIST_DST" 2>&1)" || {
ssr::warn "launchctl bootstrap failed: ${err:-no stderr}"
ssr::warn "Falling back to legacy 'launchctl load -w'"
launchctl load -w "$PLIST_DST" 2>&1 || true
}
# `enable` makes the job survive logout/reboot (parity with old `load -w`).
launchctl enable "$SERVICE_TARGET" >/dev/null 2>&1 || true
}
unload_agent() {
launchctl bootout "$SERVICE_TARGET" >/dev/null 2>&1 \
|| launchctl unload "$PLIST_DST" 2>/dev/null || true
}
cmd_on() {
[[ -f "$PLIST_SRC" ]] || ssr::die "launchd template missing: $PLIST_SRC"
render_plist
# Reload to pick up changes if it was already loaded.
launchctl unload "$PLIST_DST" 2>/dev/null || true
launchctl load -w "$PLIST_DST"
ssr::ok "Scheduled sync enabled (${INTERVAL_HOUR}:$(printf '%02d' "$INTERVAL_MIN") daily) → $PLIST_DST"
load_agent
if is_loaded; then
ssr::ok "Scheduled sync enabled (${INTERVAL_HOUR}:$(printf '%02d' "$INTERVAL_MIN") daily) → $PLIST_DST"
else
ssr::die "launchd did not register the job. Diagnose with:
launchctl bootstrap $GUI_DOMAIN $PLIST_DST
launchctl print $SERVICE_TARGET"
fi
}
cmd_off() {
if [[ -f "$PLIST_DST" ]]; then
launchctl unload "$PLIST_DST" 2>/dev/null || true
unload_agent
rm -f "$PLIST_DST"
ssr::ok "Scheduled sync disabled"
else
@@ -51,7 +90,7 @@ cmd_off() {
}
cmd_status() {
if [[ -f "$PLIST_DST" ]] && launchctl list | grep -q "$LABEL"; then
if is_loaded; then
ssr::ok "Scheduled sync: active (label=$LABEL)"
else
ssr::log "Scheduled sync: inactive"