#!/bin/sh

##############################
## TODO: PIPESTATUS is bashism
##############################

logfile=cronbuild-apply-hooks.log
difffile=cronbuild-apply-hooks.diff
EXIT_MAGIC_CODE_NOTHING_TO_DO=77

PROG=gear-cronbuild-apply-hooks
watchfile=
verbose=

error_hook()
{
    local hook_name="$1"; shift;
    echo "cronbuild: the hook $hook_name exited abnormally. see $logfile for details."
    exit 2
}

do_hook()
{
    local hook="$1"; shift;
    echo running "$hook" "$@"
    "$hook" "$@" 2>&1 | tee -a "$logfile"
    [ ${PIPESTATUS[0]} -gt 0 ] && error_hook "$hook"
    return 0
}

add_changelog_builtin()
{
    local gear_specfile="$1"; shift;
    adate=$(date +"%Y%m%d")
    add_changelog -e "- repocop cronbuild $adate. At your service." $gear_specfile
}

find_watchfile()
{
    local pkgname=$1
    watchfile=
    for i in .gear/$pkgname*.watch $pkgname*.watch .gear/autobuild.watch .gear/*.watch *.watch ; do
	if [ -f $i ]; then
	    watchfile=$i
	    return 0
	fi
    done
    watchfile=`find . -path '*/debian/watch' -type f | head -1`
    [ -z "$watchfile" ] && return 1
    [ -f "$watchfile" ] && return 0
    echo "INFO: watchfile $watchfile: not a file, skipped"
    watchfile=
    return 1
}

if ! [ -d .gear ]; then
    echo "FATAL: This utility should be run in a valid gear repository."
    echo ".gear directory not found. exiting."
    exit 1
fi

show_help()
{
	cat <<EOF
$PROG - update gear repository.

Usage: $PROG [options]

The current path must be a valid gear repository.

Options:
  --exclude=pattern                 pattern for gear-uupdate and gear-update
  -q, --quiet                       try to be more quiet;
  -v, --verbose                     print a message for each action;
  -h, --help                        show this text and exit.

Report bugs to http://bugs.altlinux.ru/

EOF
}

show_usage()
{
    show_help
    exit 1
}

tarball_exclude_pattern=
[ -e ./.gear/cronbuild-options ] && . ./.gear/cronbuild-options ||:

TEMP=`getopt -n $PROG -o hqv -l exclude:,help,quiet,verbose -- "$@"` || show_usage
eval set -- "$TEMP"

while :; do
	case "$1" in
		'') break
			;;
		--exclude) shift; tarball_exclude_pattern="$1";
			;;
		-h|--help) show_help; exit
			;;
		-q|--quiet) verbose=;
			;;
		-v|--verbose) verbose=$(($verbose+1));
			;;
		--) shift; break
			;;
		*) echo "ERROR parsing arguments: $@"; show_usage
			;;
	esac
	shift
done

[ 0"$verbose" -gt 1 ] && set -x

[ -e "$logfile" ] && rm -f "$logfile"
[ -e "$difffile" ] && rm -f "$difffile"

gear_specfile=`gear-rules-print-specfile --check-nvr`
if [ -z "$gear_specfile" ] || ! [ -e "$gear_specfile" ]; then
    echo "cronbuild: can't find spec file. exiting."
    exit 1
fi

if [ -e ./.gear/upstream/remotes ]; then
    [ 0"$verbose" -gt 0 ] && echo "found ./.gear/upstream/remotes. running gear-remotes-restore ..."
    gear-remotes-restore
fi

if [ -e ./.gear/cronbuild-git-config ]; then
    cat ./.gear/cronbuild-git-config | xargs git config
    echo "cronbuild: .gear/cronbuild-git-config is deprecated, use .gear/upstream/remotes"
fi

specfile_to_update=$gear_specfile
# mithraen@'s specgen support
if [ -e specs/$gear_specfile ]; then
    if [ -x /usr/bin/specgen ] ; then
	specfile_to_update=specs/$gear_specfile
    else
	echo "WARNING: specs/$gear_specfile but no specgen found."
    fi
fi

saved_specfile="$specfile_to_update".sav.~
saved_changelog="$specfile_to_update".changelog.sav.~
gear_changelog="$specfile_to_update".changelog.new.~
cat "$specfile_to_update" > "$saved_specfile"
sed -e '1,/^%changelog/d' "$specfile_to_update" > "$saved_changelog"

exit_cleanup()
{
    rm -f "$saved_specfile" "$saved_changelog" "$gear_changelog"
}

last_commit=`git show-ref --head HEAD | awk '{if ($2=="HEAD") print $1;}'`
last_commit=${last_commit:=HEAD}

gear_pkg_name=`gear --describe | awk '{print $1}'`

