#! @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. # Read in library functions if [ "$(type -t patch_file_name)" != function ] then if ! [ -r @SCRIPTS@/patchfns ] then echo "Cannot read library @SCRIPTS@/patchfns" >&2 exit 1 fi . @SCRIPTS@/patchfns fi usage() { echo $"Usage: $0 [-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 patch_file=$(patch_file_name $patch) local pc_file=$(pc_file_name $patch) if ! [ -e $pc_file ] then return 1 fi local apply_ts=$(date -r $pc_file '+%s') ts if [ -e "$patch_file" -a $pc_file -ot "$patch_file" ] 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 } rollback_patch() { local patch=$1 pc_file=$(pc_file_name $patch) @LIB@/backup-files $silent_unless_verbose \ -f $pc_file -z ~rpatch -r rm -f $(files_in_patch $patch | @SED@ -e 's/$/\.rej/') } interrupt() { local patch=$1 rollback_patch $patch echo $"Interrupted by user; patch $patch was not removed." exit 1 } reverse_patch() { local patch=$1 local patch_file=$(patch_file_name $patch) if ! [ -s $patch_file ] then echo $"Patch file $patch_file appears to be empty" return 0 fi if [ "x${patch_file:(-3)}" = "x.gz" ] then gzip -cd $patch_file \ | @PATCH@ $(patch_args $patch) --no-backup-if-mismatch \ -R -E $silent elif [ "x${patch_file:(-4)}" = "x.bz2" ] then bzip2 -cd $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 } rpatch() { local patch=$1 pc_file=$(pc_file_name $patch) if ! [ -e $pc_file ] then echo $"Patch $patch appears to be empty, removed" remove_from_db $patch return 0 fi echo $"Removing $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~refresh if [ $status != 0 ] then exit $status fi else if ! @LIB@/backup-files $silent_unless_verbose \ -f $pc_file -z ~rpatch then echo $"Failed to create temporary files" >&2 return 1 fi trap "interrupt $patch" SIGINT reverse_patch $patch status=$? trap "" SIGINT if [ $status -eq 0 ] && verify_removal $patch then @LIB@/backup-files $silent_unless_verbose \ -f $pc_file -z ~rpatch -x @LIB@/backup-files $silent_unless_verbose \ -f $pc_file -B .pc/$patch/ -x remove_from_db $patch else rollback_patch $patch echo $"Patch $patch does not remove (enforce with -f)" return 1 fi fi trap - SIGINT } options=`getopt -o fRqvh -- "$@"` 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 ;; -v) opt_verbose=1 shift ;; -h) usage -h ;; --) shift break ;; esac done if [ $# -ne 1 ] then usage fi patch=$(stripit $1) [ -n "$opt_quiet" ] && silent=-s [ -z "$opt_verbose" ] && silent_unless_verbose=-s top=$(top_patch) if [ -n "$top" -a -e $(pc_file_name $top)~refresh -a -z "$opt_force" ] then echo $"The topmost patch $top needs to be refreshed first." exit 1 fi rpatch "$patch" || exit 1 ### Local Variables: ### mode: shell-script ### End: # vim:filetype=sh