#!/usr/bin/env bash
#
# Generate a mail feed for a commits list.
#
# Author: David Woodhouse <dwmw2@infradead.org>

# Environment variables used by this script...
#
# $SENDMAIL and $MLIST must be set appropriately if you intend to
# actually send mail to a mailing list (or other recipient). Otherwise,
# an mbox file named 'git-commits-mail.out' will be created in the 
# current directory.
#
# $FROM specifies the From: header used in the mails. It'll default
# to GIT_COMMITTER_EMAIL if that exists, or to `whoami`@`hostname`
#
# $EXCLUDEHEAD is given as additional arguments to the git-rev-list
# invocation, and is intended to allow other branches to be excluded.
# For example, subsystem trees might avoid mailing changes which were
# merged in from Linus' tree by setting EXCLUDEHEAD=^linus
#
# $GIT_DIR has the obvious effect.
#
# $MAILTAG specifies the file in which the 'last commit mailed' information
# is stored. By default, this will be $GIT_DIR/refs/tags/MailDone, or
# just the relative path '.git/refs/tags/MailDone' if $GIT_DIR is not specified

if [ -z "SENDMAIL" -o -z "$MLIST" ]; then 
    SENDMAIL="tee --append"
    MLIST=git-commits-mail.out
fi

if [ -z "$FROM" ]; then
    if [ -n "$GIT_COMMITTER_EMAIL" ]; then 
	FROM="$GIT_COMMITTER_EMAIL"
    else
	FROM=`whoami`@`hostname`
    fi
fi

if [ -z "$MAILTAG" ]; then
    if [ "$GIT_DIR" = "" ]; then
	MAILTAG=.git/refs/tags/MailDone
    else
	MAILTAG=$GIT_DIR/refs/tags/MailDone
    fi
fi

# Command line arguments. The first specifies the commit or branch to treat
# as HEAD, and the second is the starting commit. Defaults to HEAD and 
# whatever's in $MAILTAG, resp.

if [ -z $2 ]; then
    lastmail=$(git-rev-parse `cat $MAILTAG`)
    if [ -z "$lastmail" ]; then
	echo "No last tag"
	exit 1
    fi
else
    lastmail=$(git-rev-parse $2)
fi

if [ -z $1 ]; then
    base=$(git-rev-parse HEAD) || exit 1
else
    base=$(git-rev-parse $1) || exit 1
fi


if [ "$base" != "$lastmail" ]; then
    git-rev-list --topo-order --no-merges $lastmail..$base $EXCLUDEHEAD | tac |
    while read COMMIT ; do (
	PARENT=`git-rev-parse $COMMIT^1`
	SUBJECT="`git-show --pretty=oneline $COMMIT | head -2 | tail -1`"
	echo Mail: $SUBJECT >&2

	SUBHEX="`echo -n "$SUBJECT" | od -t x1 -A none | tr a-f A-F`"
	if echo $SUBHEX | egrep -q ' [8-9A-F]' ; then
	    # Subject contains non-ASCII.
	    NEWSUB="=?UTF-8?Q?"
	    for CHR in $SUBHEX ; do
		case $CHR in
		    20|3D|3F|8*|9*|A*|B*|C*|D*|E*|F*)
			NEWSUB="$NEWSUB=$CHR"
			;;
		    *)
			NEWSUB="$NEWSUB`echo -en \\\\x$CHR`"
		esac
	    done
	    SUBJECT="$NEWSUB?="
	fi
	cat <<EOF 
From: $FROM
To: $MLIST
Subject: $SUBJECT
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Git-Commit: $COMMIT
X-Git-Parent: $PARENT

Commit:     $COMMIT
Parent:     $PARENT
EOF
	git-show -B --patch-with-stat --pretty=fuller $COMMIT | 
	    egrep -v '^diff-tree [A-Fa-f0-9]{40} \(from [A-Fa-z0-9]{40}\)$' 
	) | $SENDMAIL $MLIST
    done

    echo $base > $MAILTAG
fi

