#!/usr/bin/env bash
#
# Make a log of changes in a GIT branch.
# Copyright (c) Petr Baudis, 2005.
# Copyright (c) David Woodhouse, 2005.
# Copyright (c) Sean Estabrooks, 2005.
#
# Takes a -c option to add color to the output.
# Currently, the colors are:
#
#	header		Green	
#	author 		Cyan
#	committer	Magenta
#	files		Blue
#	signoff		Yellow
#
# Takes an -f option to list which files was changed.
#
# Takes an -r followed with id resolving to a commit to start from
# (HEAD by default), or id1:id2 representing an (id1;id2] range
# of commits to show.
#
# The rest of arguments are took as filenames; cg-log then displays
# only changes in those files.

. cg-Xlib
# Try to fix the annoying "Broken pipe" output. May not help, but apparently
# at least somewhere it does. Bash is broken.
trap exit SIGPIPE

colheader=
colauthor=
colcommitter=
colfiles=
colsignoff=
coldefault=

list_files=

log_start=
log_end=

user=

while getopts cfr:u: o
do
	case $o in
	c)	# See terminfo(5), "Color Handling"
		colheader="$(tput setaf 2)"    # Green
		colauthor="$(tput setaf 6)"    # Cyan
		colcommitter="$(tput setaf 5)" # Magenta
		colfiles="$(tput setaf 4)"     # Blue
		colsignoff="$(tput setaf 3)"   # Yellow
		coldefault="$(tput op)"        # Restore default
		;;
	f)	list_files=1 
		;;
	r)	if [ -z $log_start ]; then
			log_start="${OPTARG/:*}"
			[ $OPTARG != $log_start ] && log_end="${OPTARG/*:}"
		else	log_end="$OPTARG"
		fi
		;;
	u)	user="$OPTARG"
		;;
	*)	exit 1
		;;
	esac
done
shift $((OPTIND-1))

list_commit_files()
{
	echo
	if [ -z $2 ]; then
		git-ls-tree $1  # List all files for initial commit
	else	
		local tree1=$1; shift
		for tree2; do
			git-diff-tree -r $tree1 $tree2
		done
	fi | cut -f4 | sort -u | column | column -t | \
	sed "s/^/$colfiles    * /;s/$/$coldefault/"
}

id1="$(commit-id $log_start)" || exit 1
if [ "$log_end" ]; then
	id2="$(commit-id $log_end)" || exit 1
	git-rev-tree $id2 ^$id1 | sort -rn | cut -d' ' -f2
else
	git-rev-list $id1
fi | \
while read commit
do
	trap exit SIGPIPE
	trees=
	if [ $# -ne 0 ]; then
		parent=$(git-cat-file commit $commit | sed -n '2s/parent //p;2Q')
		[ "$parent" ] && [ "$(git-diff-tree -r $commit $parent "$@")" ] || continue
	fi
	if [ ! -z "$user" ]; then
		git-cat-file commit $commit | grep '^author ' | grep -qi "$user" || continue
	fi
	echo $colheader""commit ${commit%:*} $coldefault;
	git-cat-file commit $commit | \
		while read key rest; do
			trap exit SIGPIPE
			case "$key" in
			"author"|"committer")
				if [ "$key" = "author" ]; then
					color="$colauthor"
				else
					color="$colcommitter"
				fi

				date=(${rest#*> })
				pdate="$(showdate $date)"
				if [ "$pdate" ]; then
					echo -n $color$key $rest | sed "s/>.*/> $pdate/"
					echo $coldefault
				else
					echo $color$key $rest $coldefault
				fi
				;;
			"tree"|"parent")
				trees="$trees $rest"
				echo $colheader$key $rest $coldefault
				;;
			"")
				echo; sed -re "
				 s/^(from|cc|signed.off.by|acked.by): .*/$colsignoff&$coldefault/I
				 s/^/    /"
				[ -n "$list_files" ] && list_commit_files $trees
				;;
			*)
				echo $colheader$key $rest $coldefault
				;;
			esac

		done
	echo
done | ${PAGER:-less} ${PAGER_FLAGS:--R}
