-
Notifications
You must be signed in to change notification settings - Fork 3
/
rediff_patch
executable file
·184 lines (161 loc) · 5.71 KB
/
rediff_patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!/bin/bash
#
# Try to rediff a given patch - unpack tarball, apply the patch with default fuzz and '--force'
# and diff old and new folders to a new patch.
#
# The patch should be provided as an argument; if no argument is specified and there is only one *patch file
# in the current folder, that patch file will be used.
#
# The working folder should contain a spec file from which we know how to apply the patch
#
# If patch fails to apply, the script leaves original and new folders, so you can analyze rejected hunks
#
# Author: Denis Silakov, ROSA, [email protected]
#
shopt -s nullglob
spec_count=$(ls -1 *spec 2>/dev/null | wc -l)
if [[ $spec_count != 1 ]]; then
echo "Can't detect spec file to work with - current folder either contains no spec files or contains several spec files."
exit
fi
target_patch=$1
tarball=$2
if [[ $target_patch == '-h' || $target_patch == '--help' ]]; then
echo "USAGE: $0 [patch_to_rediff] [source_tarball] "
echo " * if patch is not specified and the current folder contains only one patch,"
echo " then that patch will be rediffed"
echo " * if tarball is not specified and the current folder contains only one tarball,"
echo " then the patch will be applied to content of that tarball"
echo " * all actions are performed in rediff_patch subfolder of the current folder"
echo " if rediff fails, that subfolder will not be removed and you will be able to "
echo " finalize rediff manually"
exit 1
fi
# Remember number of patch files in current dir
patch_count=$(ls -1 *patch 2>/dev/null | wc -l)
if [[ "${target_patch}" == "" ]]; then
# if no patch is provided as script argument and there is only a single patch in the folder,
# let's proceed with that patch. Otherwise, exit
if [[ $patch_count != 1 ]]; then
if [[ $patch_count == 0 ]]; then
echo "No patch specified as an argument and current directory contains no patches"
else
echo "No patch specified as an argument and current directory contains more than one patch file"
fi
exit 1
else
target_patch=$(ls -1 *patch)
echo "No patch specified as an argument, processing ${target_patch}"
fi
fi
# Detect how the patch should be applied
grep -q '%apply_patches' *.spec
if [[ $? == 0 ]]; then
# %apply_patches is used
patch_cmd="patch -p1 --force"
elif [[ $patch_count == 1 ]]; then
# only one patch and no %apply_patches, so we can expect the only %patch command in the spec
patch_cmd=$(grep '^%patch' *spec | cut -f1,2 -d- | sed 's/^%patch[[:digit:]]*/patch --force /')
else
# grep for Patch: record in spec corresponding to our patch
# drop name from the beginning of the patch name,
# since one can use %name or %{name} in patch name in spec
project=$(basename "$PWD")
patch_num=$(grep "^Patch.*${target_patch/$project/}" *spec | sed 's/^Patch\([[:digit:]]*\).*$/\1/')
# now grep for necessary %patch command
patch_cmd=$(grep "\%patch${patch_num}[[:space:]]\|\%patch${patch_num}\$" *spec | cut -f1,2 -d- | sed 's/^\%patch[[:digit:]]*/patch --force /')
fi
rm -rf rediff_patch
mkdir rediff_patch
pushd rediff_patch
# if we have relative path, add "../" to it
echo $tarball | grep -q "^/"
if [[ $? != 0 ]]; then
tarball="../$tarball"
fi
# tarball is specified in cmd line, let's unpack it
if [[ $tarball =~ ".tar.gz" ]]; then
tar xzf $tarball
elif [[ $tarball =~ ".tgz" ]]; then
tar xzf $tarball
elif [[ $tarball =~ ".tar.Z" ]]; then
tar xZf $tarball
elif [[ $tarball =~ ".tar.bz2" ]]; then
tar xjf $tarball
elif [[ $tarball =~ ".tbz2" ]]; then
tar xjf $tarball
elif [[ $tarball =~ ".tar.xz" ]]; then
tar xJf $tarball
elif [[ $tarball =~ ".zip" ]]; then
unzip $tarball
elif [[ ! $tarball =~ "" ]]; then
echo "Tarball type is not recognized, failed to unpack"
popd
rm -rf rediff_patch
exit 1
fi
# Tarball is not specified - let's detect it
# We only support the situaiton with single tarball in the folder
if [[ -n $(echo ../*.tar.gz) ]]; then
tar xzf ../*tar.gz
elif [[ -n $(echo ../*.tgz) ]]; then
tar xzf ../*tgz
elif [[ -n $(echo ../*.tar.Z) ]]; then
tar xZf ../*tar.Z
elif [[ -n $(echo ../*.tar.bz2) ]]; then
tar xjf ../*tar.bz2
elif [[ -n $(echo ../*.tbz2) ]]; then
tar xjf ../*tbz2
elif [[ -n $(echo ../*.tar.xz) ]]; then
tar xJf ../*tar.xz
elif [[ -n $(echo ../*.zip) ]]; then
unzip ../*zip
fi
# Let's check how many folders exist in the current one after tarball unpacking
# We support only the situation when we have a single folder (except .git)
# which will be subjected to patching then
count=$(ls -l | grep -v .git | grep '^d' 2>/dev/null | wc -l)
if [[ $count != 1 ]]; then
if [[ $count == 0 ]]; then
echo "No folders, something went wrong with unpacking of tarball"
else
echo "More than one folder found - it seems that we have a tarball bomb, this is not curently supported"
fi
popd
exit 1
fi
# Create folder backup and try to apply the patch
folder=$(ls -l | grep '^d' | rev | cut -f1 -d\ | rev)
cp -r $folder ${folder}.orig
cp ../$target_patch $folder
cd $folder
failed=0
echo "$patch_cmd < $target_patch"
$patch_cmd < $target_patch
if [[ $? != 0 ]]; then
failed=1
echo "Rediff failed, you should rework the patch"
fi
cd ..
if [[ $failed == 0 ]]; then
# Patch succeeded, let's recreate it
rm -f $folder/$target_patch
find $folder -name "*.orig" -delete
diff -Naur ${folder}.orig $folder > ../${target_patch}.new
# .. and replace patch command in spec
# in case of %apply_patches, nothing to do
grep -q '%apply_patches' ../*.spec
if [[ $? != 0 ]]; then
if [[ $patch_count == 1 ]]; then
sed -i 's/^\%patch\(.*\) -p[[:digit:]]*/\%patch\1 -p1/' ../*spec
else
sed -i "s/^\%patch${patch_num} -p[[:digit:]]*/\%patch${patch_num} -p1/" ../*spec
fi
fi
rm -rf ${folder}.orig $folder
else
popd # out from rediff_patch folder
exit 1
fi
popd # out from rediff_patch folder
rm -rf rediff_patch