| #!/usr/bin/env bash |
| set -euo pipefail |
|
|
| DATA_ROOT="${DATA_ROOT:-/data/root}" |
| SYNC_INTERVAL="${SYNC_INTERVAL:-300}" |
| CONFIG_PATH=".openclaw/openclaw.json" |
|
|
| EXCLUDES=( |
| "--exclude=.cache" |
| "--exclude=.npm/_cacache" |
| "--exclude=.npm/_update-notifier-last-checked*" |
| "--exclude=.pnpm-store" |
| "--exclude=node_modules" |
| "--exclude=.next" |
| "--exclude=dist" |
| "--exclude=build" |
| "--exclude=coverage" |
| "--exclude=tmp" |
| ) |
|
|
| data_available() { |
| [ -d /data ] || mkdir -p /data 2>/dev/null || return 1 |
| mkdir -p "$DATA_ROOT" 2>/dev/null || return 1 |
| } |
|
|
| restore_root() { |
| if data_available; then |
| echo "Restoring persistent data from $DATA_ROOT to /root..." |
| rsync -rlptD --no-specials --no-devices --update "${EXCLUDES[@]}" "$DATA_ROOT/" /root/ || true |
| else |
| echo "Persistent /data is not available; skipping restore." |
| fi |
| } |
|
|
| persist_root() { |
| if data_available; then |
| echo "Syncing /root to $DATA_ROOT..." |
| rsync -rlptD --no-specials --no-devices --update --delete "${EXCLUDES[@]}" /root/ "$DATA_ROOT/" || true |
| else |
| echo "Persistent /data is not available; skipping sync." |
| fi |
| } |
|
|
| sync_config_newer() { |
| local root_config="/root/$CONFIG_PATH" |
| local data_config="$DATA_ROOT/$CONFIG_PATH" |
|
|
| if [ -f "$data_config" ] && { [ ! -f "$root_config" ] || [ "$data_config" -nt "$root_config" ]; }; then |
| mkdir -p "$(dirname "$root_config")" |
| cp -p "$data_config" "$root_config" || true |
| echo "Pulled newer OpenClaw config from $data_config to $root_config." |
| elif [ -f "$root_config" ] && { [ ! -f "$data_config" ] || [ "$root_config" -nt "$data_config" ]; }; then |
| mkdir -p "$(dirname "$data_config")" |
| cp -p "$root_config" "$data_config" || true |
| echo "Persisted newer OpenClaw config from $root_config to $data_config." |
| fi |
| } |
|
|
| reconcile_root_data() { |
| if data_available; then |
| restore_root |
| sync_config_newer |
| persist_root |
| else |
| echo "Persistent /data is not available; skipping two-way sync." |
| fi |
| } |
|
|
| case "${1:-loop}" in |
| restore) |
| restore_root |
| ;; |
| persist) |
| persist_root |
| ;; |
| reconcile) |
| reconcile_root_data |
| ;; |
| loop) |
| while true; do |
| reconcile_root_data |
| sleep "$SYNC_INTERVAL" |
| done |
| ;; |
| *) |
| echo "Usage: $0 {restore|persist|loop}" |
| exit 2 |
| ;; |
| esac |
|
|