summaryrefslogblamecommitdiffstats
path: root/lib/rpatch.in
blob: 3c05c0aa4b2aea553e6adf6737596e039fd33830 (plain) (tree)
1
2
3
4
5
6
7






                                                                      








































































































































































































                                                                              
#! /bin/bash

#  This script is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License version 2 as
#  published by the Free Software Foundation.
#
#  See the COPYING and AUTHORS files for more details.

if ! [ -r @LIB@/patchfns ]
then
	echo "Cannot read library @LIB@/patchfns" >&2
	exit 1
fi
. @LIB@/patchfns

usage()
{
	echo "Usage: rpatch [-fRq] patchname"
	exit 1
}

verify_removal()
{
	local patch=$1
	local bup file status=0
	local dir=$(basename $PWD) suffix=${patch//\//_}

	# Check if all changes of the patch are undone
	for file in $(files_in_patch $patch)
	do
		bup=$(backup_file_name $patch $file)
		if ! [ -s $file -o -s $bup ] || \
		   cmp $file $bup > /dev/null 2> /dev/null
		then
			continue
		fi

		if [ $status -eq 0 ]
		then
			echo "Patch does not remove changes:"
		fi

		diff -Nu $DIFF_OPTS $bup $file \
		| sed -e 's:^--- [^ \t]*:--- '"$dir/$file.orig"':' \
		      -e 's:^+++ [^ \t]*:+++ '"$dir/$file"':'

		status=1
	done
	return $status
}

files_may_have_changed()
{
	local patch=$1 file
	local pc_file=$(pc_file_name $patch)
	local apply_ts=$(date -r $pc_file '+%s') ts

	if [ $pc_file -ot $(patch_file_name $patch) ]
	then
		return 0
	fi
	
	for file in $(files_in_patch $patch)
	do
		if ! [ -e $file ]
		then
			return 0  # file is missing
		fi
		
		ts=$(date -r $file '+%s')
		if [ $? -ne 0 -o $ts -gt $apply_ts ]
		then
			return 0  # file has changed
		fi
	done
	return 1
}

abort_patch()
{
	local pc_file=$(pc_file_name $1)
	@LIB@/backup-files -s -f $pc_file -z ~rpatch -r
	exit 1
}

interrupt()
{
	local patch=$1
	abort_patch $patch
	echo "rpatch interrupted by user"
	exit 1
}

do_remove()
{
	local patch=$1 pc_file=$(pc_file_name $patch)

	trap "" SIGINT
	if [ -n "$opt_force" ] || \
	   ( [ -z "$opt_remove" ] && ! files_may_have_changed $patch )
	then
		# Optimize: Force remove if the patch has not been
		# modified since it was applied. (Forced remove is
		# faster!)

		@LIB@/backup-files $silent -f $pc_file -B .pc/$patch/ -r
		status=$?
		remove_from_db $patch
		rm -f $(pc_file_name $patch)~forced
		return $status
	else
		local patch_file=$(patch_file_name $patch)
		if ! [ -e "$patch_file" ]
		then
			echo "No patch named $patch found."
			return 1
		fi
		
		trap "interrupt $patch" SIGINT
		#if [ ! -e $patch_file ] || grep -q '^%patch$' $patch_file
		#then
		#	@LIB@/parse-patch -s patch $patch_file \
		#	| patch $(patch_args $patch) --no-backup-if-mismatch \
		#		-R -E $silent
		#else
			patch $(patch_args $patch) --no-backup-if-mismatch \
				-R -E $silent -i $patch_file
		#fi
		status=$?
		trap "" SIGINT
		if [ $status -eq 0 ] && verify_removal $patch
		then 
			@LIB@/backup-files -s -f $pc_file -z ~rpatch -x
			@LIB@/backup-files -s -f $pc_file -B .pc/$patch/ -x

			remove_from_db $patch
		else
			@LIB@/backup-files -s -f $pc_file -z ~rpatch -r
			echo "Patch $patch does not remove cleanly"
			return 1
		fi
	fi
	trap - SIGINT
}

options=`getopt -o fRqh -- "$@"`

if [ $? -ne 0 ]
then
	usage
fi

eval set -- "$options"

while true
do
	case "$1" in
	-f)
		opt_force=1
		shift ;;
	-R)
		opt_remove=1  # remove properly with patch -R; no tricks
		unset opt_force
		shift ;;
	-q)
		opt_quiet=1 
		shift ;;
	-h)
		usage -h ;;
	--)
		shift
		break ;;
	esac
done

if [ $# -ne 1 ]
then
	usage
fi

patch=$(stripit $1)
[ -n "$opt_quiet" ] && silent=-s

top=$(top_patch)
if [ -n "$top" -a -e $(pc_file_name $top)~forced -a -z "$opt_force" ]
then
	echo "The topmost patch $top was force applied. Please run" \
	     "refpatch before removing it."
	exit 1
fi

#if is_applied "$patch"
#then
	do_remove "$patch" || exit 1
#else
#	echo "Patch $patch is not applied"
#	exit 1
#fi

top=$(top_patch)
if [ -z "$top" ]
then
	where="no patches applied"
else
	where="now at $top"
fi
echo "Removed $patch, $where"