|
|
|
@@ -1,160 +1,164 @@
|
|
|
|
|
#!/bin/zsh
|
|
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
|
|
|
|
|
RETVAL=0
|
|
|
|
|
# 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
|
|
|
|
|
#
|
|
|
|
|
################################################################################
|
|
|
|
|
|
|
|
|
|
# CONF
|
|
|
|
|
defaultLocalPath='/path/to/local/dir/'
|
|
|
|
|
defaultRemotePath='/path/to/remote/dir/'
|
|
|
|
|
defaultHost='devac'
|
|
|
|
|
# --- Configuration -----------------------------------------------------------
|
|
|
|
|
DEFAULT_LOCAL_PATH='/path/to/local/dir/'
|
|
|
|
|
DEFAULT_REMOTE_PATH='/path/to/remote/dir/'
|
|
|
|
|
DEFAULT_HOST='devhost'
|
|
|
|
|
|
|
|
|
|
NONE='\033[0m' # none
|
|
|
|
|
GREY='\033[2m' # grey
|
|
|
|
|
BOLD='\033[1m' # bold
|
|
|
|
|
# --- 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'
|
|
|
|
|
|
|
|
|
|
GREEN='\033[0;32m' # green
|
|
|
|
|
YELLOW='\033[0;33m' # yellow
|
|
|
|
|
RED='\033[0;31m' # red
|
|
|
|
|
BLUE='\033[0;34m' # blue
|
|
|
|
|
CYAN='\033[0;36m' # cyan
|
|
|
|
|
MAGENTA='\033[0;35m' # magenta
|
|
|
|
|
BLACK='\033[0;30m' # black
|
|
|
|
|
WHITE='\033[0;37m' # white
|
|
|
|
|
# --- Usage -------------------------------------------------------------------
|
|
|
|
|
usage() {
|
|
|
|
|
echo -e "
|
|
|
|
|
${BOLD}NAME${NONE}
|
|
|
|
|
dir-sync — Synchronize a local folder to a remote host
|
|
|
|
|
|
|
|
|
|
BBLUE='\033[1;94m' # blue bold
|
|
|
|
|
${BOLD}SYNOPSIS${NONE}
|
|
|
|
|
bash $0 [OPTION]...
|
|
|
|
|
|
|
|
|
|
POSITIONAL=()
|
|
|
|
|
${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
|
|
|
|
|
|
|
|
|
|
clear
|
|
|
|
|
|
|
|
|
|
echo -e "${NONE}${BBLUE}🔎 Lancement du script $0 ${NONE}${GREY}"
|
|
|
|
|
echo -e "${NONE}${BLUE}-------------------------------${NONE}${GREY}"
|
|
|
|
|
|
|
|
|
|
Usage()
|
|
|
|
|
{
|
|
|
|
|
echo -e "${BOLD}NAME${NONE}"
|
|
|
|
|
echo " scpsync - Synchronize local folder to a remote host"
|
|
|
|
|
echo " "
|
|
|
|
|
echo -e "${BOLD}SYNOPSIS${NONE}"
|
|
|
|
|
echo " sh $0 [OPTION]..."
|
|
|
|
|
echo " "
|
|
|
|
|
echo -e "${BOLD}DESCRIPTION${NONE}"
|
|
|
|
|
echo " -h, --help"
|
|
|
|
|
echo " "
|
|
|
|
|
echo " print this help"
|
|
|
|
|
echo " "
|
|
|
|
|
echo " -d, --dest"
|
|
|
|
|
echo " "
|
|
|
|
|
echo " remote directory absolut path"
|
|
|
|
|
echo " "
|
|
|
|
|
echo " -s, --source"
|
|
|
|
|
echo " "
|
|
|
|
|
echo " source directory absolut path"
|
|
|
|
|
echo " "
|
|
|
|
|
echo " -r, --remote-host"
|
|
|
|
|
echo " remote ssh host"
|
|
|
|
|
echo " "
|
|
|
|
|
echo -e "${RED} 🐞${NONE} Usage: $0 -s /path/to/local/dir/ -d /path/to/remote/dir/ -r sshhost"
|
|
|
|
|
${RED}Example:${NONE} $0 -s /path/to/local/ -d /path/to/remote/ -r sshhost
|
|
|
|
|
"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while [[ $# -gt 0 ]]
|
|
|
|
|
do
|
|
|
|
|
key="$1"
|
|
|
|
|
case $key in
|
|
|
|
|
-h|--help)
|
|
|
|
|
Usage
|
|
|
|
|
# --- 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
|
|
|
|
|
;;
|
|
|
|
|
-d|--dest)
|
|
|
|
|
dirRemotePath=$2
|
|
|
|
|
shift # past argument
|
|
|
|
|
shift # past value
|
|
|
|
|
;;
|
|
|
|
|
-s|--source)
|
|
|
|
|
dirLocalPath=$2
|
|
|
|
|
shift
|
|
|
|
|
shift
|
|
|
|
|
;;
|
|
|
|
|
-r|--remote-host)
|
|
|
|
|
host=$2
|
|
|
|
|
shift
|
|
|
|
|
shift
|
|
|
|
|
;;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- 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 ;;
|
|
|
|
|
*)
|
|
|
|
|
# unknown option
|
|
|
|
|
POSITIONAL+=("$1") # save it in an array for later
|
|
|
|
|
shift
|
|
|
|
|
echo -e "${RED}✗ Unknown option: $1${NONE}"
|
|
|
|
|
usage
|
|
|
|
|
exit 1
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
set -- "${POSITIONAL[@]}"
|
|
|
|
|
|
|
|
|
|
if test -z "$dirLocalPath"; then
|
|
|
|
|
dirLocalPath=$defaultLocalPath
|
|
|
|
|
echo -e "${YELLOW}⚠ Local path:${NONE} ${dirLocalPath}${YELLOW} (default)${NONE}"
|
|
|
|
|
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:${NONE} ${dirLocalPath}"
|
|
|
|
|
echo -e "${GREEN}⚙️ Local path: ${dir_local}${NONE}"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if test -z "$dirRemotePath"; then
|
|
|
|
|
dirRemotePath=$defaultRemotePath
|
|
|
|
|
echo -e "${YELLOW}⚠ Remote path:${NONE} ${dirRemotePath}${YELLOW} (default)${NONE}"
|
|
|
|
|
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:${NONE} ${dirRemotePath}"
|
|
|
|
|
echo -e "${GREEN}⚙️ Remote path: ${dir_remote}${NONE}"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [ -z "$host" ]; then
|
|
|
|
|
host=$defaultHost
|
|
|
|
|
echo -e "${YELLOW}⚠ Remote host:${NONE} ${host}${YELLOW} (default)${NONE}"
|
|
|
|
|
if [[ -z "$host" ]]; then
|
|
|
|
|
host="$DEFAULT_HOST"
|
|
|
|
|
echo -e "${YELLOW}⚠ Remote host: ${host} (default)${NONE}"
|
|
|
|
|
else
|
|
|
|
|
echo -e "${GREEN}⚙️ Remote host:${NONE} ${host}"
|
|
|
|
|
echo -e "${GREEN}⚙️ Remote host: ${host}${NONE}"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [ $RETVAL -eq 0 ]; then
|
|
|
|
|
trap exit INT
|
|
|
|
|
function exit() {
|
|
|
|
|
echo -e ""
|
|
|
|
|
echo -e "${NONE}${CYAN}♻️ Réinitialisation du répo distant...${NONE}${GREY}"
|
|
|
|
|
echo -e "${NONE}\$> ${MAGENTA}ssh ${host} \"cd ${dirRemotePath}; git reset --hard\"${NONE}"
|
|
|
|
|
ssh $host "cd $dirRemotePath; git reset --hard"
|
|
|
|
|
trap cleanup INT TERM
|
|
|
|
|
|
|
|
|
|
echo -e "\n${NONE}${CYAN}🗑️ Suppression du cache${NONE}${GREY}"
|
|
|
|
|
echo -e "${NONE}\$> ${MAGENTA}ssh ${host} \"cd ${dirRemotePath}; composer front-cache-clear\"${NONE}"
|
|
|
|
|
ssh $host "cd $dirRemotePath; composer front-cache-clear"
|
|
|
|
|
echo -e "\n${BBLUE}⏳ Watching for changes...${NONE}"
|
|
|
|
|
echo -e "${BLUE}-----------------------------${NONE}"
|
|
|
|
|
|
|
|
|
|
echo -e "${NONE}${GREEN}✔️ Ciao !${NONE}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
syncfile () {
|
|
|
|
|
fileLocalPath=$1
|
|
|
|
|
fileRemotePath=${fileLocalPath/$dirLocalPath/$dirRemotePath}
|
|
|
|
|
echo -e "\n${NONE}${CYAN}🔄 Synchronisation du fichier ${YELLOW}${fileLocalPath/$dirLocalPath/}${NONE}"
|
|
|
|
|
echo -e "${NONE}\$> ${MAGENTA}scp ${fileLocalPath} ${host}:${fileRemotePath}${NONE}"
|
|
|
|
|
scp ${fileLocalPath} $host:$fileRemotePath
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo -e "\n${NONE}${BBLUE}⏳ En attente de modification${NONE}${GREY}"
|
|
|
|
|
echo -e "${NONE}${BLUE}-----------------------------${NONE}${GREY}"
|
|
|
|
|
|
|
|
|
|
num=0
|
|
|
|
|
while read fileLocalPath; do
|
|
|
|
|
if [ "$fileLocalPath" = "NoOp" ]; then
|
|
|
|
|
num=0
|
|
|
|
|
echo -e "\n${NONE}${CYAN}🗑️ Suppression du cache${NONE}${GREY}"
|
|
|
|
|
echo -e "${NONE}\$> ${MAGENTA}ssh ${host} \"cd ${dirRemotePath}; composer front-cache-clear\"${NONE}\n"
|
|
|
|
|
ssh $host "cd $dirRemotePath; composer front-cache-clear"
|
|
|
|
|
echo -e "\n${NONE}${BBLUE}⏳ En attente de modification${NONE}${GREY}"
|
|
|
|
|
echo -e "${NONE}${BLUE}-----------------------------${NONE}${GREY}"
|
|
|
|
|
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
|
|
|
|
|
num=$((num+1))
|
|
|
|
|
#echo -e "${NONE}${num} - ${fileLocalPath}"
|
|
|
|
|
syncfile $fileLocalPath $num &
|
|
|
|
|
sync_file "$file" &
|
|
|
|
|
fi
|
|
|
|
|
done < <(fswatch --batch-marker -0 --exclude '.git/' $dirLocalPath | xargs -0 -n 1 -I {})
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}⚠ ${NONE} Le script a rencontré une erreur"
|
|
|
|
|
echo "-----------------------------"
|
|
|
|
|
echo -e "${RED} 💀 Exit code:${NONE} $RETVAL"
|
|
|
|
|
exit $RETVAL
|
|
|
|
|
fi
|
|
|
|
|
done < <(fswatch --batch-marker -0 --exclude '.git/' "$dir_local" | tr '\0' '\n')
|
|
|
|
|