#!/bin/sh
#
# typical usage:
# push-pcp -b main -t pcp -r 6bad98e4b0537c2e99b3906ca7a36f4998ea3419..
#

# cd to the base of the current PCP repo
#
_here=`pwd`
_cwd="$_here"
while true
do
    # looks like git repo
    #
    if [ -d .git ]
    then
	# now is the origin a clone of the official PCP repo?
	#
	if git config --get remote.origin.url | grep '/github.com.*/pcp$' >/dev/null
	then
	    break
	fi
    fi
    cd ..
    _next_cwd=`pwd`
    if [ "$_next_cwd" = "$_cwd" ]
    then
	# back to / and no luck
	echo >&2 "Error: no PCP git repo between cwd and /"
	cd "$_here"
	exit
    fi
    _cwd="$_next_cwd"
done
origin_url=`git config --get remote.origin.url`

tmp=/var/tmp/$$
trap "rm -f $tmp.*; exit 0" 0 1 2 3 15

_usage()
{
    echo >&2 "Usage: pcp-push [options]"
    echo >&2
    echo >&2 "options:"
    echo >&2 "  -b branch           [defaults to current branch]"
    echo >&2 "  -m                  don't launch mail client or create pull request"
    echo >&2 "  -n                  dryrun"
    echo >&2 "  -r range            [defaults to \$(cat $pushed_sha)..)]"
    echo >&2 "  -s                  short format, do not include commit messages"
    exit 1
}

case `id -un`
in
    kenj)
	if which hub >/dev/null
	then
	    hub=hub
	elif which git-hub >/dev/null
	then
	    hub=git-hub
	else
	    echo "Arrgh: hub(1)/git-hub(1) is missing.  Suggest reinstall from https://github.com/github/hub"
	    echo "Else for Ubuntu: $ sudo apt install git-hub"
	    exit 1
	fi
	;;
esac

dryrun=false
GIT=git
RM=rm
branch=`git branch --list | sed -n -e 's/^\* //p'`
tree=origin
short=false
if [ -f $branch.sha ]
then
    range=$(cat $branch.sha)..
    pushed_sha=$branch.sha
elif [ -f pushed.sha ]
then
    range=$(cat pushed.sha)..
    pushed_sha=pushed.sha
else
    range=''
fi
mail=true
while getopts "b:mnr:s?" c
do
    case $c
    in
	b)
	    branch="$OPTARG"
	    ;;
	m)	# don't launch mail client or generate pull request
	    mail=false
	    ;;
	n)
	    dryrun=true
	    GIT="echo + git"
	    RM="echo + rm"
	    ;;
	r)
	    range="$OPTARG"
	    ;;
	s)
	    short=true
	    ;;
	*)
	    _usage
	    # NOTREACHED
    esac
done
shift `expr $OPTIND - 1`

[ $# -eq 0 ] || _usage

if [ -z "$range" ]
then
    echo "Error: no range from $pushed_sha, so need -r range"
    exit 1
fi


unset GIT_EXTERNAL_DIFF
push=`git config remote.origin.url`
case "$push"
in
    *github*)
	# new school ...
	#
	;;

    *)
	echo "Sorry, no recipe to handle repo: $push"
	exit 1
	;;
esac

changes=true
echo "Changes committed to $push $branch" >/tmp/msg
echo >>/tmp/msg
git shortlog --no-merges --numbered $range >$tmp.tmp
if [ -s $tmp.tmp ]
then
    cat $tmp.tmp >>/tmp/msg
else
    echo "Nothing to push ..."
    changes=false
    rm -f /tmp/msg
fi

if $changes
then
    git log --no-merges -p $range | diffstat -p1 >>/tmp/msg
    if $short
    then
	:
    else
	echo >>/tmp/msg
	echo "Details ..." >>/tmp/msg
	echo >>/tmp/msg
	git log --no-merges $range >>/tmp/msg
    fi

    xclip -sel clip < /tmp/msg
    cat /tmp/msg
    echo "(all of this for email is in /tmp/msg)"
fi

# even if no changes locally, still push to remote, e.g.
# after git-refresh to pull commits from the remote official
# repo, then these need to go back to the origin for this
# repo
#
rm -f $tmp.y
while true
do
    echo -n "Push to $push $branch [y|n|q] (or ctrl+C to abort) "
    read ans </dev/tty
    if [ -z "$ans" ]
    then
	:
    elif [ "$ans" = y ]
    then
	touch $tmp.y
	break
    elif [ "$ans" = n ]
    then
	break
    elif [ "$ans" = q ]
    then
	echo "Quitting ... $pushed_sha not updated"
	exit
    fi
    echo "Answer the question, bozo!"
done
rm -f $tmp.needpush
if [ -f $tmp.y ]
then
    if [ "$branch" != main ]
    then
	$GIT push -u origin $branch
	touch $tmp.needpush
    else
	$GIT push $push
	# need to get last commit aligned locally and remotely, so that
	# HEAD -> main, origin/main, origin/HEAD
	#
	$GIT pull
    fi
fi

# remember last commit that was pushed ...
#
sha=`git log | sed -e 's/commit //' -e 1q`
if $dryrun
then
    echo "+ echo $sha >pushed.sha"
else
    echo "$sha" >pushed.sha
fi

if $mail
then
    case `id -un`
    in
	kenj)
	    # using hub(1)/git-hub(1) to generate a pull request
	    #
	    while true
	    do
		rm -f $tmp.pr
		echo -n "Pull request title: [n|q|title] "
		read ans </dev/tty
		if [ "$ans" = n ]
		then
		    echo "Skipping ... github pull request"
		    break
		elif [ "$ans" = q ]
		then
		    echo "Quitting ... no github pull request generated"
		    exit
		elif [ -n "$ans" ]
		then
		    echo "$ans" >$tmp.pr
		    echo >>$tmp.pr
		    cat /tmp/msg >>$tmp.pr
		    break
		else
		    echo "Answer the question, bozo!"
		fi
	    done
	    if [ -f $tmp.pr ]
	    then
		if $dryrun
		then
		    echo "+ $hub pull-request -F $tmp.pr"
		    echo "---- 8< ----"
		    cat $tmp.pr
		else
		    $hub pull-request -F $tmp.pr
		fi
	    fi
	    ;;
    esac
else
    if $changes
    then
	echo "cut-n-paste from /tmp/msg into mail program and send to pcp@group.io"
    fi
fi

if [ "$branch" != main ]
then
    # Back to the main branch, but leave the temporary branch to
    # allow further commits to be added onto the same Pull Request
    # on github
    #
    $GIT checkout main
    # and if we pushed a non-main branch, then also push the main
    # branch back to the remote repo
    #
    if [ -f $tmp.needpush ]
    then
	$GIT push $push
    fi
fi

# may have local git mirror that needs to be updated ...
#
if [ -d $HOME/git-mirror ]
then
    here=`pwd`
    cd $HOME/git-mirror
    for dir in *
    do
	[ -d "$dir" ] || continue
	[ -f "$dir/config" ] || continue
	if grep "url = $push" "$dir/config" >/dev/null 2>&1
	then
	    # found repo with url matching the one we've just pushed to
	    #
	    cd $dir
	    echo "Update local $dir git mirror ..."
	    $GIT fetch
	    cd ..
	fi
    done
    cd $here
fi
