Add --merge-run to rsync and --force to arr_sync for authoritative node compliance

This commit is contained in:
Gmer4Lfe
2026-06-14 15:51:28 -04:00
parent 5a7d5b5005
commit 3c303210a3
2 changed files with 165 additions and 37 deletions
+57
View File
@@ -131,6 +131,13 @@
# rsync.sh /path/to/share --seed
# Skip the empty-remote-share guard. Use for first-time seeding of a new share.
#
# rsync.sh /path/to/share --merge-run
# Bidirectional merge: pull remote-unique content to local first (--ignore-existing),
# then push local → remote with --delete so the remote matches local exactly.
# Local is always authoritative — remote loses divergent file versions but keeps
# any content the local did not have (pulled in pass 1 before the delete push).
# Also auto-triggered when pre-scan detects ≥75% directory overlap with remote.
#
# ==============================================================================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -141,12 +148,14 @@ source "$SCRIPT_DIR/../load_config.sh"
DIRECTORY=""
PROFILE_OVERRIDE=""
SEED=false
MERGE_RUN=false
RAW_ARGS=()
for ARG in "$@"; do
case "$ARG" in
--profile=*) PROFILE_OVERRIDE="${ARG#--profile=}" ;;
--seed) SEED=true ;;
--merge-run) MERGE_RUN=true ;;
--*|*=*) RAW_ARGS+=("$ARG") ;;
*) [[ -z "$DIRECTORY" ]] && DIRECTORY="$ARG" || RAW_ARGS+=("$ARG") ;;
esac
@@ -260,6 +269,31 @@ check_remote_rootfs
[[ "$SEED" == false ]] && check_remote_share "$DIRECTORY"
check_remote_disks "$DIRECTORY"
# ── Merge-run pre-scan ────────────────────────────────────────────────────────────────────────
# Auto-promote to merge mode when ≥75% of remote's top-level entries exist locally.
# Skipped when --merge-run is already set or --seed is active (remote was just created).
if [[ "$MERGE_RUN" == false && "$SEED" == false ]]; then
_remote_top=$(ssh -i "$SSH_KEY" -o ConnectTimeout=10 -o BatchMode=yes \
root@"$REMOTE_SERVER" "ls -1A '$DIRECTORY' 2>/dev/null | sort" 2>/dev/null)
_remote_count=$(echo "$_remote_top" | grep -c . 2>/dev/null || echo 0)
if [[ "$_remote_count" -gt 0 ]]; then
_local_top=$(ls -1A "$DIRECTORY" 2>/dev/null | sort)
_overlap=$(comm -12 \
<(echo "$_local_top") \
<(echo "$_remote_top") | grep -c . 2>/dev/null || echo 0)
_overlap_pct=$(( _overlap * 100 / _remote_count ))
if [[ "$_overlap_pct" -ge 75 ]]; then
info "Overlap ${_overlap_pct}% (${_overlap}/${_remote_count} entries) — auto-promoting to merge mode"
MERGE_RUN=true
else
log "Overlap ${_overlap_pct}% (${_overlap}/${_remote_count} entries) — normal sync"
fi
fi
unset _remote_top _remote_count _local_top _overlap _overlap_pct
fi
# Remote Docker daemon — check before attempting container operations
if [[ ${#CRITICAL_CONTAINER_NAMES[@]} -gt 0 ]] || [[ ${#REMOTE_RESTART_CONTAINERS[@]} -gt 0 ]]; then
check_remote_docker_daemon || {
@@ -315,6 +349,29 @@ RSYNC_OPTS+=(--stats)
[[ "$DRY_RUN" == true ]] && RSYNC_OPTS+=("--dry-run")
# ── Merge pass 1: pull remote-unique content to local (--ignore-existing) ────────────────────
# Runs before the push so anything the remote has that we don't is preserved locally.
# After this pass, local is the superset — the delete push in pass 2 is then safe.
if [[ "$MERGE_RUN" == true ]]; then
echo "$ICON_SYNC Merge pass 1 — pulling ${REMOTE_SERVER_NAME}-unique content to local..."
_pull_opts=(-av --ignore-existing --stats)
[[ "$DRY_RUN" == true ]] && _pull_opts+=(--dry-run)
_pull_output=$(rsync "${_pull_opts[@]}" \
-e "ssh -i $SSH_KEY -T -o Compression=no -o IPQoS=throughput" \
"root@${REMOTE_SERVER}:${DIRECTORY}/" "${DIRECTORY}/" 2>&1)
_pull_exit=$?
_pull_bytes=$(echo "$_pull_output" | \
awk '/Total transferred file size:/{gsub(/,/,"",$NF); gsub(/[^0-9]/,"",$NF); print $NF+0}')
if [[ "$_pull_exit" -eq 0 ]]; then
echo "$ICON_DONE Merge pass 1 complete — ${_pull_bytes:-0} bytes pulled"
else
warn "Merge pass 1 failed (exit $_pull_exit) — continuing with push"
fi
unset _pull_opts _pull_output _pull_exit _pull_bytes
# Pass 2: push with --delete — local is now the authoritative superset
RSYNC_OPTS+=(--delete)
fi
START=$(date +%s)
RSYNC_SUCCESS=false
BYTES_TRANSFERRED=0