Files
System-Sync-Restore/lib/cloud.sh
T
Oliver Surke 554ed519c6 Enhance cloud storage handling and configuration documentation
- Updated `ssr.conf.example` to clarify the usage of `SSR_CLOUD_PATH` for custom cloud providers, including examples for handling multiple folders.
- Introduced `ssr::cloud::resolve_storage_pattern` function in `lib/cloud.sh` to improve directory resolution for cloud storage providers, ensuring proper handling of multiple matches.
- Refactored `ssr::cloud::resolve_dir` to utilize the new storage resolution function, enhancing error handling and user feedback for cloud directory detection.
2026-05-18 10:24:31 +02:00

128 lines
4.7 KiB
Bash

#!/usr/bin/env bash
# lib/cloud.sh — cloud storage provider abstraction.
# Resolves SSR_CLOUD_DIR based on SSR_CLOUD_PROVIDER from config.
# Echo one directory under ~/Library/CloudStorage matching find -name "$1".
# $2 = label for errors (e.g. OneDrive). $3 = optional fallback dir if zero matches.
# If several folders match (e.g. personal + work OneDrive), SSR_CLOUD_PATH must
# be set to the absolute path of the chosen root (same as one of the matches);
# otherwise we abort with a list of candidates. Tilde in SSR_CLOUD_PATH is expanded.
ssr::cloud::resolve_storage_pattern() {
local pattern="$1" label="$2" zero_fallback="${3:-}"
local cs="$HOME/Library/CloudStorage"
local custom="${SSR_CLOUD_PATH:-}"
case "$custom" in
'~' | '~'/*) custom="${custom/#\~/$HOME}" ;;
esac
local matches=()
local d
if [[ -d "$cs" ]]; then
while IFS= read -r d; do
[[ -n "$d" && -d "$d" ]] && matches+=("$d")
done < <(find "$cs" -maxdepth 1 -type d -name "$pattern" 2>/dev/null | LC_ALL=C sort -u)
fi
local n="${#matches[@]}"
if [[ "$n" -eq 0 ]]; then
if [[ -n "$zero_fallback" && -d "$zero_fallback" ]]; then
printf '%s\n' "$zero_fallback"
return 0
fi
ssr::die "$label folder not found under ~/Library/CloudStorage"
fi
if [[ "$n" -eq 1 ]]; then
printf '%s\n' "${matches[0]}"
return 0
fi
if [[ -z "$custom" ]]; then
ssr::err "Multiple $label folders found; set SSR_CLOUD_PATH in ssr.conf to the root you want (absolute path), or use SSR_CLOUD_PROVIDER=custom."
for d in "${matches[@]}"; do ssr::err " $d"; done
exit 1
fi
ssr::validate_path "$custom"
[[ -d "$custom" ]] || ssr::die "SSR_CLOUD_PATH is not a directory: $custom"
local abs_c abs_m picked=""
abs_c="$(cd "$custom" && pwd -P)" || ssr::die "SSR_CLOUD_PATH not accessible: $custom"
for d in "${matches[@]}"; do
abs_m="$(cd "$d" && pwd -P)" || continue
if [[ "$abs_m" == "$abs_c" ]]; then
picked="$d"
break
fi
done
if [[ -z "$picked" ]]; then
ssr::err "SSR_CLOUD_PATH=$custom is not one of the detected $label roots:"
for d in "${matches[@]}"; do ssr::err " $d"; done
exit 1
fi
printf '%s\n' "$picked"
}
ssr::cloud::resolve_dir() {
local provider="${SSR_CLOUD_PROVIDER:-icloud}" custom="${SSR_CLOUD_PATH:-}"
case "$provider" in
icloud)
printf '%s\n' "$HOME/Library/Mobile Documents/com~apple~CloudDocs"
;;
dropbox)
if [[ ! -d "$HOME/Library/CloudStorage" ]]; then
[[ -d "$HOME/Dropbox" ]] || ssr::die "Dropbox not found (no ~/Library/CloudStorage and no ~/Dropbox)."
printf '%s\n' "$HOME/Dropbox"
return 0
fi
ssr::cloud::resolve_storage_pattern 'Dropbox*' 'Dropbox' "$HOME/Dropbox"
;;
googledrive)
ssr::cloud::resolve_storage_pattern 'GoogleDrive-*' 'Google Drive' ''
;;
onedrive)
ssr::cloud::resolve_storage_pattern 'OneDrive-*' 'OneDrive' ''
;;
custom)
[[ -n "$custom" ]] || ssr::die "SSR_CLOUD_PROVIDER=custom requires SSR_CLOUD_PATH"
case "$custom" in
'~' | '~'/*) custom="${custom/#\~/$HOME}" ;;
esac
ssr::validate_path "$custom"
printf '%s\n' "$custom"
;;
*)
ssr::die "Unknown SSR_CLOUD_PROVIDER: $provider (use: icloud|dropbox|googledrive|onedrive|custom)"
;;
esac
}
# Returns the per-host backup directory under the cloud root.
ssr::cloud::backup_dir() {
local cloud host uuid
cloud="$(ssr::cloud::resolve_dir)"
host="$(hostname -s)"
uuid="$(/usr/sbin/system_profiler SPHardwareDataType 2>/dev/null \
| awk '/Hardware UUID/ { print $3 }')"
[[ -n "$uuid" ]] || uuid="no-uuid"
local subdir="${SSR_BACKUP_SUBDIR:-BACKUP}"
printf '%s/%s/%s - %s\n' "$cloud" "$subdir" "$host" "$uuid"
}
# Parent directory for Mackup file_system storage: same cloud subfolder as
# per-host backups (SSR_BACKUP_SUBDIR). ~/.mackup.cfg sets path=<this> and
# directory=mackup — Mackup places files under <this>/mackup/ (not SSR-controlled).
ssr::cloud::mackup_dir() {
local cloud subdir
cloud="$(ssr::cloud::resolve_dir)"
subdir="${SSR_BACKUP_SUBDIR:-BACKUP}"
printf '%s/%s\n' "$cloud" "$subdir"
}
ssr::cloud::ensure_available() {
local cloud
cloud="$(ssr::cloud::resolve_dir)"
[[ -d "$cloud" ]] || ssr::die "Cloud directory not available: $cloud"
ssr::ok "Cloud provider: ${SSR_CLOUD_PROVIDER:-icloud}$cloud"
}