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