#!/usr/bin/env bash

#et -x

# On using rsync for really efficient backups:
# http://www.mikerubel.org/computers/rsync_snapshots/

# On setting up a windows machine with an rsync daemon (service) :
# http://www.gaztronics.net/rsync.php

set -u

export PATH=/bin:/usr/bin:/sbin:/usr/sbin

USE_COMPRESSION=false
RSYNC_OPTS=""
VERBOSE=0

if tty -s
then
	ON_TTY=true
	#TTY_OPTS="-v --progress --stats"
	TTY_OPTS="--progress --stats"
else
	ON_TTY=false
	TTY_OPTS="--stats"
fi

while [ "$#" -ge 1 ]
do
	case "$1" in
		--rsync-opts)
			RSYNC_OPTS="$2"
			shift
			;;
		--srcdir)
			SRCDIR="$2"
			shift
			;;
		--dstdir)
			DSTDIR="$2"
			shift
			;;
		--num-to-keep)
			NUM_TO_KEEP="$2"
			shift
			;;
		--verbose)
			VERBOSE=$[$VERBOSE+1]
			;;
		--use-compression)
			USE_COMPRESSION=true
			;;
		--dan)
			SRCDIR=/big
			DSTDIR=/backups/dan-rsync-backups
			NUM_TO_KEEP=60
			USE_COMPRESSION=false
			;;
		--gg)
			SRCDIR=rsync://192.168.1.201/GG
			DSTDIR=/backups/gg-rsync-backups
			NUM_TO_KEEP=60
			#USE_COMPRESSION=true
			# Guangyu's machine tends to overheat if we enable compression
			USE_COMPRESSION=false
			;;
		*)
			echo "$0: Illegal option: $1" 1>&2
			exit 1
			;;
	esac
	shift
done

if [ "${SRCDIR:-''}" = "" ]
then
	echo Sorry, you must give a source directory with --srcdir
fi

if [ "${DSTDIR:-''}" = "" ]
then
	echo Sorry, you must give a destination directory with --dstdir
fi

if [ "$USE_COMPRESSION" = true ]
then
	COMPRESS_FLAG=-z
else
	COMPRESS_FLAG=""
fi

if ! mkdir -p "$DSTDIR"
then
	echo Sorry, mkdir -p "$DSTDIR" failed 1>&2
	exit 1
fi

if ! cd "$DSTDIR"
then
	echo Sorry, cd "$DSTDIR" failed 1>&2
	exit 1
fi

if [ -d backup."$NUM_TO_KEEP" ]
then
	# make room for some sliding, if the last directory already exists
	rm -rf backup."$NUM_TO_KEEP"
fi

if [ -d "backup.1.complete" ]
then
	# slide them up a notch
	for backup_no in $(seq $[$NUM_TO_KEEP-1] -1 1)
	do
		if [ "$VERBOSE" -ge 1 ]
		then
			echo Checking backup $backup_no...
		fi
		if [ -d "backup.$backup_no.complete" ]
		then
			if [ "$VERBOSE" -ge 1 ]
			then
				echo Sliding backup $backup_no...
			fi
			backup_no_plus_1="$[$backup_no+1]"
			mv "backup.$backup_no.complete" "backup.$backup_no_plus_1.complete"
			if [ -d "backup.$backup_no" ]
			then
				(
					echo "Both backup.$backup_no and backup.$backup_no.complete detected"
					echo "Will keep backup.$backup_no.complete, but delete backup.$backup_no"
				) 1>&2
				rm -rf "backup.$backup_no"
			fi
		fi
	done
	if ! mkdir backup.1
	then
		echo Sorry, mkdir backup.1 failed 1>&2
		exit 1
	fi
elif [ -d backup.1 ]
then
	(
		echo "Incomplete backup detected - instead of sliding backups up a notch, instead"
		echo "we'll try to get a complete backup using the prior incomplete one as"
		echo "a starting point..."
	) 1>&2
else
	if ! mkdir backup.1
	then
		echo Sorry, mkdir backup.1 failed 1>&2
		exit 1
	fi
fi

echo "Backing up $SRCDIR to $DSTDIR..." 1>&2

rsync \
	$RSYNC_OPTS \
	-a \
	$TTY_OPTS \
	$COMPRESS_FLAG \
	--delete \
	--link-dest=../backup.2.complete "$SRCDIR"/ backup.1
rsync_exit_status="$?"
# 24 means a file vanished from the initial file list before it could be transferred, but that's OK.
# 23 means some files couldn't be transferred - EG, because some pathnames were too long.
case "$rsync_exit_status" in
	0|23|24)
		mv backup.1 backup.1.complete
		;;
	*)
		echo rsync failed with exit status "$rsync_exit_status", not "mv'ing"
		;;
esac