#!/bin/sh

# Dommage, on peut surveiller un dossier contenant des sous-dossiers accentués, mais pas directement un dossier accentué.
# http://stackoverflow.com/questions/22450292/how-to-encode-a-path-containing-spaces-in-a-cfstringref
# (et j'ai essayé de le convertir en toutes les fragrances d'UTF-8 avant de chercher sur internet).

mode=async
mode=sync # En fait avec Unison le mode async ne marche pas, car Unison verrouille l'arbo quand il travaille dessus; du coup impossible d'avoir deux Unison tournant en même temps sur la même arbo.

exec >> /tmp/p.log 2>&1

auSecours()
{
	moi="`basename "$0"`"
	cat >&2 <<TERMINE
# Utilisation: $moi [-n <nom de machine>] <source> <dest> [<dest>...]
TERMINE
	exit 1
}

analyserParametres()
{
	vars="source dests"
	source=
	dests=
	
	while [ $# -gt 0 ]
	do
		case "$1" in
			-n) shift ; nom="$1" ;;
			*)
				if [ -z "$vars" ]
				then
					dests="$dests;$1"
				else
					for i in $vars
					do
						eval $i="\"$1\""
						break
					done
					vars="`echo "$vars" | sed -e 's/[^ ]* //'`"
				fi
				;;
		esac
		shift
	done
	
	[ -z "$source" -o -z "$dests" ] && auSecours
	[ ! -d "$source" ] && echo "# $source inexistant." >&2 && exit 1
}

menage()
{
	[ -e "$T/pids" ] && kill `cat "$T/pids"` || true
	[ -z "$T" ] || rm -Rf "$T"
	exit 0
}

initDest()
{
	dest="$1"
	
	numeroDest="`expr $numeroDest + 1`"

	if [ $mode = sync ]
	then
		fichiertemps="$T/temps.$numeroDest"
		echo "255 999999 $fichiertemps $dest" > "$fichiertemps"
	fi

	pousse "$dest"
	
	[ $mode = async ] || return
	
	touch "$T/dest.$numeroDest"
	(
		tail -f "$T/dest.$numeroDest" | while read modif
		do
			# À FAIRE: nc -z pour savoir si on a quelqu'un au bout. Si non, mettre en file d'attente
			pousse "$dest"
		done
	) &
	echo $! >> "$T/pids"
}

mesurer()
{
	# On n'utilise pas time, car ça entremêle sortie du process et de time. La précision de date +%s nous suffit.
	t0="`date +%s`"
	"$@"
	r=$?
	t1="`date +%s`"
	echo "$r `expr $t1 - $t0` $fichiertemps $dest" > "$fichiertemps"
}

faireAsync()
{
	for f in "$T"/dest.*
	do
		echo 1 >> "$f"
	done
}

faireSync()
{
	# On trie les derniers résultats pour tenter en premier la destination qui, ayant réussi (état de sortie 0), a mis le moins de temps.
	# Coup de bol, parmi les différents états de sortie, le 1 (qui viendra se placer juste après le 0, et avant les autres cas d'erreur plus graves du genre impossible de joindre la cible) désigne une synchro partielle, 2 des erreurs non fatales, 3 un gros souci. Bref, les états sont bien triés.
	cat "$T"/temps.* | sort -n -k 1 -n -k 2 | while read dernierestatut derniertemps fichiertemps dest
	do
		pousse "$dest"
	done
}

if [ $mode = sync ]
then
	tracer() { mesurer "$@" ; }
	faire() { faireSync "$@" ; }
else
	tracer() { "$@" ; }
	faire() { faireAsync "$@" ; }
fi

pousse()
{
	dest="$1"
	export UNISONLOCALHOSTNAME
	tracer unison -batch -backups -maxbackups 3 "$source" "$dest"
}

analyserParametres "$@"

T="/tmp/temp.$$.partages"
UNISONLOCALHOSTNAME="$nom"
export UNISONLOCALHOSTNAME
rm -Rf "$T"
mkdir "$T"
numeroDest=0

trap menage INT
trap menage TERM

echo "$dests" | tr \; '\012' | while read dest
do
	initDest "$dest"
done

fswatch -e ".unison.*.unison.tmp" -e ".bak.*" "$source" | while read f
do
	echo "CHANGEMENT $f"
	faire
done
