scripts/patch-rework.sh
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Mon Aug 23 14:32:16 2010 +0200 (2010-08-23)
changeset 2100 f9fcfc002c8a
child 2147 0ec4491d6496
permissions -rwxr-xr-x
debug/gdb: install dependable libs in a generic target static libs dir

For now, ncurses is the only dependable target library built for gdb.
But expat is coming, and there's no reason to install each library in
its own place.

So, install ncurses in a generic directory, where other dependable
libraries can be installed as well.

Signed-off-by: "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
     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"