#!/bin/sh -f
# note: bash-dependent due to checkbashisms

export LC_ALL=C
repobranch=sisyphus
gitbranch=
gitery_gears="git://git.altlinux.org/gears"
GITERYALTHOST=git.alt
GIRARALTHOST=girar
message=
tag=
use_default_tag=
kill_remote_repo_before=
kill_remote_repo_after=
add_to_task=
share_task=
autocommit=
push_related_tags=
tolerate_existing_tag=
REPOPREFIX=
TASKID=
BEFORE_TASK=

while getopts a:Ab:B:cd:hH:kKm:n:p:rR:St:T opt; do
	case "$opt" in
		B) BEFORE_TASK="${OPTARG:?}"
			readonly BEFORE_TASK ;;
		b) repobranch="${OPTARG:?}"
			readonly repobranch ;;
		c) autocommit=1 ;;
		d) gitbranch="${OPTARG:?}" 
			readonly gitbranch ;;
		p) REPOPREFIX="${OPTARG:?}"
			readonly REPOPREFIX ;;
		H) GITERYALTHOST="${OPTARG:?}"
			readonly GITERYALTHOST ;;
		R) GIRARALTHOST="${OPTARG:?}"
			readonly GIRARALTHOST ;;
		a) TASKID="${OPTARG:?}"
		        add_to_task=1 
			readonly TASKID ;;
		A) TASKID=
		        add_to_task=1 
			readonly TASKID ;;
		m) message="${OPTARG:?}" ;;
		n) gitery_path="${OPTARG:?}" ;;
		r) push_related_tags=1 ;;
		S) share_task=1 ;;
		t) tag="${OPTARG:?}"
		   tolerate_existing_tag=1 ;;
		T) use_default_tag=1 ;;
		k) kill_remote_repo_before=1 
			readonly kill_remote_repo_before ;;
		K) kill_remote_repo_after=1 
			readonly kill_remote_repo_after ;;
		:) missing="${OPTARG:?}"
		case "$missing" in
		    a) add_to_task=1 ;;
		    t) use_default_tag=1 ;;
		    *) pod2usage --exit=0 "$0"; exit 0 ;;
		esac
		;;
		h) pod2usage --exit=0 "$0"; exit 0 ;;
		*) pod2usage --exit=2 "$0"; exit 2 ;;
	esac
done

if [ -n "$BEFORE_TASK" ] && [ -z "$TASKID" ]; then
    echo "-B <before_subtask_id> require -a <taskid> option"
    exit 2
fi

shift "$((OPTIND-1))"

if [ -n "$1" ] && [ -e "$1/.git" ] && ([ -e "$1/.gear" ] || [ -e "$1/.gear-rules" ]); then
    echo "entering $1 ..."
    cd "$1"
    [ -z "$gitery_path" ] && gitery_path=`basename "$1"`
fi

if ! [ -e .git ] || ! ([ -e .gear ] || [ -e .gear-rules ]) ; then 
    echo "this program should be run inside git/gear repository"; exit 2;
fi

modified_files=`git status --porcelain --untracked-files=no`
[ -n "$modified_files" ] && [ -n "$autocommit" ] && gear-commit

modified_files=`git status --porcelain --untracked-files=no`
if [ -n "$modified_files" ]; then
	echo "WARNING: found modified files:"
	git status --porcelain --untracked-files=no
	echo "please, commit or discard them first."
	exit 3;
fi

if [ -n "$gitbranch" ]; then
    CURRENT_BRANCH="$(git branch | awk '/^\*/{print $2}')"
    #[ "$CURRENT_BRANCH" = "(no_branch)" ] && CURRENT_BRANCH=
    if [ "$CURRENT_BRANCH" != "$gitbranch" ]; then
	echo "WARNING: local branch is $CURRENT_BRANCH but should be $gitbranch"
	exit 9;
    fi
fi

# bash-specific; use variable inside of EOF instead
read -r gear_pkg_name gear_pkg_version gear_pkg_release <<< `gear --describe`

