scripts/patch-rework.sh
author "Yann E. MORIN" <yann.morin.1998@free.fr>
Mon May 07 00:27:05 2012 +0200 (2012-05-07)
changeset 2981 80151a249b85
parent 2224 fc58927f24b8
permissions -rwxr-xr-x
samples: use savedefconfig when saving samples

When saving a sample, use savedefconfig instead of copying
the full .config file.

This reduces the saved .config, and reduces clutter when it
is later upgraded.

Also use defconfig when retrieving a sample.

Reported-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.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 do_help() {
    13     cat <<-_EOF_
    14 		${0##*/}: transform a patchset of non-p1 patches into -p1 patches
    15 		
    16 		Usage:
    17 		    ${0##*/} <basedir> <src> <dst> [diffopts ...]
    18 		
    19 		Where:
    20 		    basedir
    21 		        points to the directory of the component to patch
    22 		
    23 		    src
    24 		        points to the directory containing the existing patchset
    25 		        to transform
    26 		
    27 		    dst
    28 		        points to the directory where to put transformed patches
    29 		
    30 		    diffopts
    31 		        optional options to pass to diff, for debug purposes. You
    32 		        should not need it
    33 		
    34 		Example:
    35 		    Transform Gentoo patches against gcc-4.4.2 (some of which are
    36 		    -p0, -p1 or even -p2 patches) into all -p1 patches:
    37 		
    38 		        tar xjf gcc-4.4.2.tar.bz2
    39 		        patch-rework.sh gcc-4.4.2                   \\
    40 		                        /path/to/gentoo/gcc/patches \\
    41 		                        gcc-4.4.2.patches
    42 		_EOF_
    43 }
    44 
    45 # Sanity checks
    46 if [    -z "${base}"                    \
    47      -o ! -d "${base}"                  \
    48      -o ! -d "${src}"                   \
    49      -o -e "${dst}" -a ! -d "${dst}"    \
    50    ]; then
    51 	do_help
    52 	exit 1
    53 fi
    54 
    55 mkdir -p "${dst}"
    56 base="${base%%/}"
    57 src="$( cd "${src}"; pwd )"
    58 dst="$( cd "${dst}"; pwd )"
    59 
    60 # This function checks that the files listed in the file in "$1"
    61 # do exist, at the given depth-stripping level (aka diff -p#)
    62 do_check_files_at_depth() {
    63   local flist="$1"
    64   local depth="$2"
    65   local ret=0   # 0: OK,  !0: KO
    66 
    67   exec 6<&0
    68   exec 7<"${flist}"
    69 
    70   while read -u7 f; do
    71     f="$( echo "${f}" |sed -r -e "s:^([^/]+/){${depth}}::;" )"
    72     [ -f "${f}" ] || ret=1
    73   done
    74 
    75   exec 7<&-
    76   exec <&6
    77 
    78   return ${ret}
    79 }
    80 
    81 # Iterate through patches
    82 for p in "${src}/"*.patch; do
    83   pname="$( basename "${p}" )"
    84 
    85   printf "Handling patch '${pname}'...\n"
    86 
    87   printf "  creating reference..."
    88   cp -a "${base}" "${base}.orig"
    89   printf " done\n"
    90 
    91   printf "  retrieving patch comment..."
    92   comment="$( awk '
    93 BEGIN { mark=0; }
    94 $0~/^diff --/ { nextfile; }
    95 $1=="---" { mark=1; next; }
    96 $1=="+++" && mark==1 { nextfile; }
    97 { mark=0; print; }
    98 ' "${p}" )"
    99   printf " done\n"
   100 
   101   printf "  creating patched file list..."
   102   diffstat -f 4 -r 2 -u -p 0 "${p}"                         \
   103   |head -n -1                                               \
   104   |awk '{ for(i=NF;i>=NF-5;i--) { $(i) = ""; } print; }'    \
   105   |sort                                                     \
   106   >"diffstat.orig"
   107   printf " done\n"
   108 
   109   pushd "${base}" >/dev/null 2>&1
   110 
   111   # Check all files exist, up to depth 3
   112   printf "  checking depth:"
   113   for((d=0;d<4;d++)); do
   114     printf " ${d}"
   115     if do_check_files_at_depth "../diffstat.orig" ${d}; then
   116       printf " ok, using depth '${d}'\n"
   117       break
   118     fi
   119   done
   120   if [ ${d} -ge 4 ]; then
   121     printf "\n"
   122     printf "  checking depth failed\n"
   123     read -p "  --> enter patch depth (or Ctrl-C to abort): " d
   124   fi
   125 
   126   # Store the original list of files touched by the patch,
   127   # removing the $d leading components
   128   sed -r -e "s:^([^/]+/){${d}}::;" "../diffstat.orig" >"${dst}/${pname}.diffstat.orig"
   129 
   130   # Apply the patch proper, and check it applied cleanly.
   131   # We can't check with --dry-run because of patches that
   132   # contain multiple accumulated patches onto a single file.
   133   printf "  applying patch..."
   134   if ! patch -g0 -F1 -f -p${d} <"${p}" >"../patch.out" 2>&1; then
   135     printf " ERROR\n\n"
   136     popd >/dev/null 2>&1
   137     printf "There was an error while applying:\n  -->  ${p}  <--\n"
   138     printf "'${base}' was restored to the state it was prior to applying this faulty patch.\n"
   139     printf "Here's the 'patch' command, and its output:\n"
   140     printf "  ----8<----\n"
   141     printf "  patch -g0 -F1 -f -p${d} <'${p}'\n"
   142     sed -r -e 's/^/  /;' "patch.out"
   143     printf "  ----8<----\n"
   144     exit 1
   145   fi
   146   printf " done\n"
   147 
   148   printf "  removing '.orig' files..."
   149   find . -type f -name '*.orig' -exec rm -f {} +
   150   printf " done\n"
   151 
   152   popd >/dev/null 2>&1
   153 
   154   printf "  re-diffing the patch..."
   155   printf "%s\n\n" "${comment}" >"${dst}/${pname}"
   156   diff -durN "${base}.orig" "${base}" >>"${dst}/${pname}"
   157   printf " done\n"
   158 
   159   if [ -n "${diff}" ]; then
   160     printf "  applying diff filter..."
   161     filterdiff -x "${diff}" "${dst}/${pname}" >"tmp-diff"
   162     mv "tmp-diff" "${dst}/${pname}"
   163     printf " done\n"
   164   fi
   165 
   166   printf "  creating new patched file list..."
   167   diffstat -f 4 -r 2 -u -p 1 "${dst}/${pname}"              \
   168   |head -n -1                                               \
   169   |awk '{ for(i=NF;i>=NF-5;i--) { $(i) = ""; } print; }'    \
   170   |sort                                                     \
   171   >"${dst}/${pname}.diffstat.new"
   172   printf " done\n"
   173 
   174   printf "  removing temporary files/dirs..."
   175   rm -f "patch.out"
   176   rm -f "diffstat.tmp"
   177   rm -f "diffstat.orig"
   178   rm -rf "${base}.orig"
   179   printf " done\n"
   180 done
   181 
   182 # Scan all new patches to see if they touch
   183 # more files than the original patches
   184 printf "\nChecking resulting patchset:\n"
   185 for p in "${dst}/"*.patch; do
   186   pname="$( basename "${p}" )"
   187 
   188   if ! cmp "${p}.diffstat.orig" "${p}.diffstat.new" >/dev/null; then
   189     printf "  --> '${pname}' differ in touched files <--\n"
   190   else
   191     rm -f "${p}.diffstat.orig" "${p}.diffstat.new"
   192   fi
   193 done
   194 printf "  done.\n"