gear_uupdate_cmd=gear-uupdate
[ -n "$tarball_exclude_pattern" ] && gear_uupdate_cmd="$gear_uupdate_cmd --exclude '$tarball_exclude_pattern'"
# mithraen@'s specgen support
if [ $specfile_to_update != $gear_specfile ] && [ -x /usr/bin/specgen ] ; then
    gear_uupdate_cmd="$gear_uupdate_cmd --specgen"
fi

if [ -x ./.gear/cronbuild-update-source ]; then
    [ 0"$verbose" -gt 0 ] && echo "running .gear/cronbuild-update-source $specfile_to_update ..."
    do_hook ./.gear/cronbuild-update-source $specfile_to_update
elif [ -e ./.gear/upstream/remotes ]; then
    [ 0"$verbose" -gt 0 ] && echo "running gear-remotes-uscan --action=$gear_uupdate_cmd ..."
    gear-remotes-uscan --action="$gear_uupdate_cmd"
elif find_watchfile $gear_pkg_name; then
    echo "INFO: using watchfile $watchfile"
    [ 0"$verbose" -gt 0 ] && echo "running rpm-uscan --any-archive --watchfile=$watchfile --force-action=$gear_uupdate_cmd ..."
    rpm-uscan --any-archive --watchfile="$watchfile" --force-action="$gear_uupdate_cmd"
else
    echo "gear-cronbuild-apply-hooks: ERROR: nothing to apply."
    echo "* watch file not found."
    echo "* .gear/upstream/remotes not found."
    echo "* ./.gear/cronbuild-update-source is missing or not executable."
    echo "* see https://www.altlinux.org/Gear/cronbuild."
    exit_cleanup
    exit 3
fi

git diff $last_commit > "$difffile"
if ! [ -s "$difffile" ]; then
    echo "INFO: source files did not change after cronbuild-update. Nothing to do.";
    rm -f "$difffile"
    exit $EXIT_MAGIC_CODE_NOTHING_TO_DO;
fi
rm -f "$difffile"

if [ -x ./.gear/cronbuild-update-version ]; then
    [ 0"$verbose" -gt 0 ] && echo "running .gear/cronbuild-update-version $specfile_to_update ..."
    do_hook ./.gear/cronbuild-update-version $specfile_to_update
elif cmp "$saved_specfile" "$specfile_to_update"; then
    echo "INFO: spec file did not change after cronbuild-update-source."
    echo "INFO: running built-in cronbuild-update-version"
    do_hook gear-cronbuild-update-spec-timestamp $specfile_to_update
else
    echo "INFO: spec file changed after cronbuild-update-source."
    echo "INFO: skip built-in cronbuild-update-version"
fi

sed -e '1,/^%changelog/d' "$specfile_to_update" > "$gear_changelog"
if [ -x ./.gear/cronbuild-add-changelog ]; then
    do_hook ./.gear/cronbuild-add-changelog $specfile_to_update
elif cmp "$saved_changelog" "$gear_changelog"; then
    echo "INFO: changelog did not change before cronbuild-add-changelog."
    echo "INFO: running built-in cronbuild-add-changelog"
    do_hook add_changelog_builtin $specfile_to_update
elif [ -n "$watchfile" ] || [ -e ./.gear/upstream/remotes ]; then
    : # do nothing, Their update methods add changelog.
else
    echo "INFO: changelog changed before cronbuild-add-changelog."
    echo "INFO: skip built-in cronbuild-add-changelog"
fi

exit_cleanup

git add $specfile_to_update
git add $gear_specfile

: <<'__EOF__'

=head1	NAME

gear-cronbuild-apply-hooks

=head1	SYNOPSIS

B<gear-cronbuild-apply-hooks>

=head1	DESCRIPTION

B<gear-cronbuild-apply-hooks> tries to update current gear repository
using .gear/cronbuild-* hooks if found, or using gear-remotes-uscan
if VCS: tag or .gear/upstream/remotes found, or using rpm-uscan if
watch file is found.

=head1	OPTIONS

=over

=item	B<--exclude> I<pattern>

pattern for gear-uupdate and gear-update.
This pattern is passed "as is" to uupdate hook command.
Normally, gear-uupdate is used.

=item	B<-v,--verbose>

Internal verbosity. Multiple options increase verbosity.

=item	B<-q,--quiet>

Disable verbosity.


=item	B<-h,--help>

Print help.

=back

=head1 FILES

=over

=item B<*.watch>

Debian watch file. Optional.
Recommended locations are either in . or in ./gear

=item B<.gear/cronbuild-update-source>

Optional. Required if no *.watch file found.

=item B<.gear/cronbuild-update-version>

Optional.

=item B<.gear/cronbuild-add-changelog>

Optional.

=back

=head1 SEE ALSO

http://www.altlinux.org/Gear/cronbuild

=head1	AUTHOR

Written by Igor Vlasenko <viy@altlinux.org>.

=head1	COPYING

Copyright (c) 2010-2023 Igor Vlasenko, ALT Linux Team.

This 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.

=cut

__EOF__
