#!/bin/sh
#
# An example hook script to mail out commit update information.
# It also blocks tags that aren't annotated.
# Called by git-receive-pack with arguments: refname sha1-old sha1-new
#
# To enable this hook:
# (1) make this file executable by "chmod +x update".
# (2) define the recipient e-mail address in $GIT_DIR/mailto file.
# (3) define the project description in $GIT_DIR/description file.
# (4) optionally define email charset in $GIT_DIR/charset file.
#

LANG=C
LANGUAGE=C
LC_ALL=C
export LANG LANGUAGE LC_ALL

mailto="$(
	cat $GIT_DIR/mailto 2>/dev/null |
	sed -e 's/^[[:space:]]\+//' -e 's/[[:space:]]\+$//' |
	tr -s '\n' , |
	sed -e 's/^,\+//' -e 's/,\+$//'
)"

ref_type="$(git cat-file -t "$3")" || exit 1

# Only allow annotated tags in a shared repo
# Remove this code to treat dumb tags the same as everything else
case "$1,$ref_type" in
refs/tags/*,commit)
	echo >&2 "*** Un-annotated tags are not allowed in this repo"
	echo >&2 "*** Use 'git tag [ -a | -s ]' for tags you want to propagate."
	exit 1
	;;
refs/tags/*,tag)
	echo "### Pushing version '${1##refs/tags/}' to the masses" >&2
	;;
esac

[ -n "$mailto" ] || exit 0

exit_handler()
{
	local rc=$?
	trap - EXIT
	rm -rf -- "$workdir"
	exit $rc
}
workdir="$(mktemp -dt git-update.XXXXXXXX)" || exit 1
trap exit_handler HUP PIPE INT QUIT TERM EXIT

MSG="$workdir/message"
DIFF="$workdir/diff"

DIFFMAX=65536
date_format="%F %T %z"
git_dir="$(readlink -e "$GIT_DIR")"
project="$(head -n1 $GIT_DIR/description)"
charset="$(head -n1 $GIT_DIR/charset 2>/dev/null)"

cat >"$MSG" <<EOF
To: $mailto
Subject: [git update] $project: ${1##refs/}
Content-Type: text/plain${charset:+; charset=$charset}
X-git-dir: $git_dir
X-git-description: $project

Update of $git_dir

EOF

if expr "$2" : '0*$' >/dev/null; then
	# new ref
	case "$1" in
	refs/tags/*)
		# a pushed and annotated tag (usually) means a new version
		tag="${1##refs/tags/}"
		if [ "$ref_type" = tag ]; then
			TAG="$workdir/tag"
			git cat-file tag "$3" >"$TAG"
			tagger="$(sed -ne '4s/^tagger \([^>]\+>\).*/\1/p' <"$TAG")"
			ts="$(sed -ne '4s/^tagger [^>]\+>[^0-9]*\([0-9]\+\).*/\1/p' <"$TAG")"
			date="$(date --date="1970-01-01 00:00:00 $ts seconds" +"$date_format")"
			echo "Tag '$tag' created by $tagger at $date"
			echo "with the following message:"
			git cat-file tag "$3" |sed -n '5,$p'
			echo =======
			echo
		fi
		prev="$(git describe "$3^" 2>/dev/null| sed 's/-g.*//')"
		# the first tag in a repo will yield no $prev
		if [ -z "$prev" ]; then
			echo "Changes since the dawn of time:"
			git rev-list --pretty "$3"
		else
			echo "Changes since \`$prev':"
			git diff -M "$3" "^$prev" >"$DIFF"
			git diff -M --stat "$3" "^$prev"
			echo
			git rev-list --pretty "$3" "^$prev"
			echo
			SIZE="`wc -c $DIFF | sed 's/^[^0-9]*\([0-9]*\).*$/\1/'`"
			if [ $SIZE -ge $DIFFMAX ]; then
				echo "Full changes since \`$prev' are too large ($SIZE bytes)"
			else
				echo "Full changes since \`$prev' follow:"
				cat "$DIFF"
			fi
		fi
		;;

	refs/heads/*)
		branch="${1##refs/heads/}"
		echo "New branch \`$branch' available with the following commits:"
		git rev-list --pretty "$3" $(git rev-parse --not --all)
		;;
	esac
else
	base="$(git merge-base "$2" "$3")"
	prev="$(git describe "$base" 2>/dev/null)" || prev="$base"
	if [ -z "$prev" ]; then
		echo "Changes since the dawn of time:"
		git rev-list --pretty "$3"
	else
		case "$base" in
		"$2")
			echo "Changes since \`$prev':"
			;;
		*)
			echo "Changes since common ancestor \`$prev':"
			;;
		esac
		git diff -M "$3" "^$base" >"$DIFF"
		git diff -M --stat "$3" "^$base"
		echo
		git rev-list --pretty "$3" "^$base"
		echo
		SIZE="`wc -c $DIFF | sed 's/^[^0-9]*\([0-9]*\).*$/\1/'`"
		if [ $SIZE -ge $DIFFMAX ]; then
			echo "Full changes since \`$prev' are too large ($SIZE bytes)"
		else
			echo "Full changes since \`$prev' follow:"
			cat "$DIFF"
		fi
	fi
fi >>"$MSG"

/usr/sbin/sendmail -i -t <"$MSG"
exit 0
