#!/bin/bash

set -e

OPTIONS_KEEPDASHDASH=
OPTIONS_SPEC="\
gob-bump [options] <branch> <tag>
--
apply-dir=           use apply-dir
continue             continue from previous run
debug                print everything
distro=              use branches for distro
limit=               bump only LIMIT branches

 BRANCH     Merge the newest changes from here
 TAG        To create the new gob-tag-name tag
"

. git sh-setup

log() { grep -E "^(CONFLICT|Created commit|Merge)" || :; }

parse_config () {
	while test $# != 0
	 do
		case "$1" in
		--apply-dir)
			shift
			apply_dir=$1
			;;
		--continue)
			continue=t
			;;
		--debug)
			set -x
			log() { cat; }
			;;
		--distro)
			shift
			distro=$1
			;;
		--limit)
			shift
			limit=$1
			;;
		--)
			shift
			break ;;
		*)	usage ;;
		esac
		shift
	done
	args_left=$#
}

test $# != 0 || usage

parse_config "$@"
while test $args_left -lt $#; do shift; done

test $# = 2 || usage

new_changes=$1
new_tag=gob-$2

# setup
this_branch=$(git symbolic-ref HEAD | cut -b 12-)
update_branch=gob-bump/work/update

gob_bases=$(git tag | grep '^gob-' || true)
if test -z "$gob_bases"
then
	echo 'Cannot find any gob-* tag, aborting'  1>&2
	exit 1
fi

# second run, tag already set?
the_tag=$(git tag | grep "^$new_tag\$" || true)

# find the last unpatched version and create a 'reset' commit
# (actually this is one commit after that, we'll use ${one_ofter}^ to get
# the right one)
one_after=$(git rev-list $this_branch --not $gob_bases | tail -n 1)
latest_tag=$(git log --pretty=oneline -2 $one_after | tail -1 | sed -e s'/ .*//')

if test -n "$the_tag" -a -z "$continue"
then
	echo "TAG: \`$the_tag' already exists, specify new tag or use --continue" 1>&2
	exit 1
elif test -z "$the_tag"
then
	echo "Bumping: $this_branch"
	# reset to the state of the last gob tag
	if test -n "$one_after"
	then
		temp_branch=gob-bump/tmp/work
		git branch -D $temp_branch 2>&1 | log || :
		git checkout -b $temp_branch $latest_tag
		git reset --soft $this_branch
		git commit -m "Reset tree to state of previous gob tag: $latest_tag." -a 2>&1 | log
		git checkout $this_branch
		git clean -df > /dev/null 2>&1 | log
		if git merge $temp_branch 2>&1 | log
		then
			git branch -d $temp_branch
		else
			echo "Reverting changes failed." 1>&2
			exit 1
		fi
	fi
	
	git checkout $this_branch
	# get the newest changes and tag the tip
	git merge $new_changes 2>&1 | log
	git tag $new_tag

	echo "Bumping: $update_branch"
	## Keep commits in master this_branch, do all work with
	## $update_branch: cannot seem to get around merging twice.
	git branch -D $update_branch 2>&1 | log || :
	git checkout -b $update_branch
	gob-collapse-commits $latest_tag
	git merge $new_changes 2>&1 | log
fi

git checkout $update_branch
# update the branches
if test -z "$apply_dir"
then
	branches="$(git branch -r | sed 's#^.*origin/##' | grep -Ev '/|^(HEAD|master|patched|pristine)$')"
else
	# Allow gob-bump to work in multi-distro GIT: work with subset
	# of [this distro's only] branches
	if test -z "$distro"
	then
		distro=SUSE
	fi
	branches="$(gob --apply-dir=$apply_dir --distro=$distro branches)"
fi

broken='BROKEN-NONEMPTY'
bumped=$(git branch | grep bumped/ | sed -e s'@bumped/@@' | tr -d ' ' | tr '\n' '|' | sed -e s'@|$@@')
if test -n "$bumped" -a -z "$continue"
then
	echo 'bumped/* branches found, delete them or use --continue' 1>&2
	exit 1
fi

i=0
echo "$branches" | grep -Ev "^(${broken}|${bumped})\$" | while read branch
do
	echo "Bumping: $branch"
	temp_branch=gob-bump/tmp/$branch
	temp_update=gob-bump/tmp/update
	git branch -D $temp_branch $temp_update 2>&1 | log || :
	git checkout -b $temp_branch origin/$branch
	git branch $temp_update $update_branch
	if gob-update $temp_update 2>&1 | log
	then
		# Let's push later...
		# git push
		git checkout $temp_update
 		if git merge $temp_branch 2>&1 | log
		then
			# ...so preserve succesfully bumped branches locally
			# git branch -d $temp_branch
			git checkout $temp_branch
			git branch -m $temp_branch bumped/$branch
			git branch -D $temp_update 2>&1 | log
		else
			echo "Merging back failed, please merge manually: $temp_branch" 1>&2
		fi
	else
		echo "Update failed, please update manually: $temp_branch" 1>&2
	fi
	foo=$((i++))
	if test -n "$limit" -a $i -gt 0$limit
	then
		echo Do only $limit
		break
	fi
done

git checkout $this_branch
# Do not delete, need for --continue
# git branch -D $update_branch 2>&1 | log

# Local Variables:
# sh-basic-offset:8
# End:
