#!/usr/bin/env bash # lib/icloud.sh — iCloud Drive prefetch, wait, and keep-local helpers. # # All functions are no-ops when the target directory is not under iCloud # (i.e. does not contain "Mobile Documents" in the path). # --- Guard: only operate on iCloud paths ------------------------------------ _ssr::icloud::is_icloud() { case "$1" in *Mobile\ Documents*) return 0 ;; esac return 1 } # --------------------------------------------------------------------------- # ssr::icloud::prefetch # # Triggers background download of every .icloud placeholder file found under # . Returns immediately (async). Use ssr::icloud::wait to poll for # completion before running tools that need the real file content. # --------------------------------------------------------------------------- ssr::icloud::prefetch() { local dir="$1" [[ -d "$dir" ]] || return 0 _ssr::icloud::is_icloud "$dir" || return 0 local count=0 stub d base real while IFS= read -r stub; do [[ -n "$stub" ]] || continue d="$(dirname "$stub")" base="$(basename "$stub")" # .icloud stubs are named ..icloud — strip leading dot + suffix. real="${base#.}"; real="${real%.icloud}" # open -g: open in background without bringing any app to the front. # This is the supported way to request iCloud Drive file materialisation # since brctl download was removed in macOS Sonoma. open -g "$d/$real" 2>/dev/null & count=$(( count + 1 )) done < <(find "$dir" -name '*.icloud' -type f 2>/dev/null) if [[ $count -gt 0 ]]; then ssr::log "iCloud prefetch: triggered download of $count placeholder(s) in $(basename "$dir") (async)" fi } # --------------------------------------------------------------------------- # ssr::icloud::wait [timeout_seconds] # # Polls until all .icloud placeholder files under are gone (fully # downloaded) or until (default 180) elapses. # Returns 0 on full completion, 1 on timeout (non-fatal). # --------------------------------------------------------------------------- ssr::icloud::wait() { local dir="$1" timeout="${2:-180}" interval=5 [[ -d "$dir" ]] || return 0 _ssr::icloud::is_icloud "$dir" || return 0 local elapsed=0 remaining while [[ $elapsed -lt $timeout ]]; do remaining="$(find "$dir" -name '*.icloud' -type f 2>/dev/null | wc -l | tr -d ' ')" [[ "$remaining" -eq 0 ]] && { ssr::ok "iCloud sync complete (all files local)" return 0 } ssr::log "iCloud: $remaining file(s) still downloading… (${elapsed}s/${timeout}s)" sleep "$interval" elapsed=$(( elapsed + interval )) done remaining="$(find "$dir" -name '*.icloud' -type f 2>/dev/null | wc -l | tr -d ' ')" ssr::warn "iCloud wait timed out after ${timeout}s — $remaining placeholder(s) still pending; continuing anyway" return 1 } # --------------------------------------------------------------------------- # ssr::icloud::keep_local # # Best-effort: marks every real (non-stub) file under as non-evictable # so iCloud Drive does not replace them with .icloud placeholders between # runs. Two complementary techniques: # # 1. Remove com.apple.icloud.evictable — iCloud-internal xattr that, when # absent (or set to 0), prevents on-demand eviction. This xattr is # written by iCloudDrive when eviction is allowed; removing it pins # the file locally. (Internal API — best-effort.) # # 2. Update the access-time (touch -a) — iCloud uses an LRU policy; files # accessed recently are the last to be evicted. # # Note: Apple provides no *public* CLI to permanently pin iCloud files. # For a guaranteed "Keep Downloaded" equivalent the Finder UI must be used, # or NSFileManager.setUbiquitous(false, …) from a native app. # --------------------------------------------------------------------------- ssr::icloud::keep_local() { local dir="$1" [[ -d "$dir" ]] || return 0 _ssr::icloud::is_icloud "$dir" || return 0 local count=0 f while IFS= read -r f; do [[ -n "$f" ]] || continue # 1) Remove the evictable attribute (ignore errors on files that don't have it). xattr -d "com.apple.icloud.evictable" "$f" 2>/dev/null || true # 2) Touch access time so LRU keeps this file at the back of the eviction queue. touch -a "$f" 2>/dev/null || true count=$(( count + 1 )) done < <(find "$dir" -type f -not -name '*.icloud' 2>/dev/null) [[ $count -gt 0 ]] && ssr::log "iCloud keep-local: marked $count file(s) in $(basename "$dir") (access-time + xattr)" return 0 }