#!/bin/sh -efu
#
# Copyright (C) 2007-2014  Alexey Gladkov <legion@altlinux.org>
# Copyright (C) 2007-2021  Dmitry V. Levin <ldv@altlinux.org>
# Copyright (C) 2008  Alexey I. Froloff <raorn@altlinux.org>
#
# gear-create-tag - create a signed release tag object.
#
# 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-utils-sh-functions

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

Copyright (C) 2007-2014  Alexey Gladkov <legion@altlinux.org>
Copyright (C) 2007-2021  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
}

show_help()
{
	cat <<EOF
$PROG - create a signed release tag object for the given commit object

Usage: $PROG [commit-ish]

Options:
  -f, --force           replace an existing tag (instead of failing);
  -u, --key-id=KEYID    use the given GPG key to create a signed tag;
  -m, --message=TEXT    override custom tag message
                        (default: <NAME> <VERSION>-<RELEASE>);
  -n, --name=TEXT       override custom tag name
                        (default: <VERSION>-<RELEASE>);
  -r, --rules=FILENAME  override rules file name;
  -s, --specsubst=VARIABLE=VALUE
                        add specsubst definition to the tag message,
                        this option can be specified more than once;
  -t, --time=DATE-FMT   set the date used in tag;
  -q, --quiet           try to be more quiet;
  -v, --verbose         print a message for each action;
  -V, --version         print program version and exit;
  -h, --help            show this text and exit.

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

EOF
	exit
}

TEMP=$(getopt -n $PROG -o f,m:,n:,r:,s:,t:,u:,q,v,V,h -l force,key-id:,message:,name:,rules:,specsubst:,time:,quiet,verbose,version,help -- "$@") ||
	show_usage
eval set -- "$TEMP"

force=
keyid=
opt_s='-s'
nl='
'
specsubst_prefix='X-gear-specsubst: '
specsubst_msg=
gear_config_option tag_name name '@version@-@release@'
gear_config_option tag_msg message '@name@ @version@-@release@'
main_tree_id='HEAD'
while :; do
	case "$1" in
	    -f|--force) force=-f
		;;
	    -m|--message) shift; tag_msg="$1"
		;;
	    -n|--name) shift; tag_name="$1"
		;;
	    -r|--rules) shift; rules="$1"
		;;
	    -s|--specsubst)
		case "$2" in
		    [^=]*=*)
			[ -z "$(printf %s "${2%%=*}" |
				LANG=C tr -d '[:alnum:]_')" ] ||
			fatal "invalid $1 value: $2" ;;
		    *) fatal "invalid $1 value: $2" ;;
		esac
		shift
		specsubst_msg="$specsubst_msg$nl$specsubst_prefix$1"
		;;
	    -t|--time) shift
		[ -z "$1" ] ||
			export GIT_COMMITTER_DATE="$1"
		;;
	    -u|--key-id) shift; keyid="$1"; opt_s=
		;;
	    -q|--quiet) quiet=-q verbose=
		;;
	    -v|--verbose) verbose=-v quiet=
		;;
	    -V|--version) print_version
		;;
	    -h|--help) show_help
		;;
	    --) shift; break
		;;
	    *) fatal "unrecognized option: $1"
		;;
	esac
	shift
done

if [ "$#" -gt 0 ]; then
	main_tree_id="$1"
	shift
fi

[ "$#" -eq 0 ] ||
	show_usage 'Too many arguments.'

chdir_to_toplevel

main_commit_sha1="$(get_commit_sha1 "$main_tree_id")" ||
	fatal "$main_tree_id: Invalid commit object name"
disable_specsubst=1

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

subst_NVR_from_spec_file '' tag_name tag_msg

[ -z "$specsubst_msg" ] ||
	tag_msg="$tag_msg$nl$specsubst_msg"

# Check whether all required specsubst variables are defined in the tag message.
# The implementation is derived from substitute_vars_in_spec().
get_uniq_directive_from_rules specsubst specsubst
[ -z "$(printf %s "$specsubst" |LANG=C tr -d '[:alnum:]_[:space:]')" ] ||
	rules_error "Invalid specsubst value \"$specsubst\" specified"
# $specsubst is a space-separated sequence of alphanumerics
for var in $specsubst; do
	printf %s "$tag_msg" |
	    grep -qs "^X-gear-specsubst:[[:space:]]\\+$var=" ||
		fatal "specsubst variable \"$var\" is not defined in the tag message"
done
unset var

cleanup_workdir
uninstall_cleanup_handler

[ -n "$quiet" ] ||
	message "Creating tag named \"$tag_name\" using tag message \"$tag_msg\" for commit $main_commit_sha1"

rc=0
git tag $force $opt_s ${keyid:+-u "$keyid"} -m "$tag_msg" "$tag_name" "$main_commit_sha1" ||
	rc=$?

if [ -z "$quiet" ]; then
	[ "$rc" = 0 ] &&
		message "Created tag \"$tag_name\"" ||
		message "Failed to create tag \"$tag_name\""
fi

exit $rc
