Files
adastra_scripts/dirsync/dir-sync.sh
T

165 lines
4.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# Author: Julien Gautier <jgautier.webdev@gmail.com>
# Organization: AdAstra
# Project: adastra_scripts
#
################################################################################
# Directory Sync Utility Script
#
# Watches a local directory for file changes and syncs them to a remote host
# via SCP in real time. On exit (Ctrl+C), resets the remote repository and
# clears the remote cache.
#
# Usage: ./dir-sync.sh [OPTIONS]
#
# Options:
# -s, --source <path> Local directory absolute path
# -d, --dest <path> Remote directory absolute path
# -r, --remote-host <h> Remote SSH host
# -h, --help Print this help
#
# Examples:
# ./dir-sync.sh -s /var/www/myapp/ -d /var/www/myapp/ -r myserver
# ./dir-sync.sh -s ~/projects/app/ -d /srv/app/ -r devhost
#
# Requirements:
# fswatch, scp, ssh
#
################################################################################
# --- Configuration -----------------------------------------------------------
DEFAULT_LOCAL_PATH='/path/to/local/dir/'
DEFAULT_REMOTE_PATH='/path/to/remote/dir/'
DEFAULT_HOST='devhost'
# --- Colors ------------------------------------------------------------------
NONE='\033[0m'
BOLD='\033[1m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
BBLUE='\033[1;94m'
# --- Usage -------------------------------------------------------------------
usage() {
echo -e "
${BOLD}NAME${NONE}
dir-sync — Synchronize a local folder to a remote host
${BOLD}SYNOPSIS${NONE}
bash $0 [OPTION]...
${BOLD}OPTIONS${NONE}
-h, --help Print this help
-s, --source <path> Local directory absolute path
-d, --dest <path> Remote directory absolute path
-r, --remote-host <h> Remote SSH host
${RED}Example:${NONE} $0 -s /path/to/local/ -d /path/to/remote/ -r sshhost
"
}
# --- Prerequisite checks -----------------------------------------------------
check_deps() {
local missing=0
for cmd in fswatch scp ssh; do
if ! command -v "$cmd" &>/dev/null; then
echo -e "${RED}✗ Missing required command: ${cmd}${NONE}"
missing=1
fi
done
[ "$missing" -eq 0 ] || exit 1
}
# --- Cleanup (runs on INT/TERM) ----------------------------------------------
cleanup() {
echo -e "\n${CYAN}♻️ Resetting remote repository...${NONE}"
echo -e "\$> ${MAGENTA}ssh ${host} \"cd '${dir_remote}'; git reset --hard\"${NONE}"
ssh "$host" "cd '${dir_remote}'; git reset --hard"
echo -e "\n${CYAN}🗑️ Clearing remote cache...${NONE}"
echo -e "\$> ${MAGENTA}ssh ${host} \"cd '${dir_remote}'; composer front-cache-clear\"${NONE}"
ssh "$host" "cd '${dir_remote}'; composer front-cache-clear"
wait
echo -e "\n${GREEN}✔ Done.${NONE}"
exit 0
}
# --- Sync a single file ------------------------------------------------------
sync_file() {
local local_path="$1"
local remote_path="${local_path/$dir_local/$dir_remote}"
echo -e "\n${CYAN}🔄 Syncing ${YELLOW}${local_path/$dir_local/}${NONE}"
echo -e "\$> ${MAGENTA}scp '${local_path}' ${host}:'${remote_path}'${NONE}"
scp "${local_path}" "${host}:${remote_path}"
}
# --- Main --------------------------------------------------------------------
clear
echo -e "${BBLUE}🔎 Starting $0${NONE}"
echo -e "${BLUE}-------------------------------${NONE}"
check_deps
dir_local=''
dir_remote=''
host=''
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help) usage; exit 0 ;;
-s|--source) dir_local="$2"; shift 2 ;;
-d|--dest) dir_remote="$2"; shift 2 ;;
-r|--remote-host) host="$2"; shift 2 ;;
*)
echo -e "${RED}✗ Unknown option: $1${NONE}"
usage
exit 1
;;
esac
done
if [[ -z "$dir_local" ]]; then
dir_local="$DEFAULT_LOCAL_PATH"
echo -e "${YELLOW}⚠ Local path: ${dir_local} (default)${NONE}"
else
echo -e "${GREEN}⚙️ Local path: ${dir_local}${NONE}"
fi
if [[ -z "$dir_remote" ]]; then
dir_remote="$DEFAULT_REMOTE_PATH"
echo -e "${YELLOW}⚠ Remote path: ${dir_remote} (default)${NONE}"
else
echo -e "${GREEN}⚙️ Remote path: ${dir_remote}${NONE}"
fi
if [[ -z "$host" ]]; then
host="$DEFAULT_HOST"
echo -e "${YELLOW}⚠ Remote host: ${host} (default)${NONE}"
else
echo -e "${GREEN}⚙️ Remote host: ${host}${NONE}"
fi
trap cleanup INT TERM
echo -e "\n${BBLUE}⏳ Watching for changes...${NONE}"
echo -e "${BLUE}-----------------------------${NONE}"
while IFS= read -r file; do
if [[ "$file" == "NoOp" ]]; then
echo -e "\n${CYAN}🗑️ Clearing remote cache...${NONE}"
echo -e "\$> ${MAGENTA}ssh ${host} \"cd '${dir_remote}'; composer front-cache-clear\"${NONE}"
ssh "$host" "cd '${dir_remote}'; composer front-cache-clear"
echo -e "\n${BBLUE}⏳ Watching for changes...${NONE}"
echo -e "${BLUE}-----------------------------${NONE}"
else
sync_file "$file" &
fi
done < <(fswatch --batch-marker -0 --exclude '.git/' "$dir_local" | tr '\0' '\n')