#!/bin/sh -efu
#
# Copyright (C) 2008  Alexey Gladkov <legion@altlinux.org>
# Copyright (C) 2008  Dmitry V. Levin <ldv@altlinux.org>
# Copyright (C) 2008  Alexey I. Froloff <raorn@altlinux.org>
#
# gear-changelog generate changelog entry from git commit logs.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#

. gear-sh-functions

rules="${RULES-}"
main_tree_id='HEAD'
changelog_rules='.gear/changelog'
cwidth=70
format='rpm'
specfile=
tab="$(printf \\t)"

show_help() {
	cat <<EOF
Usage: $PROG [options] [<since>]

Options:

  --no-rules          do not use rules at all, changelog entries will be
                      written without aggregation (grouping, filtering, etc);
  --no-groups         do not group entries as described in a rules file;
  --no-specfile       do not use information from specfile;
  -f, --format=TYPE   specify source type: 'deb', 'rpm' or 'gnu',
                      default is 'rpm';
  -r, --rules=RULES   name of a rules file, default is .gear/changelog;
  -V, --version       print program version and exit;
  -h, --help          show this text and exit.

Report bugs to http://bugzilla.altlinux.org/

EOF
	exit
}

print_version() {
	cat <<EOF
$PROG version $PROG_VERSION
Written by Alexey Gladkov <legion@altlinux.org>

Copyright (C) 2008  Alexey Gladkov <legion@altlinux.org>
Copyright (C) 2008  Dmitry V. Levin <ldv@altlinux.org>
Copyright (C) 2008  Alexey I. Froloff <raorn@altlinux.org>
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
EOF
	exit
}

find_changelog_rules() {
	: >"$workdir/rules"
	if [ -n "$(git ls-tree "$main_tree_id" "$changelog_rules")" ]; then
		cat_blob "$main_tree_id" "$changelog_rules" >"$workdir/rules"
	fi
	rules_cleanup "$workdir/rules"
	changelog_rules="$workdir/rules"
}

num_groups=0
write_group() {
	[ -n "$regexp" ] ||
		fatal 'Group with empty regexp found.'

	mkdir -p -- "$workdir/$num_groups"
	printf '%s\n' "$group"  >"$workdir/$num_groups/descr"
	printf '%s\n' "$regexp" >"$workdir/$num_groups/regexp"
	printf '%s\n' "$filter" >"$workdir/$num_groups/filter"

	num_groups=$(($num_groups+1))
	filter= regexp=
}

parse_changelog_rules() {
	local found= group= regexp= filter=
	local cmd value

	while read -r cmd value; do
		case "$cmd" in
			''|'#'*) continue
				;;
			width:)
				[ -z "$group" ] ||
					fatal "Directive \`$cmd' cannot be specified inside group."

				cwidth="$(opt_check_number width "$value")"
				;;
			group:)
				[ -n "$value" ] ||
					fatal "Directive \`$cmd' cannot be specified without a value."

				[ -z "$group" -o "$group" = "$value" ] ||
					write_group "$num_groups"

				group="$value"
				found=1
				;;
			regexp:) regexp="${regexp:+$regexp
}$value"
				;;
			filter:) filter="${filter:+$filter
}$value"
				;;
		esac
	done < "$changelog_rules"

	[ -z "$found" ] ||
		write_group
}

workdir=
cleanup_handler()
{
	[ -z "$workdir" ] || rm -rf -- "$workdir"
}

TEMP=`getopt -n $PROG -o 'f:,r:,h,V' -l 'format:,no-groups,no-rules,no-spec,rules:,help,version' -- "$@"` ||
	show_usage
eval set -- "$TEMP"

no_rules=
no_groups=
no_specfile=
while :; do
	case "$1" in
		--no-groups) no_groups=1
			;;
		--no-rules) no_rules=1
			;;
		--no-spec) no_specfile=1
			;;
		-r|--rules) shift; changelog_rules="$1"
			;;
		-f|--format) shift
			[ -z "$1" ] &&
				fatal 'Empty format does not make sense!' ||
				format="$1"
			;;
		-h|--help) show_help
			;;
		-V|--version) print_version
			;;
		--) shift; break
			;;
	esac
	shift
done

case "$format" in
	deb|rpm|gnu) ;;
	*) fatal "Unknown format: $format" ;;
esac

chdir_to_toplevel

[ "$#" -eq 0 ] ||
	since="$1"

[ -n "${since-}" ] ||
	since="$(git describe --abbrev=0)"

install_cleanup_handler cleanup_handler
workdir="$(mktemp -dt "$PROG.XXXXXXXXXX")"

if [ -z "$no_specfile" ]; then
	find_specfile

	[ -s "$specfile" ] ||
		fatal 'No specfile found.'
fi

if [ -z "$no_rules" ]; then
	if [ ! -s "$changelog_rules" ]; then
		find_changelog_rules

		[ -s "$changelog_rules" ] ||
			fatal 'No rules found.'
	fi
	parse_changelog_rules
fi

gear_config_option GIT_AUTHOR_NAME name "${GIT_AUTHOR_NAME-$(git config --get user.name)}"
gear_config_option GIT_AUTHOR_EMAIL email "${GIT_AUTHOR_EMAIL-$(git config --get user.email)}"

releaser="${GIT_AUTHOR_NAME-GIT_AUTHOR_NAME} <${GIT_AUTHOR_EMAIL-GIT_AUTHOR_EMAIL}>"

. "$0-$format"

git log \
	--no-merges \
	--pretty="format:%h$tab%at$tab%an$tab%ae$tab%s%n" \
	${since:+$since..HEAD} |
while IFS="$tab" read -r hash atime aname aemail subj; do
	[ -n "$hash" ] ||
		continue

	if [ -n "$no_rules" ]; then
		format_commit "$subj" >> "$workdir/group"
		continue
	fi

	i=0
	while [ "$num_groups" -gt "$i" ]; do
		if printf '%s' "$subj" |egrep -qsf "$workdir/$i/regexp"; then
			[ ! -s "$workdir/$i/filter" ] ||
				subj="$(printf '%s\n' "$subj" |
					sed -r -f "$workdir/$i/filter")"

			out="$workdir/group$i"
			[ -z "$no_groups" ] ||
				out="$workdir/group"

			format_commit "$subj" >> "$out"
			break
		fi
		i=$(($i+1))
	done
done

format_header
if [ -z "$no_rules" -a -z "$no_groups" ]; then
	i=0
	while [ "$num_groups" -gt "$i" ]; do
		if [ ! -s "$workdir/group$i" ]; then
			i=$(($i+1))
			continue
		fi
		group="$(cat "$workdir/$i/descr")"
		format_group "$group"
		uniq < "$workdir/group$i"
		i=$(($i+1))
	done
else
	uniq < "$workdir/group"
fi
format_footer
