scripts/patch-rework.sh
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Wed Jan 13 20:46:01 2010 +0100 (2010-01-13)
changeset 1732 6b2ae7804c6f
child 2147 0ec4491d6496
permissions -rwxr-xr-x
debug/gdb: staticaly link to ncurses for the native gdb

Staticaly link the native gdb (the one that runs on the target,
not the cross one that runs on the host) to ncurses.
     1 #!/bin/sh
     2 
     3 # Get our required options
     4 base="$1"
     5 src="$2"
     6 dst="$3"
     7 shift 3
     8 
     9 # The remainder is for diff
    10 diff="$@"
    11 
    12 # This function checks that the files listed in the file in "$1"
    13 # do exist, at the given depth-stripping level (aka diff -p#)
    14 do_check_files_at_depth() {
    15   local flist="$1"
    16   local depth="$2"
    17   local ok=0  # 0: OK,  !0: KO
    18 
    19   exec 6<&0
    20   exec 7<"${flist}"
    21 
    22   while read -u7 f; do
    23     f="$( echo "${f}" |sed -r -e "s:^([^/]+/){${depth}}::;" )"
    24     [ -f "${f}" ] || ok=1
    25   done
    26 
    27   exec 7<&-
    28   exec <&6
    29 
    30   return ${ok}
    31 }
    32 
    33 mkdir -p "${dst}"
    34 dst="$( cd "${dst}"; pwd )"
    35 
    36 # Iterate through patches
    37 for p in "${src}/"*.patch; do
    38   pname="$( basename "${p}" )"
    39 
    40   printf "Handling patch '${pname}'...\n"
    41 
    42   printf "  creating reference..."
    43   cp -a "${base}" "${base}.orig"
    44   printf " done\n"
    45 
    46   printf "  retrieving patch comment..."
    47   comment="$( awk '
    48 BEGIN { mark=0; }
    49 $0~/^diff --/ { nextfile; }
    50 $1=="---" { mark=1; next; }
    51 $1=="+++" && mark==1 { nextfile; }
    52 { mark=0; print; }
    53 ' "${p}" )"
    54   printf " done\n"
    55 
    56   printf "  creating patched file list..."
    57   diffstat -f 4 -r 2 -u -p 0 "${p}"                         \
    58   |head -n -1                                               \
    59   |awk '{ for(i=NF;i>=NF-5;i--) { $(i) = ""; } print; }'    \
    60   |sort                                                     \
    61   >"diffstat.orig"
    62   printf " done\n"
    63 
    64   pushd "${base}" >/dev/null 2>&1
    65 
    66   # Check all files exist, up to depth 3
    67   printf "  checking depth:"
    68   for((d=0;d<4;d++)); do
    69     printf " ${d}"
    70     if do_check_files_at_depth "../diffstat.orig" ${d}; then
    71       printf " ok, using depth '${d}'\n"
    72       break
    73     fi
    74   done
    75   if [ ${d} -ge 4 ]; then
    76     printf "\n"
    77     printf "  checking depth failed\n"
    78     read -p "  --> enter patch depth (or Ctrl-C to abort): " d
    79   fi
    80 
    81   # Store the original list of fiels touched by the patch,
    82   # removing the $d leading components
    83   sed -r -e "s:^([^/]+/){${d}}::;" "../diffstat.orig" >"${dst}/${pname}.diffstat.orig"
    84 
    85   # Apply the patch proper, and check it applied cleanly.
    86   # We can't check with --dry-run because of patches that
    87   # contain multiple accumulated patches onto a single file.
    88   printf "  applying patch..."
    89   if ! patch -g0 -F1 -f -p${d} <"${p}" >"../patch.out" 2>&1; then
    90     printf " ERROR\n"
    91     # Revert the patch
    92     popd >/dev/null 2>&1
    93     printf "  restoring '${base}'..."
    94     rm -f "diffstat.tmp"
    95     rm -rf "${base}"
    96     mv "${base}.orig" "${base}"
    97     printf " done\n\n"
    98     printf "There was an error while applying:\n  -->  ${p}  <--\n"
    99     printf "'${base}' was restored to the state it was prior to applying this faulty patch.\n"
   100     printf "Here's the 'patch' command, and its output:\n"
   101     printf "  ----8<----\n"
   102     printf "  patch -g0 -F1 -f -p${d} <'${p}'\n"
   103     cat "patch.out" |(IFS=$(printf "\n"); while read line; do printf "  ${line}\n"; done)
   104     rm -f "patch.out"
   105     printf "  ----8<----\n"
   106     exit 1
   107   fi
   108   printf " done\n"
   109 
   110   printf "  removing '.orig' files..."
   111   find . -type f -name '*.orig' -exec rm -f {} +
   112   printf " done\n"
   113 
   114   popd >/dev/null 2>&1
   115 
   116   printf "  re-diffing the patch..."
   117   printf "%s\n\n" "${comment}" >"${dst}/${pname}"
   118   diff -durN "${base}.orig" "${base}" >>"${dst}/${pname}"
   119   printf " done\n"
   120 
   121   if [ -n "${diff}" ]; then
   122     printf "  applying diff filter..."
   123     filterdiff -x "${diff}" "${dst}/${pname}" >"tmp-diff"
   124     mv "tmp-diff" "${dst}/${pname}"
   125     printf " done\n"
   126   fi
   127 
   128   printf "  creating new patched file list..."
   129   diffstat -f 4 -r 2 -u -p 1 "${dst}/${pname}"              \
   130   |head -n -1                                               \
   131   |awk '{ for(i=NF;i>=NF-5;i--) { $(i) = ""; } print; }'    \
   132   |sort                                                     \
   133   >"${dst}/${pname}.diffstat.new"
   134   printf " done\n"
   135 
   136   printf "  removing temporary files/dirs..."
   137   rm -f "patch.out"
   138   rm -f "diffstat.tmp"
   139   rm -rf "${base}.orig"
   140   printf " done\n"
   141 done
   142 
   143 # Scan all new patches to see if they touch
   144 # more files than the original patches
   145 printf "\nChecking resulting patchset:\n"
   146 for p in "${dst}/"*.patch; do
   147   pname="$( basename "${p}" )"
   148 
   149   if ! cmp "${p}.diffstat.orig" "${p}.diffstat.new" >/dev/null; then
   150     printf "  --> '${pname}' differ in touched files <--\n"
   151   fi
   152 done
   153 printf "  done.\n"