scripts/patch-rework.sh
author "Yann E. MORIN" <yann.morin.1998@free.fr>
Thu Nov 22 19:43:26 2012 +0100 (2012-11-22)
branch1.17
changeset 3130 8db540910974
parent 2224 fc58927f24b8
permissions -rwxr-xr-x
scripts/functions: fix debug-shell

Properly catch resuming the build when continuing past the
failed command.

The 'case ;;&' construct is a bash4ism. Get rid of it.

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