#!/usr/bin/env bash # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. # # zsync — copy new backup files offsite; or build + mirror a vite project's dist. # # Usage: # zsync # new files: backups folder -> paths.oneDriveBackups # zsync --dest /mnt/mirror/dist # # The no-args mode copies only files that don't exist at the destination yet # (never overwrites, never deletes). The project mode runs npm run build, then # mirrors dist/ to --dest (or $ZSYNC_DEST) with rsync --delete. set -uo pipefail source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/zhelpers.sh" z_track_start "$@" z_need_config projects=(); dest="${ZSYNC_DEST:-}" while [ $# -gt 0 ]; do case "$1" in --dest) dest="${2:-}"; shift 2 ;; -*) err "Unknown option: $1"; exit 1 ;; *) projects+=("$1"); shift ;; esac done # ---- no-args mode: backups -> offsite, new files only ------------------------ if [ "${#projects[@]}" -eq 0 ]; then BACKUPS_ROOT="$(dirname "$(z_path "$(zq '.paths.backupsLocal')")")" OFFSITE_ROOT="$(z_path "$(zq '.paths.oneDriveBackups')")" printf '\n'; info "=== zsync (backups -> offsite) ===" dim " Source: $BACKUPS_ROOT" dim " Destination: $OFFSITE_ROOT" dim " Mode: new files and folders only" printf '\n' if [ -z "$OFFSITE_ROOT" ]; then warn " paths.oneDriveBackups is not set in zconfig.json - nothing to do." exit 0 fi if [ ! -d "$BACKUPS_ROOT" ]; then warn " Source not found (skipped): $BACKUPS_ROOT" exit 0 fi mkdir -p "$OFFSITE_ROOT" copied=0; skipped=0 while IFS= read -r -d '' f; do rel="${f#"$BACKUPS_ROOT"/}" target="$OFFSITE_ROOT/$rel" if [ -e "$target" ]; then skipped=$((skipped + 1)); continue; fi mkdir -p "$(dirname "$target")" cp -p "$f" "$target" ok " Copied: $rel ($(z_size_mb "$f") MB)" copied=$((copied + 1)) done < <(find "$BACKUPS_ROOT" -type f -print0 2>/dev/null) printf '\n'; info " Done: $copied copied, $skipped already present" printf '\n' exit 0 fi # ---- project mode: build + mirror a vite project's dist ---------------------- z_require rsync for key in "${projects[@]}"; do zproj_require "$key" kind="$(zproj "$key" .kind)" if [ "$kind" != "vite" ]; then printf '\n'; warn "zsync project mode only supports vite kind (builds and mirrors dist/). '$key' is kind '$kind'." exit 1 fi root="$(zproj_root "$key")" if [ -z "$dest" ]; then printf '\n'; info "=== zsync ($(zproj "$key" .label)) ===" warn "No destination set." dim "Set ZSYNC_DEST or run: zsync $key --dest /path/to/folder" dim "This runs npm run build, then mirrors dist -> destination (rsync --delete)." exit 1 fi printf '\n'; info "=== zsync ($(zproj "$key" .label)) ===" info "Build + mirror dist -> $dest" printf '\n' (cd "$root" && npm run build) || { err "npm run build failed"; exit 1; } [ -d "$root/dist" ] || { err "dist/ missing after build."; exit 1; } mkdir -p "$dest" rsync -a --delete "$root/dist/" "$dest/" || { err "rsync failed"; exit 1; } printf '\n'; ok "Sync complete." done