#!/bin/bash
# Generate a patch for each of the ia64 files in the linux-2.6-xen-sparse tree

# Path to mercurial tree of upstream Linux
# WARNING: This will do an 'hg up -C' on the upstream Linux tree, you
#          will lose data if there's anything there you care about.
: ${LINUXPATH:=/tmp/linux-2.6}
# Tag of current base upstream image for Xen files
: ${OLDTAG:=v$(awk '/^LINUX_VER/{print $NF}' buildconfigs/mk.linux-2.6-xen)}
# Tag of new upstream base to go to
: ${NEWTAG:=v$(wget -O- -o/dev/null http://kernel.org/kdist/finger_banner \
    | awk '/latest stable/{print $NF}')}
# Restrict merge to specific arch (set to . for all)
: ${ARCH:=ia64}

SPARSEDIR=linux-2.6-xen-sparse
WD=$PWD

if [ ! -d $SPARSEDIR ]; then
	echo "Can't find $SPARSEDIR directory."
	exit
fi

# Check for modified files in the sparse tree before starting
if hg st $SPARSEDIR | head | grep .; then
    echo
    echo "$SPARSEDIR contains modifications, please clean it up first"
    exit
fi

# We want the linux upstream tree to be at the OLDTAG to get the OLDTAG-Xen diff.
# Save current revision to restore when done
cd $LINUXPATH || exit 1
OLDCSET=$(hg parents | awk '/^changeset:/{print($2)}' | cut -f 1 -d :)
for t in $OLDTAG $NEWTAG; do
    [[ $t == *.* ]] || continue
    if ! hg tags | cut -f1 -d' ' | grep -Fx $t; then
	echo "Tag $t not found, ketching up"
	if [[ $t == *-* ]]; then
	    # rc/pre/git versions start at the previous stable release
	    micro=${t%%-*}; micro=${micro##*.}
	    stable=${t%%-*}; stable=${stable%.*}.$((micro-1))
	    hg up -C $stable
	else
	    hg up -C ${t%.*} || exit 1
	fi
	ketchup ${t#v} || exit 1
	hg addremove
	hg ci -m $t
	hg tag -l $t
    fi
done
hg up -C $OLDTAG || exit 1

cd $WD
for i in $(hg manifest | awk '{print($3)}' | grep $SPARSEDIR | grep "$ARCH"); do
	cd $WD

	FILENAME=$(basename $i)
	DIRNAME=$(dirname $i)
	DIFFPATH=$(echo $i | sed -e "s,^$SPARSEDIR,$LINUXPATH,")

	if [ ! -d $DIRNAME ]; then
		echo "Hmm, something bad happened parsing directory name: $i"
		continue
	fi

	if [ ! -e $DIFFPATH ]; then
		continue
	fi

	echo -n "$i ... "

	cd $DIRNAME
	XENDIR=$(pwd)

	ORIGPATH=$(echo $i | sed -e "s/^$SPARSEDIR/./")
	APATH=$(echo $i | sed -e "s/^$SPARSEDIR/a/")
	BPATH=$(echo $i | sed -e "s/^$SPARSEDIR/b/")
	cd $LINUXPATH
	hg diff -r $OLDTAG -r $NEWTAG $ORIGPATH | \
	    sed -e "s,^--- $APATH,--- $FILENAME," \
	        -e "s,^+++ $BPATH,+++ $FILENAME," \
	    > $XENDIR/$FILENAME-$OLDTAG-$NEWTAG.diff
	cd $XENDIR

	# Do we have a diff file?  Did anything change?
	if [ ! -s $FILENAME-$OLDTAG-$NEWTAG.diff ]; then
		echo "SUCCESS (Upstream unchanged)"
		continue
	fi

	if ! patch -f -i $FILENAME-$OLDTAG-$NEWTAG.diff > /dev/null 2>&1; then
		# It failed, how badly?
		if [ ! -e ${FILENAME}.rej ]; then
			echo "ERROR, Hmm, no .rej file, but diff failed, fix manually"
			continue
		fi
		TONEWREJ=$(wc -l ${FILENAME}.rej | \
		           awk '{print($1)}')
		hg st $FILENAME | grep -q . && hg revert $FILENAME
		rm -f ${FILENAME}.rej ${FILENAME}.orig
		diff -uN $DIFFPATH $FILENAME | \
		    sed -e "s,^--- $DIFFPATH,--- $FILENAME," \
		    > $FILENAME-$OLDTAG-Xen.diff

		if [ ! -e $FILENAME-$OLDTAG-Xen.diff ]; then
			echo "ERROR, failed to create patch file"
			continue
		fi

		if ! patch -R -i $FILENAME-$OLDTAG-Xen.diff > /dev/null 2>&1; then
			echo "ERROR, reverting Xen changes failed"
			hg revert $FILENAME
			continue
		fi

		if ! patch -f -i $FILENAME-$OLDTAG-$NEWTAG.diff > /dev/null 2>&1; then
			echo "ERROR, new upstream patch failed on reverted file"
			hg revert $FILENAME
			continue
		fi

		if ! patch -f -i $FILENAME-$OLDTAG-Xen.diff > /dev/null 2>&1; then
			if [ ! -e ${FILENAME}.rej ]; then
				echo "ERROR, Hmm, no .rej file, but diff failed, fix manually"
				continue
			fi
			TOXENREJ=$(wc -l ${FILENAME}.rej | \
			           awk '{print($1)}')

			if  [ $TOXENREJ -gt $TONEWREJ ]; then
				hg revert $FILENAME
				rm -f ${FILENAME}.rej ${FILENAME}.orig
				patch -f -i $FILENAME-$OLDTAG-$NEWTAG.diff > /dev/null 2>&1
				echo "MANUAL MERGE REQUIRED (Upstream reject)"
			else
				echo "MANUAL MERGE REQUIRED (Xen reject)"
			fi

		else
			rm -f ${FILENAME}.rej ${FILENAME}.orig
			echo "SUCCESS (Re-applied Xen patch)"
		fi
	else
			rm -f ${FILENAME}.rej ${FILENAME}.orig
			echo "SUCCESS (Upstream applied)"
	fi
done
find $SPARSEDIR -name \*.diff -empty | xargs -r rm -f
cd $LINUXPATH
hg up -C $OLDCSET
