#!/bin/sh

DEBUG=$(git config --type bool --default false netbsd.debug)
if $DEBUG; then
	echo BEGIN update $$ "$@"
	trap 'echo END update $$' EXIT HUP INT TERM
fi

set -Ceu
if $DEBUG; then
	set -x
fi

ref=$1
old=$2
new=$3

if $DEBUG; then
	i=0
	while [ "$i" -lt "${GIT_PUSH_OPTION_COUNT:-0}" ]; do
		eval echo [update] GIT_PUSH_OPTION_$i=\$GIT_PUSH_OPTION_$i
		i=$((i + 1))
	done
fi

case ${GIT_NAMESPACE-} in
'')
	remote=origin
	prefix=
	;;
draft)
	remote=draft
	prefix=topics/
	export GIT_CINNABAR_EXPERIMENTS=branch # XXX
	;;
*)	echo 'forbidden namespace' >&2
	exit 1
	;;
esac

# Allow only refs/heads/* to be updated.
#
# In the future, we should consider:
#
#       refs/tags/*                     git cinnabar tag
#	refs/namespaces/dev/$DEV/*      developer namespace
#
case $ref in
refs/heads/*)
	ref=refs/heads/${prefix}${ref#refs/heads/}
	;;
*)	echo 'only head updates are allowed' >&2
	exit 1
	;;
esac

# Lock the cinnabar bridge so pushes don't happen concurrently.  If the
# system crashes in the middle, no big deal -- the lock will be broken,
# but no concurrent pushes will be happening anyway.  The lock will be
# released when this process exits (specifically, when all file
# descriptors referencing this open of the lock file are closed).
#
# This doesn't make batch ref updates atomic -- it only ensures that
# each ref update is forwarded on to Mercurial in serial and no
# concurrent pushes attempts to update cinnabar metadata
# simultaneously.  It's possible that metadata updates by git-cinnabar
# are already safe but let's play it safer.
#
# If the lock can't be acquired immediately, print message to say where
# the holdup is coming from.
#
# Make sure to preserve file permissions according to
# core.sharedRepository so in a group-shared repository, other members
# of the group can also take the lock.
umask=$(umask)
sharedrepo=$(git config --default false core.sharedRepository | tr A-Z a-z)
case $sharedrepo in
false|umask|0)
	;;
group|true|1)
	umask 002
	;;
0???)
	umask $sharedrepo
	;;
*)
	echo invalid core.sharedRepository setting >&2
	;;
esac
exec 3>>$GIT_DIR/cinnabridge.lock
umask $umask
if ! flock -n 3 3<&3; then
	echo 'waiting for Mercurial bridge lock...' >&2
	flock 3 3<&3
	echo 'Mercurial bridge lock acquired' >&2
fi

# Push back to the origin via git-cinnabar.  Set the environment
# variable TNFREPO_HG_GIT_PUSH while doing this so that any hg hooks
# know this is coming from a git-push and won't try to recursively come
# back to the git repo to git-fetch.
TNFREPO_HG_GIT_PUSH= \
git push "$remote" "$new:$ref" || exit $?
