#!/bin/sh
: ${SNAP_SRC:=.}

usage() {
	printf >&2 "Usage: %s: [-S SNAP_SRC] [-D SNAP_DST] [-] [RSYNC_ARGS]\n" $(basename "$0")
	exit 2
}

die() {
	printf "%s" "$*"
	exit 1
}

while getopts S:D: opt; do
	case $opt in
		(S) SNAP_SRC=$OPTARG;;
		(D) SNAP_DST=$OPTARG;;
		(?) usage;;
		(h) usage;;
	esac
done
shift $(($OPTIND - 1))

case $1 in
	(-) shift;;
	(--) shift;;
esac

if test -z "$SNAP_DST"; then
	echo >&2 "SNAP_DST is required either as env var or argument"
	usage
fi

: ${SNAP_WRITESRC:=$SNAP_SRC}

check_local() {
	for m in $SNAP_WRITESRC/.snapshot.[0-9]*; do
		test -f "$m" || continue
		test -n "$mark" && die "duplicate snapshot mark"
		mark=$m
	done

	test -f "$mark" || die "snapshot mark not found"
	ts=${mark##*.}
}

check_remote() {
	snap.list "$SNAP_SRC/" | while read m; do
		test -n "$ts" && die "duplicate snapshot mark"
		ts=$m
	done
	test -n "$ts" || die "snapshot mark not found"
}

rs() {
	rsync -aA --delete $RSYNC_ARGS "$@"
}

push_remote() {
	# remote
	case "$SNAP_DST" in
		(*.push) ;;
		(*) SNAP_DST=${SNAP_DST}.push;;
	esac
	rs "$@" --exclude=/${mark##*/} "$SNAP_SRC/" "$SNAP_DST/" && \
	rs "$@" "$SNAP_WRITESRC/${mark##*/}" "$SNAP_DST/"
}

push_local() {
	test -d "$SNAP_DST" || die "destination not a directory: ${SNAP_DST}"
	snapshot=$(snap.list "$SNAP_DST/" | tail -1)
	if test -n "$snapshot"; then
		link=${SNAP_DST}/${snapshot}
		mkdir -p "${SNAP_DST}/batch" || exit $?
		rs "$@" --write-batch="${SNAP_DST}/batch/${snapshot}-$ts" "--link-dest=$link/" "$SNAP_SRC/" "$SNAP_DST/$ts/" || exit $?
	else
		rs "$@" "$SNAP_SRC/" "$SNAP_DST/$ts/" || exit $?
	fi
	touch "${SNAP_DST}/${mark##*/}"
}

case "$SNAP_SRC" in
	(*:*) check_remote;;
	(*) check_local;;
esac

case "$SNAP_DST" in
	(rsync:*) push_remote "$@";;
	(*::*) push_remote "$@";;
	(*:*) die "pushing via remote shell directly not supported, use -e with rsync:// instead";;
	(*) push_local "$@";;
esac