diff options
Diffstat (limited to 'lib/rpatch.in')
-rwxr-xr-x | lib/rpatch.in | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/lib/rpatch.in b/lib/rpatch.in new file mode 100755 index 0000000..d25695b --- /dev/null +++ b/lib/rpatch.in @@ -0,0 +1,202 @@ +#!/bin/sh + +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" + |