File sync with fswatch and rsync
Some projects I work on require that I use a remote web server. PHPStorm is my IDE of choice and, up until now, I've had it SFTP the files to the remote host. But that has been less than ideal as it still feels slow and I could swear it isn't keeping the remote connection alive leading to quite a lag in uploads.
As a replacement I'm going to trial using fswatch to record a list of changed files which is then handed over to rsync to upload. To speed things up I configure SSH on macOS to re-use an existing session. With this enabled further connections, including rsync, are a lot snappier.
To do that edit ~/.ssh/config
adding something similar to the following:
Host example.org
ControlMaster auto
ControlPath /tmp/%h%p%r
I then created a bash script that performs the following actions:
- Performs an initial rsync with the remote host in order to ensure we're working from a clean slate
- Watches for changes to files in
/Users/alistair/Code/example.org/
excluding.idea
and.git
folders - Adds the path to all changed files to a temporary file
- Generates a relative version of the paths
- Calls rsync with the list of files
- Generates a macOS Notification Center alert letting you know it's done
Now, if you keep an SSH session open elsewhere, rsync will re-use this which, when combined with the list of files to upload, should result in speedier uploads.
It's early days yet for this set up but initial tests seem promising. Shell scripting like this certainly isn't my forte so I'll be the first one to say that there's probably a lot of optimisation that could be done. But it works for me.
#!/usr/bin/env bash
rm --force /tmp/example.org-rsync.txt
rm --force /tmp/example.org-rsync-relative.txt
echo "Starting initial sync..."
rsync --verbose -azP --delete --exclude='.git/' --exclude='.idea/' --exclude='.DS_Store' --exclude='tmp/' /Users/alistair/Code/example.org/ user@example.org:/var/www/example.org
echo ""
echo "Watching..."
fswatch --exclude="___jb_" --exclude=".idea" --exclude=".git" --batch-marker=EOF -xn /Users/alistair/Code/example.org/ | while read file event; do
if [ $file = "EOF" ]; then
printf "%s\n" "${list[@]}" > /tmp/example.org-rsync.txt
sed -e "s,/Users/alistair/Code/example.org/,," /tmp/example.org-rsync.txt > /tmp/example.org-rsync-relative.txt
echo "Beginning sync..."
rsync --verbose --files-from=/tmp/example.org-rsync-relative.txt /Users/alistair/Code/example.org/ user@example.org:/var/www/example.org
osascript -e 'display notification "rsync complete!" with title "example.org"'
echo "sync completed"
echo "Watching..."
list=()
else
list+=($file)
fi
done