#!/usr/bin/env bash
# $FreeWRT$
# $MirOS: ports/infrastructure/scripts/update-patches,v 1.5 2006/06/15 19:18:43 tg Exp $
#-
# Copyright (c) 2006
#	Thorsten Glaser <tg@freewrt.org>
#
# Derived from the MirPorts Framework "update-patches" script:
#
# Copyright (c) 2003, 2004, 2005
#	Thorsten "mirabile" Glaser <tg@MirBSD.de>
# Based upon code and idea (c) 2000
#	Marc Espie for the OpenBSD project. All rights reserved.
#
# Licensee is hereby permitted to deal in this work without restric-
# tion, including unlimited rights to use, publicly perform, modify,
# merge, distribute, sell, give away or sublicence, provided all co-
# pyright notices above, these terms and the disclaimer are retained
# in all redistributions or reproduced in accompanying documentation
# or other materials provided with binary redistributions.
#
# Licensor offers the work "AS IS" and WITHOUT WARRANTY of any kind,
# express, or implied, to the maximum extent permitted by applicable
# law, without malicious intent or gross negligence; in no event may
# licensor, an author or contributor be held liable for any indirect
# or other damage, or direct damage except proven a consequence of a
# direct error of said person and intended use of this work, loss or
# other issues arising in any way out of its use, even if advised of
# the possibility of such damage or existence of a nontrivial bug.

shopt -s extglob

do_diff()
{
	local f1=$2/$1
	local f2=$3/$1

	if [[ ! -e $f1 ]]; then
		if [[ ! -s $f2 ]]; then
			cat <<EOF
--- $f1	(non-existant)
+++ $f2	(empty)
@@ -0,0 +0,0 @@
EOF
			return 0
		fi
		touch -t 197001010000.00 "$f1"
	fi
	diff -adup "$f1" "$f2"
	return $?
}

TRANSFORM='sed s/[.+]/\\\\&/g'
PATCHDIR=$CURDIR/patches
EXTRADIR=$CURDIR/extra

mkdir -p $PATCHDIR

SUBDIST=${WRKDIST##${WRKDIR1}?(/)}
if [[ -n $SUBDIST ]]; then
	mv ${WRKDIR1}.orig/${SUBDIST} ${WRKDIR1}/${SUBDIST}.orig
	D_BASE=${WRKDIR1}
	D_SUB=${SUBDIST}
	D_CMP=$D_SUB
else
	# WRKSRC == WRKDIR
	D_BASE=$(dirname ${WRKDIR1})
	D_SUB=$(basename ${WRKDIR1})
	D_CMP=
fi
ORGDIST=${D_BASE}/${D_SUB}.orig

[[ -d $EXTRADIR ]] && \
    (cd $EXTRADIR; find . -print0) | \
    (cd $WRKDIST; pax -rw -0 -d $ORGDIST/) >/dev/null 2>&1

if [[ -e $WRKDIST/.patched-newfiles ]]; then
	touch $ORGDIST/.patched-newfiles
	patch_newfiles=1
else
	patch_newfiles=0
fi

DIFF_FLAGS="-adu -I \"^--- $(echo $D_SUB.orig/ | $TRANSFORM)@@	.*\""
DIFF_FLAGS="$DIFF_FLAGS -I \"^\+\+\+ $(echo $D_SUB/ | $TRANSFORM)@@	.*\""

for file in $(cd ${WRKDIST}; find . -type f | sed 's#^\./##'); do
	[[ ! -e $ORGDIST/$file && $patch_newfiles = 0 ]] && continue
	cmp -s "$ORGDIST/$file" "$WRKDIST/$file" && continue
	echo "Processing ${file}..." >&2
	# look in patchdir for an existing patchfile matching this
	cd $PATCHDIR
	for i in $PATCH_LIST; do
		# Ignore non-files, or old backup
		[[ ! -f $i || $i = *@(.orig|.rej|~) ]] && continue

		# Patch found. Is this the one?
		if grep "^[+-][+-][+-] $D_CMP[^/]*/$file	" "$i" >/dev/null; then
			# Multiple files in the diff?
			if [ $(grep -c "^--- $D_CMP" "$i") -gt 1 -o \
			    $(grep -c "^+++ $D_CMP" "$i") -gt 1 ]; then
				echo "Cannot process, $i contains patches" >&2
				echo "to multiple files! Aborting." >&2
				echo FAIL
				[[ -n $SUBDIST ]] && mv \
				    ${WRKDIR1}/${SUBDIST}.orig \
				    ${WRKDIR1}.orig/${SUBDIST}
				exit 0
			fi
			# Multiple diffs with this file?
			let n=0
			pflst=
			for j in $PATCH_LIST; do
				[[ ! -f $j || $j = *@(.orig|.rej|~) ]] && \
				    continue
				grep "^[+-][+-][+-] $D_CMP[^/]*/$file	" \
				    "$j" >/dev/null || continue
				let n++
				pflst="$pflst '$j'"
			done
			if (( n != 1 )); then
				echo "Cannot process, file $file" >&2
				echo "is contained in multiple patches:" >&2
				echo "$pflst" >&2
				echo FAIL
				[[ -n $SUBDIST ]] && mv \
				    ${WRKDIR1}/${SUBDIST}.orig \
				    ${WRKDIR1}.orig/${SUBDIST}
				exit 0
			fi
			# No, process this patch

			accounted="$accounted $i"
			# found it, copy preamble before comparision
			( sed -e "/^--- /,\$d" <$i; \
			  cd $D_BASE && do_diff "$file" "$D_SUB.orig" "$D_SUB" \
			) >"$i.new"
			# did it change ? mark it as changed
			tfile="$(echo "$file" | $TRANSFORM)"
			if eval diff "$(echo "${DIFF_FLAGS}" \
			    | sed "s#@@#${tfile}#g")" \
			    "$i" "$i.new" 1>&2; then
				rm "$i.new"
			else
				echo "Patch $i for $file updated" >&2
				mv "$i" "$i.orig"
				mv "$i.new" "$i"
				edit="$edit $i"
			fi
			continue 2
		fi
	done

	# Build a sensible name for the new patch file
	patchname=patch-$(echo "$file" | sed -e 's#[/. ]#_#g')
	echo "No patch-* found for $file, creating $patchname" >&2
	( echo '$Free''WRT$'; \
	  cd $D_BASE && do_diff "$file" "$D_SUB.orig" "$D_SUB" \
	) >$patchname
	edit="$edit $patchname"
	accounted="$accounted $patchname"
done

# Verify all patches accounted for
cd $PATCHDIR
for i in *; do
	[[ ! -f $i || $i = *@(.orig|.rej|~) ]] && continue
	grep '^\\ No newline at end of file' $i >/dev/null \
	    && echo "*** Patch $i needs manual intervention" >&2
	[[ $accounted != *@($i)* ]] \
	    && echo "*** Patch $i not accounted for" >&2
done

echo $edit
[[ -n $SUBDIST ]] && mv ${WRKDIR1}/${SUBDIST}.orig ${WRKDIR1}.orig/${SUBDIST}
exit 0
