summaryrefslogblamecommitdiffstats
path: root/bin/patch-wrapper.in
blob: 46ef8ae994de6edf6bf5da31765a35264afcd1bb (plain) (tree)






































                                                                      




                                                                              
















                                                                        
                             



































































































                                                                         


                                                                 



                                       


                                      
    














                                                        





                               
                           
 
                                                                         













                                          
                                                       

            
#! @BASH@

# This is a wrapper to GNU patch that recognizes the most common
# options and mimics GNU patch's behavior and output, and creates the
# quilt metadata as if quilt push was used to apply the patches.  When
# options are used that this wrapper does not recognize, GNU patch is
# used directly, and no quilt metadata will get created.

PATCH=patch
original_options=("$@")

# GNU patch recognizes these environment variables
if [ -n "$SIMPLE_BACKUP_SUFFIX" ]
then
    set -- --suffix "$SIMPLE_BACKUP_SUFFIX" "$@"
fi
if [ -n "$PATCH_VERSION_CONTROL" ]
then
    set -- --version-control "$PATCH_VERSION_CONTROL" "$@"
elif [ -n "$VERSION_CONTROL" ]
then
    set -- --version-control "$VERSION_CONTROL" "$@"
fi
if [ -n "$POSIXLY_CORRECT" ]
then
    set -- --posix "$@"
fi

backup_files() {
    declare dir=${QUILT_PC:-.pc}/$patch

    if [ "$backup_mode" = --backup-if-mismatch ]
    then
	awk '
	/^patching file / \
	    { file=$0
	      sub(/^patching file /, "", file)
	    }
	/^Hunk #[0-9]* / \
	    { if (!(file in backup)) {
	        backup[file] = 1
	        #print "ln -f "dir"/"file" "prefix file suffix > "/dev/stderr"
	        system("ln -f "dir"/"file" "prefix file suffix)
	      }
	    }
	    { if (!silent)
	        print
	    }
	' dir="${dir//\\/\\\\}" \
	  prefix="${opt_prefix//\\/\\\\}" \
	  suffix="${opt_suffix//\\/\\\\}" \
	  silent="${opt_silent:+1}"
    elif [ -n "$opt_silent" ]; then
	cat > /dev/null
    fi
    if [ "$backup_mode" = --backup ]
    then
	for file in $(find "$dir" -type f -a ! -path "$path/.timestamp")
	do
	    dest=$opt_prefix${file#$dir/}$opt_suffix
	    mkdir -p $(dirname "$dest")
	    ln -f $file $dest
	done
    fi
}

options=`getopt -q -o bsB:z:i:p:d: \
		   --long quiet,silent,backup,backup-if-mismatch \
		   --long no-backup-if-mismatch,prefix: \
		   --long suffix:,posix,input:,strip:,directory: -- "$@"`
if [ $? -ne 0 ]
then
    cannot_handle=1
elif [[ ! ${LC_ALL:-${LC_MESSAGES:-${LANG}}} =~ "^$|^C$|^POSIX$|^en" ]]
then
    cannot_handle=1
else
    eval set -- "$options"

    backup_mode=--backup-if-mismatch
    opt_prefix=
    opt_suffix=
    opt_silent=
    opt_input=
    opt_strip=
    opt_directory=$PWD

    while :
    do
	case "$1" in
	-b|--backup)
	    backup_mode=--backup
	    ;;
	--backup-if-mismatch)
	    backup_mode=--backup-if-mismatch
	    ;;
	-d|--directory)
	    cd "$2" || exit 1
	    shift
	    ;;
	-i|--input)
	    opt_input=$2
	    new_options[${#new_options[@]}]=$1
	    new_options[${#new_options[@]}]=$2
	    shift
	    ;;
	--no-backup-if-mismatch)
	    backup_mode=--no-backup-if-mismatch
	    ;;
	-B|--prefix)
	    opt_prefix=$2
	    new_options[${#new_options[@]}]=$1
	    new_options[${#new_options[@]}]=$2
	    shift
	    ;;
	-s|--silent|--quiet)
	    opt_silent=--silent
	    ;;
	-p|--strip)
	    opt_strip=-p$2
	    new_options[${#new_options[@]}]=-p$2
	    shift
	    ;;
	-z|--suffix)
	    opt_suffix=$2
	    new_options[${#new_options[@]}]=$1
	    new_options[${#new_options[@]}]=$2
	    shift
	    ;;
	--posix)
	    backup_mode=--no-backup-if-mismatch
	    new_options[${#new_options[@]}]=$1
	    ;;
	--)
	    shift
	    break
	    ;;
	*)
	    new_options[${#new_options[@]}]=$1
	    ;;
	esac
	shift
    done

    [ -n "$opt_prefix$opt_suffix" ] || opt_suffix=.orig
    if [ -z "$opt_strip" -o $# -ne 0 ]
    then
	cannot_handle=1
    fi
fi

if [ -n "$cannot_handle" ]
then
    $PATCH "${original_options[@]}"
    exit
fi

if [ -n "$opt_input" ]
then
    patch=$opt_input
else
    patch=$(readlink /proc/self/fd/0)
    # FIXME: try to recognize pipes, find the other end of a pipe
    # in /proc, and for gzip and bzip2 processes, use the file
    # that the process is reading from.
fi
patch=${patch#$PWD/}

quilt_patches=${QUILT_PATCHES:-patches}
dir=$(dirname "$quilt_patches/$patch")
mkdir -p "$dir"
if [ -e "$patch" ]
then
    if [ "${patch:0:1}" = / ]
    then
	patch=${patch#/}
	ln -s "$patch" "$quilt_patches/$patch"
    else
	while ! [ "$dir/$updir$patch" -ef "$patch" ]
	do
	    updir=$updir../
	    [ ${#updir} -gt 96 ] && break
	done
	if [ "$dir/$updir$patch" -ef "$patch" ]
	then
	    ln -s "$updir$patch" "$quilt_patches/$patch"
	fi
    fi
fi

if [ "$opt_strip" = -p1 ]; then
    echo "$patch"
else
    echo "$patch $opt_strip"
fi >> $quilt_patches/series

$PATCH "${new_options[@]}" --backup --prefix "${QUILT_PC:-.pc}/$patch/" \
    | backup_files
status=${PIPESTATUS[0]}
if [ $status -eq 0 ]
then
    dir=${QUILT_PC:-.pc}/$patch
    if [ ! -e "$dir" ]
    then
	mkdir -p "$dir"
    fi
    echo -n "" > $dir/.timestamp
    if [ ! -e ${QUILT_PC:-.pc}/.version ]
    then
	echo 2 > ${QUILT_PC:-.pc}/.version
    fi
    echo "$patch" >> "${QUILT_PC:-.pc}/applied-patches"
fi
exit $status