# hack around apache with gear_pkg_release=[%branch_release alt7.1]
gear_pkg_release=${gear_pkg_release// /_}
gear_pkg_release=${gear_pkg_release//%/_}
gear_pkg_version=${gear_pkg_version//%/_}

[ -z "$gitery_path" ] && gitery_path="$gear_pkg_name"
gitery_path=${gitery_path%%.git}

if [ -z "$gitery_path" ]; then 
    pod2usage --exit=2 "$0"; exit 2;
fi

# TODO: check if the tag already exists and create $tag.tryN
[ -n "$use_default_tag" ] && tag="${gear_pkg_version}-$gear_pkg_release"

if [ -z "$tag" ]; then
    tag=`git describe --exact-match --abbrev=0`;
    if [ $? -gt 0 ]; then
	echo "tag not found! to create a tag, add one of the options"
	echo "	-T (creates tag %version-%release), or"
	echo "	-t <tag> option, or place tag manually."
	exit 5;
    fi
else
    message="${message:-$tag}"
    found_tags=`git tag -l "$tag"`
    if [ -z "$found_tags" ]; then
	echo running git tag -s -m "$message" $tag
	git tag -s -m "$message" $tag || exit 3
    else
	if [ -z "$tolerate_existing_tag" ]; then
	    echo "tag $tag already exists. Use -t $tag to force use of that tag."
	    exit 3
	fi
    fi
fi
uploaddir=`dirname "$gitery_path"`
uploadname=`basename "$gitery_path" | sed -e 's,[^-A-Za-z0-9_.],,g'`
if [ -n "$uploaddir" ] && [ x"$uploaddir" != x. ]; then
    repopath="$gitery_path"
    [ -n "$REPOPREFIX" ] && echo "repository name $reponame already contains '/'. Add prefix $REPOPREFIX to the name manually."
else
    reponame="${REPOPREFIX}${uploadname}"
    repopath="packages/$reponame"
fi
if [ -n "$kill_remote_repo_before" ];then 
    echo ssh $GITERYALTHOST git-rm-db "${repopath}"
    ssh $GITERYALTHOST git-rm-db "${repopath}"
fi


if [ -n "$uploaddir" ] && [ x"$uploaddir" != x. ]; then
    echo "$gitery_path is a path, not a name. Skipped remote git init-db/clone/push"
else
    # relative path; let's conveniently create the git repo to push to and then push
    name=`basename "$gitery_path"`
    commit=`git ls-remote -h $gitery_gears/${name:0:1}/${name}.git refs/heads/$repobranch | awk '{print $1}'`
    if [ -n "$commit" ]; then
	ssh $GITERYALTHOST clone "/gears/${name:0:1}/${name}.git" "${repopath}"
    else
	# $name is not a git-built package"
	ssh $GITERYALTHOST git-init-db "${repopath}"
    fi

    PUSHLIST=$tag
    if [ -n "$push_related_tags" ]; then
	# Restore gears tags and branches
	gear-restore-tags -f
	# append related tags to pushlist
	PUSHLIST="$PUSHLIST "`gear-restore-tags -q -l --no-tags --no-type --no-sha1 | sed -r -n 's/^[[:space:]]*([^[:space:]]+)[[:space:]]*$/\1:\1/p'`
	PUSHLIST="$PUSHLIST "`gear-restore-tags -q -l --no-branches --no-type --no-sha1`
    fi

    git push --force ${GITERYALTHOST}:${repopath} ${gitbranch:+$gitbranch:$gitbranch} $PUSHLIST
fi

RETVAL=0
if [ -n "$add_to_task" ]; then
    ssh $GIRARALTHOST task add $TASKID $BEFORE_TASK repo "$repopath" $tag || RETVAL=$?
elif [ -n "$share_task" ]; then
    ssh $GIRARALTHOST task new ${repobranch:+$repobranch} && \
    ssh $GIRARALTHOST task add repo "$repopath" $tag && \
    ssh $GIRARALTHOST task share enabled && \
    ssh $GIRARALTHOST task run || RETVAL=$?
else
    ssh $GIRARALTHOST build ${repobranch:+-b $repobranch} "$repopath" $tag || RETVAL=$?
fi
if [ -n "$kill_remote_repo_after" ]; then
    echo ssh $GITERYALTHOST git-rm-db "$repopath"
    ssh $GITERYALTHOST git-rm-db "$repopath"
fi
#popd

[ $RETVAL -gt 0 ] && exit $RETVAL

: <<'__EOF__'

=head1	NAME

girar-nmu-helper-git-push-build - NMU helper for git/gear repository.

=head1	SYNOPSIS

B<girar-nmu-helper-git-push-build>
[B<-h>] 
[B<-a> I<task ID>] 
[B<-A>]
[B<-B> I<before_subtask_id>]
[B<-b> I<repository branch>]
[B<-c>]
[B<-d> I<local branch>]
[B<-H> I<ssh gitery(git.alt) alias>]
[B<-R> I<ssh girar alias>]
[B<-k>] 
[B<-K>] 
[B<-p> I<prefix>]
[B<-r>] 
[B<-S>] 
[B<-n> I<gitery name or path>] 
[B<-m> I<tag message>] 
[B<-t> I<tag>] 
[B<-T>] 
[</path/to/gear-repository.git>]


=head1	DESCRIPTION

B<girar-nmu-helper-git-push-build> NMU helper for git/gear repository.
It (optionally) create a tag in current git repository, 
remotely clones git.alt/gears/ repository, pushes the tag to git.alt,
and either adds package build with the tag to a specified task with -a option,
or current task, with -A option, or builds a package from the tag. 
It also can remove the remote repository (with -K option).

=head1	OPTIONS

=over

=item	B<-a> [I<task ID>]

git.alt task [I<task ID>] add.

=item	B<-A> 

git.alt task add.

=item	[B<-B> I<before_subtask_id>]

I<before_subtask_id> is used in the extended format of girar-task add coomand:
girar-task add [<task_id> [<before_subtask_id>]] srpm <filename>

=item	B<-b> I<repository name>

Name of the repository branch. Values: sisyphus|5.1|p5|..
Default is sisyphus.

=item   B<-c>

Commit. If modified files are found, call gear-commit.

=item	B<-d> I<local branch name>

Name of the local branch to build from. Default is master.

=item	B<-R> [I<girar ssh alias>]

By default, git.altlinux.org account should be configured as girar in ~/.ssh/config.
If you do not follow that convention, use -G <girar your ssh alias> option.

=item	B<-H> [I<gitery(git.alt) ssh alias>]

By default, gitery.altlinux.org account should be configured as git.alt in ~/.ssh/config.
If you do not follow that convention, use -H <git.alt your ssh alias> option.

=item	B<-h>

Display this help and exit.

=item	B<-k>

Try to kill remote git repository before upload (useful for robotic and nmu builds).

=item	B<-K>

Kill remote git repository after upload (useful for robotic and nmu builds).

=item	B<-m> [I<tag message>]

Specifies a message for git tag [I<tag>]. Default is tag name.

=item	B<-n> [I<repository name or path on gitery>]

Specifies a repository name or path on gitery. 
It can be used to run a task from a tag in a repository of another maintainer.
Together with -R <alias> it canm be used to run task from an alias.
Default is to guess from current gear repository.
If a path a specified, then git init-db / clone / push is skipped.

=item	B<-p> I<prefix>

Prefix to add before git repository name.
Use something like 00-tmp- to distinguish among automated and own repositories.

=item	B<-r>

Push related tags as well. Push all tags that are ancestors of the current build tag.
Useful when intermediate tags, like v@version@, are created.

=item	B<-S>

Create and run a shared task

=item	B<-t> [I<tag>]

Call git tag [I<tag>]. Default is %NAME-%VERSION.
If B<-t> or B<-T> is not specified then last commit is expected to be tag.

=item	B<-T> 

Call git tag %NAME-%VERSION.
If B<-t> or B<-T> is not specified then last commit is expected to be tag.

=back

=head1	AUTHOR

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

=head1	COPYING

Copyright (c) 2010-2015 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__
