2025-10-22 10:46:36 +03:00
|
|
|
#!/bin/bash
|
|
|
|
|
|
|
|
|
|
# This script is used to sync a project from
|
|
|
|
|
# a remote server to a local machine.
|
|
|
|
|
|
2025-11-06 17:56:48 +02:00
|
|
|
# Get current script real directory (follow symlinks)
|
|
|
|
|
SCRIPT_PATH="$(realpath "$0")"
|
|
|
|
|
SCRIPT_DIR="$(dirname "$SCRIPT_PATH")"
|
2025-12-07 23:12:28 +02:00
|
|
|
|
2026-01-28 20:04:24 +02:00
|
|
|
# Source shared variables
|
|
|
|
|
source "$SCRIPT_DIR/shared.sh"
|
|
|
|
|
|
|
|
|
|
ARCHIVE_NAME="sync.tar.gz"
|
2026-01-17 16:49:25 +02:00
|
|
|
|
2025-12-07 23:12:28 +02:00
|
|
|
# Parse command line arguments
|
|
|
|
|
SFTP_ONLY=false
|
2026-01-17 16:17:24 +02:00
|
|
|
FILES_ONLY=false
|
2026-01-23 17:37:04 +02:00
|
|
|
GIT_ONLY=false
|
2026-01-17 16:17:24 +02:00
|
|
|
|
2025-12-07 23:12:28 +02:00
|
|
|
for arg in "$@"; do
|
2026-01-22 15:32:27 +02:00
|
|
|
case "$arg" in
|
|
|
|
|
-h | --help)
|
|
|
|
|
cat "$SCRIPT_DIR/MANUAL"
|
|
|
|
|
exit 0
|
|
|
|
|
;;
|
|
|
|
|
--sftp-only)
|
|
|
|
|
SFTP_ONLY=true
|
|
|
|
|
echo -e "${YELLOW}SFTP only mode enabled${NC}"
|
|
|
|
|
;;
|
|
|
|
|
--files-only)
|
|
|
|
|
FILES_ONLY=true
|
|
|
|
|
echo -e "${YELLOW}Files only mode enabled${NC}"
|
|
|
|
|
;;
|
2026-01-23 17:37:04 +02:00
|
|
|
--git)
|
|
|
|
|
GIT_ONLY=true
|
|
|
|
|
echo -e "${YELLOW}Git clone mode enabled${NC}"
|
|
|
|
|
;;
|
2026-01-22 15:32:27 +02:00
|
|
|
esac
|
2025-12-07 23:12:28 +02:00
|
|
|
done
|
2025-11-06 17:56:48 +02:00
|
|
|
|
2025-12-04 13:39:57 +02:00
|
|
|
# Function to add entry to .gitignore if not already present
|
|
|
|
|
add_to_gitignore() {
|
2026-01-22 15:32:27 +02:00
|
|
|
local entry="$1"
|
|
|
|
|
cat .gitignore | grep "$entry" >/dev/null 2>&1
|
|
|
|
|
if [ $? -ne 0 ]; then
|
|
|
|
|
echo "$entry" >>.gitignore
|
|
|
|
|
echo -e "${BLUE}Added $entry to .gitignore${NC}"
|
|
|
|
|
else
|
|
|
|
|
echo -e "${YELLOW}$entry already is inside of .gitignore file${NC}"
|
|
|
|
|
fi
|
2025-12-04 13:39:57 +02:00
|
|
|
}
|
|
|
|
|
|
2025-10-22 10:46:36 +03:00
|
|
|
echo -e "${BLUE}=== Project Sync Configuration ===${NC}"
|
|
|
|
|
echo ""
|
|
|
|
|
|
2025-12-04 13:30:00 +02:00
|
|
|
# Check if config is predefined (for testing usually)
|
|
|
|
|
if [ -f ".sync-credentials" ]; then
|
2026-01-22 15:32:27 +02:00
|
|
|
source ".sync-credentials"
|
2025-12-04 13:30:00 +02:00
|
|
|
else
|
2026-01-22 15:32:27 +02:00
|
|
|
# Prompt for configuration (password before path for SSH resolution)
|
|
|
|
|
read -p "Server user@host (e.g., leo@server.com): " SERVER_HOST
|
|
|
|
|
read -sp "SSH Password: " SSH_PASSWORD
|
|
|
|
|
echo ""
|
|
|
|
|
read -p "Server project path (default: ~/public_leo): " SERVER_PROJECT_PATH
|
|
|
|
|
read -p "Local folder path (e.g., Delta Pharmacy): " LOCAL_FOLDER
|
|
|
|
|
echo ""
|
2025-12-04 13:30:00 +02:00
|
|
|
fi
|
2025-10-22 10:46:36 +03:00
|
|
|
|
2026-01-17 16:49:25 +02:00
|
|
|
# Default path to ~/public_leo if empty
|
|
|
|
|
if [ -z "$SERVER_PROJECT_PATH" ]; then
|
2026-01-22 15:32:27 +02:00
|
|
|
SERVER_PROJECT_PATH="~/public_leo"
|
2026-01-17 16:49:25 +02:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Resolve ~ to full path via SSH
|
|
|
|
|
if [[ "$SERVER_PROJECT_PATH" == ~* ]]; then
|
2026-01-22 15:32:27 +02:00
|
|
|
echo "Resolving path..."
|
|
|
|
|
SERVER_PROJECT_PATH=$(sshpass -p "${SSH_PASSWORD}" ssh $SSH_OPTS ${SERVER_HOST} "cd ${SERVER_PROJECT_PATH} && pwd")
|
|
|
|
|
if [ $? -ne 0 ]; then
|
|
|
|
|
echo -e "${RED}Failed to resolve path${NC}"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
echo -e "${GREEN}Resolved to: ${SERVER_PROJECT_PATH}${NC}"
|
2026-01-17 16:49:25 +02:00
|
|
|
fi
|
|
|
|
|
|
2025-12-04 13:30:00 +02:00
|
|
|
# Validate required variables (all except password)
|
|
|
|
|
if [ -z "$SERVER_HOST" ]; then
|
2026-01-22 15:32:27 +02:00
|
|
|
echo -e "${RED}Error: SERVER_HOST is not set${NC}"
|
|
|
|
|
exit 1
|
2025-12-04 13:30:00 +02:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [ -z "$SERVER_PROJECT_PATH" ]; then
|
2026-01-22 15:32:27 +02:00
|
|
|
echo -e "${RED}Error: SERVER_PROJECT_PATH is not set${NC}"
|
|
|
|
|
exit 1
|
2025-12-04 13:30:00 +02:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [ -z "$LOCAL_FOLDER" ]; then
|
2026-01-22 15:32:27 +02:00
|
|
|
echo -e "${RED}Error: LOCAL_FOLDER is not set${NC}"
|
|
|
|
|
exit 1
|
2025-12-04 13:30:00 +02:00
|
|
|
fi
|
2025-10-22 10:46:36 +03:00
|
|
|
|
2026-01-28 20:04:24 +02:00
|
|
|
# Git clone mode - delegate to sync-git-project.sh
|
2026-01-23 17:37:04 +02:00
|
|
|
if [ "$GIT_ONLY" = true ]; then
|
2026-01-28 20:04:24 +02:00
|
|
|
"$SCRIPT_DIR/sync-git-project.sh" \
|
|
|
|
|
"$SERVER_HOST" \
|
|
|
|
|
"$SSH_PASSWORD" \
|
|
|
|
|
"$SERVER_PROJECT_PATH" \
|
|
|
|
|
"$LOCAL_FOLDER"
|
|
|
|
|
exit $?
|
2026-01-23 17:37:04 +02:00
|
|
|
fi
|
|
|
|
|
|
2026-01-17 16:49:25 +02:00
|
|
|
# Sync terminal info on full sync (no flags)
|
|
|
|
|
if [ "$SFTP_ONLY" = false ] && [ "$FILES_ONLY" = false ]; then
|
2026-01-22 15:32:27 +02:00
|
|
|
# Detect terminal type
|
|
|
|
|
if [[ "$TERM" == *"ghostty"* ]]; then
|
|
|
|
|
TERM_TYPE="xterm-ghostty"
|
|
|
|
|
elif [[ "$TERM" == *"kitty"* ]]; then
|
|
|
|
|
TERM_TYPE="xterm-kitty"
|
|
|
|
|
else
|
|
|
|
|
TERM_TYPE=""
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [ -n "$TERM_TYPE" ]; then
|
|
|
|
|
echo "Syncing terminal info ($TERM_TYPE)..."
|
|
|
|
|
infocmp -x "$TERM_TYPE" | sshpass -p "${SSH_PASSWORD}" ssh $SSH_OPTS ${SERVER_HOST} -- tic -x -
|
|
|
|
|
echo -e "${GREEN}Terminal info synced${NC}"
|
|
|
|
|
else
|
|
|
|
|
echo -e "${YELLOW}Warning: Unknown terminal ($TERM), skipping terminfo sync${NC}"
|
|
|
|
|
fi
|
2026-01-17 16:49:25 +02:00
|
|
|
fi
|
|
|
|
|
|
2025-12-04 13:30:00 +02:00
|
|
|
# Start sync process
|
2025-10-22 10:46:36 +03:00
|
|
|
echo "Starting project sync..."
|
|
|
|
|
|
|
|
|
|
# Step 1: SSH into server and create tar archive
|
|
|
|
|
echo "Creating archive on server..."
|
2026-01-17 16:17:24 +02:00
|
|
|
if [ "$FILES_ONLY" = true ]; then
|
2026-01-22 15:32:27 +02:00
|
|
|
sshpass -p "${SSH_PASSWORD}" ssh $SSH_OPTS ${SERVER_HOST} "cd ${SERVER_PROJECT_PATH} && tar -czf ../${ARCHIVE_NAME} --exclude='node_modules' --exclude='vendor' --exclude='uploads' ."
|
2026-01-17 16:17:24 +02:00
|
|
|
else
|
2026-01-22 15:32:27 +02:00
|
|
|
sshpass -p "${SSH_PASSWORD}" ssh $SSH_OPTS ${SERVER_HOST} "cd ${SERVER_PROJECT_PATH} && tar -czf ../${ARCHIVE_NAME} --exclude='uploads' ."
|
2026-01-17 16:17:24 +02:00
|
|
|
fi
|
2025-10-22 10:46:36 +03:00
|
|
|
|
|
|
|
|
if [ $? -ne 0 ]; then
|
2026-01-22 15:32:27 +02:00
|
|
|
echo -e "${RED}Failed to create archive on server${NC}"
|
|
|
|
|
exit 1
|
2025-10-22 10:46:36 +03:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo -e "${GREEN}Archive created successfully${NC}"
|
|
|
|
|
|
|
|
|
|
# Step 2: Create local folder if it doesn't exist
|
|
|
|
|
mkdir -p "${LOCAL_FOLDER}"
|
|
|
|
|
|
|
|
|
|
# Step 3: Copy archive from server to local
|
|
|
|
|
echo "Copying archive to local machine..."
|
2026-01-17 16:58:17 +02:00
|
|
|
sshpass -p "${SSH_PASSWORD}" rsync -az --info=progress2 -e "ssh $SSH_OPTS" ${SERVER_HOST}:~/${ARCHIVE_NAME} "${LOCAL_FOLDER}/"
|
2025-10-22 10:46:36 +03:00
|
|
|
|
|
|
|
|
if [ $? -ne 0 ]; then
|
2026-01-22 15:32:27 +02:00
|
|
|
echo -e "${RED}Failed to copy archive${NC}"
|
|
|
|
|
exit 1
|
2025-10-22 10:46:36 +03:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo -e "${GREEN}Archive copied successfully${NC}"
|
|
|
|
|
|
|
|
|
|
# Step 4: Extract archive locally
|
|
|
|
|
echo "Extracting archive..."
|
|
|
|
|
cd "${LOCAL_FOLDER}"
|
|
|
|
|
tar -xzf ${ARCHIVE_NAME}
|
|
|
|
|
|
|
|
|
|
if [ $? -ne 0 ]; then
|
2026-01-22 15:32:27 +02:00
|
|
|
echo -e "${RED}Failed to extract archive${NC}"
|
|
|
|
|
exit 1
|
2025-10-22 10:46:36 +03:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo -e "${GREEN}Archive extracted successfully${NC}"
|
|
|
|
|
|
|
|
|
|
# Step 5: Clean up - delete local archive
|
|
|
|
|
echo "Cleaning up local archive..."
|
|
|
|
|
rm ${ARCHIVE_NAME}
|
|
|
|
|
|
|
|
|
|
# Step 6: Clean up - delete server archive
|
|
|
|
|
echo "Cleaning up server archive..."
|
2026-01-17 16:49:25 +02:00
|
|
|
sshpass -p "${SSH_PASSWORD}" ssh $SSH_OPTS ${SERVER_HOST} "rm ~/${ARCHIVE_NAME}"
|
2025-10-22 10:46:36 +03:00
|
|
|
|
2025-11-06 17:56:48 +02:00
|
|
|
echo -e "${GREEN}File sync complete!${NC}"
|
2025-10-22 10:46:36 +03:00
|
|
|
|
2026-01-17 16:17:24 +02:00
|
|
|
# Skip helper scripts and config generation in files-only mode
|
|
|
|
|
if [ "$FILES_ONLY" = true ]; then
|
2026-01-22 15:32:27 +02:00
|
|
|
exit 0
|
2026-01-17 16:17:24 +02:00
|
|
|
fi
|
|
|
|
|
|
2025-10-22 10:46:36 +03:00
|
|
|
# Create .vscode sftp.json file
|
|
|
|
|
mkdir -p .vscode
|
|
|
|
|
|
|
|
|
|
# Extract username and host from SERVER_HOST
|
|
|
|
|
USERNAME="${SERVER_HOST%@*}"
|
|
|
|
|
HOST="${SERVER_HOST#*@}"
|
|
|
|
|
|
|
|
|
|
echo "{
|
|
|
|
|
\"name\": \"${LOCAL_FOLDER}\",
|
|
|
|
|
\"host\": \"${HOST}\",
|
|
|
|
|
\"protocol\": \"sftp\",
|
|
|
|
|
\"port\": 22,
|
|
|
|
|
\"username\": \"${USERNAME}\",
|
|
|
|
|
\"password\": \"${SSH_PASSWORD}\",
|
|
|
|
|
\"remotePath\": \"${SERVER_PROJECT_PATH}\",
|
|
|
|
|
\"uploadOnSave\": true,
|
|
|
|
|
\"useTempFile\": false,
|
|
|
|
|
\"openSsh\": false,
|
|
|
|
|
\"ignore\": [
|
|
|
|
|
\".vscode\",
|
|
|
|
|
\".DS_Store\",
|
|
|
|
|
\"node_modules\",
|
|
|
|
|
\"vendor\",
|
|
|
|
|
\"storage\",
|
|
|
|
|
\"uploads\",
|
|
|
|
|
\"temp\",
|
|
|
|
|
\"cache\",
|
|
|
|
|
\"sitepress-multilingual-cms\"
|
|
|
|
|
]
|
|
|
|
|
}" >.vscode/sftp.json
|
|
|
|
|
|
|
|
|
|
echo -e "${GREEN}.vscode/sftp.json created successfully${NC}"
|
|
|
|
|
|
2025-11-14 22:57:27 +02:00
|
|
|
# Go through scripts, add variables and add them to project folder
|
2025-12-07 23:12:28 +02:00
|
|
|
if [ "$SFTP_ONLY" = true ]; then
|
2025-12-16 16:06:09 +02:00
|
|
|
# Sftp only scripts
|
2026-01-22 15:32:27 +02:00
|
|
|
scripts=("local-remote.sh" "remote-local.sh" "sftp-watch.sh" "ssh.sh")
|
2025-12-07 23:12:28 +02:00
|
|
|
else
|
2025-12-16 16:06:09 +02:00
|
|
|
# All scripts
|
2026-01-22 15:32:27 +02:00
|
|
|
scripts=("watch-build.sh" "local-remote.sh" "remote-local.sh" "sftp-watch.sh" "ssh.sh" "split-conflicts.sh")
|
2025-12-07 23:12:28 +02:00
|
|
|
fi
|
2025-11-14 22:57:27 +02:00
|
|
|
|
|
|
|
|
for script in "${scripts[@]}"; do
|
2026-01-22 15:32:27 +02:00
|
|
|
# Add variables to script
|
|
|
|
|
echo "
|
2025-11-19 09:53:54 +02:00
|
|
|
#!/bin/bash
|
|
|
|
|
set -e
|
|
|
|
|
|
|
|
|
|
# Configuration
|
|
|
|
|
SERVER_USER=\"${USERNAME}\"
|
|
|
|
|
SERVER_HOST=\"${HOST}\"
|
|
|
|
|
SERVER_PASSWORD=\"${SSH_PASSWORD}\"
|
|
|
|
|
SERVER_PATH=\"${SERVER_PROJECT_PATH}/\"
|
2025-12-16 16:06:09 +02:00
|
|
|
REMOTE_PROGRESS=\".remote-in-progress\"
|
2026-01-22 15:32:27 +02:00
|
|
|
" >"${script}"
|
2025-11-14 22:57:27 +02:00
|
|
|
|
2026-01-22 15:32:27 +02:00
|
|
|
# Append the rest of the upload core build script
|
|
|
|
|
cat "${SCRIPT_DIR}/scripts/${script}" >>"${script}"
|
|
|
|
|
echo "${script} created successfully"
|
2025-11-14 22:57:27 +02:00
|
|
|
|
2026-01-22 15:32:27 +02:00
|
|
|
# Skip .gitignore updates when --sftp-only flag is present
|
|
|
|
|
if [ "$SFTP_ONLY" = false ]; then
|
|
|
|
|
add_to_gitignore "${script}"
|
|
|
|
|
fi
|
2025-11-14 22:57:27 +02:00
|
|
|
done
|
2025-11-10 15:15:44 +02:00
|
|
|
|
2025-12-07 23:12:28 +02:00
|
|
|
# Upload lazygit to server (skip when --sftp-only flag is present)
|
|
|
|
|
if [ "$SFTP_ONLY" = false ]; then
|
2026-01-22 15:32:27 +02:00
|
|
|
echo "Uploading lazygit to server..."
|
2025-11-10 15:15:44 +02:00
|
|
|
|
2026-01-22 15:32:27 +02:00
|
|
|
sshpass -p "${SSH_PASSWORD}" scp $SSH_OPTS "${SCRIPT_DIR}/lazygit" ${SERVER_HOST}:${SERVER_PROJECT_PATH}
|
|
|
|
|
echo -e "${GREEN}lazygit uploaded successfully${NC}"
|
2025-11-10 15:15:44 +02:00
|
|
|
|
2026-01-22 15:32:27 +02:00
|
|
|
# Add lazygit to .gitignore
|
|
|
|
|
add_to_gitignore "lazygit"
|
2025-12-07 23:12:28 +02:00
|
|
|
fi
|