Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-ports-kde
Path: blob/main/Mk/Scripts/smart_makepatch.sh
16461 views
1
#!/bin/sh
2
# MAINTAINER: [email protected]
3
4
# This script regenerates patches. It conserves existing comments and
5
# file names, even if the file name does not meet any current or
6
# previous convention. It will keep multiple patches in the same file
7
# rather than splitting them into individual files.
8
#
9
# If a generated patch was not present before, it will create a file
10
# name where forward slashes are replaced with an underscore and
11
# underscores are appended by another underscore.
12
#
13
# Limitations:
14
# 1) If a file is modified by multiple patches, it will be regenerated
15
# as a single patch. That means if two multi-patch files modified
16
# the same source file, when regenerated, the source file's patch
17
# will only appear in one of patch file.
18
# 2) It's possible that trailing garbage at the end of a patch in a
19
# multipatch file might corrupt the comment (or be interpreted as
20
# a comment) of the following patch. (garbage in, garbage out)
21
#
22
# Reminder
23
# Don't forget to disable post-patch targets before regenerating patches
24
# if those targets modify source files (e.g. with sed). You may also
25
# want to disable EXTRA_PATCHES as well if that is being used.
26
27
set -o pipefail
28
29
[ -n "${DEBUG_MK_SCRIPTS}" -o -n "${DEBUG_MK_SCRIPTS_SMART_MAKEPATCH}" ] && set -x
30
31
if [ -z "${PATCHDIR}" -o -z "${PATCH_WRKSRC}" -o -z "${WRKDIR}" ]; then
32
echo "WRKDIR, PATCHDIR, and PATCH_WRKSRC required in environment." >&2
33
exit 1
34
fi
35
36
WORKAREA=${WRKDIR}/.makepatch-tmp
37
PATCHMAP=${WORKAREA}/pregen.map
38
COMMENTS=${WORKAREA}/comments
39
REGENNED=${WORKAREA}/regenerated
40
DESTDIR=${WORKAREA}/staged
41
SAVEDIR=${WORKAREA}/archived-patches
42
43
case "${STRIP_COMPONENTS}" in
44
[123456789]) ;;
45
1[0123456789]) ;;
46
*) STRIP_COMPONENTS=0
47
esac
48
49
strip_path() {
50
local raw_name=$1
51
if [ "${STRIP_COMPONENTS}" = "0" ]; then
52
echo ${raw_name}
53
else
54
echo ${raw_name} | awk -v sc=${STRIP_COMPONENTS} -F "/" \
55
'{ for (x = sc + 1; x <= NF; x++) {
56
slash = (x>sc+1) ? "/" : "";
57
printf ("%s%s", slash, $x);
58
}}'
59
fi
60
}
61
62
std_patch_filename() {
63
local sans_cwd
64
local raw_name
65
sans_cwd=$(echo $1 | sed 's|^\.\/||')
66
raw_name=$(strip_path ${sans_cwd})
67
echo "patch-$(echo ${raw_name} | sed -e 's|_|&&|g; s|/|_|g')"
68
}
69
70
patchdir_files_list() {
71
if [ -d "${PATCHDIR}" ]; then
72
(cd ${PATCHDIR} && \
73
find -s . -type f -name "patch-*" -maxdepth 1 \
74
2>/dev/null | sed -e 's,^\./,,; /\.orig$/d'
75
)
76
fi;
77
}
78
79
valid_name() {
80
local current_patch_name=$1
81
local result=$3
82
local first_target
83
local testres
84
local lps
85
first_target=$(echo $2 | sed 's|^\.\/||')
86
for lps in __ - + ; do
87
testres=patch-$(echo ${first_target} | sed -e "s|/|${lps}|g")
88
if [ "${testres}" = "${current_patch_name}" ]; then
89
result=${testres}
90
break
91
fi
92
done
93
echo ${result}
94
}
95
96
map_existing_patches() {
97
mkdir -p ${WORKAREA}
98
: > ${PATCHMAP}
99
local target
100
local future_name
101
local std_target
102
local P
103
local t
104
for P in ${old_patch_list}; do
105
target=$(cd ${PATCHDIR} && \
106
grep "^+++ " ${P} | awk '{print $2}'
107
)
108
# For single patches, we honor previous separators, but use
109
# a standard patch name if the current patch name does not
110
# conform. However, if two or more patches are contained in
111
# single file, then we do *NOT* rename the file
112
future_name=
113
for t in ${target}; do
114
if [ -n "${future_name}" ]; then
115
future_name=${P}
116
break;
117
fi
118
std_target=$(std_patch_filename ${t})
119
future_name=$(valid_name ${P} ${t} ${std_target})
120
done
121
for t in ${target}; do
122
std_target=$(std_patch_filename ${t})
123
echo "${future_name} ${std_target}" >> ${PATCHMAP}
124
done
125
done
126
}
127
128
extract_comment_from_patch() {
129
local existing_patch=${PATCHDIR}/$1
130
local contains
131
local rawname
132
local fname
133
local num
134
contains=$(grep "^+++ " ${existing_patch} | awk '{x++; print x}')
135
for num in ${contains}; do
136
rawname=$(grep "^+++ " ${existing_patch} | \
137
awk -v num=${num} '{x++; if (x==num) print $2}')
138
fname=$(std_patch_filename $rawname)
139
awk -v num=${num} '
140
BEGIN { done=0; x=0; hunk=0; looking=(num==1) }
141
{
142
if (!done) {
143
if ($1 == "@@") {
144
split ($2,a,",");
145
split ($3,b,",");
146
hca = a[2];
147
hcb = a[3];
148
hunk = 1;
149
} else if (hunk) {
150
first=substr($1,1,1);
151
if (first == "-") { hca-- }
152
else if (first == "+") { hcb-- }
153
else {hca--; hcb--}
154
if (hca == 0 && hcb == 0) {hunk = 0}
155
}
156
if ($1 == "---") {
157
x++;
158
if (x == num) { done = 1 }
159
if (x + 1 == num) { looking = 1 }
160
} else if (!hunk && looking) {
161
if ($1!="diff" && $1!="index" && $1!="+++") {
162
print $0
163
}
164
}
165
}
166
}' ${existing_patch} > ${COMMENTS}/${fname}
167
done
168
}
169
170
extract_comments() {
171
mkdir -p ${COMMENTS}
172
rm -f ${COMMENTS}/*
173
local P
174
for P in ${old_patch_list}; do
175
extract_comment_from_patch ${P}
176
done
177
}
178
179
regenerate_patches() {
180
mkdir -p ${REGENNED}
181
rm -f ${REGENNED}/*
182
[ ! -d "${PATCH_WRKSRC}" ] && return
183
184
local F
185
local NEW
186
local OUT
187
local ORIG
188
local new_list
189
new_list=$(cd "${PATCH_WRKSRC}" && \
190
find -s . -type f -name '*.orig' 2>/dev/null)
191
(cd "${PATCH_WRKSRC}" && for F in ${new_list}; do
192
ORIG=${F#./}
193
NEW=${ORIG%.orig}
194
cmp -s ${ORIG} ${NEW} && continue
195
OUT=${REGENNED}/$(std_patch_filename ${NEW})
196
TZ=UTC diff -audp ${ORIG} ${NEW} | sed \
197
-e '/^---/s|\.[0-9]* +0000$| UTC|' \
198
-e '/^+++/s|\([[:blank:]][-0-9:.+]*\)*$||' \
199
> ${OUT} || true
200
done)
201
}
202
203
get_patch_name() {
204
awk -v name=$1 '
205
{ if ($2 == name)
206
{
207
if (!done) { print $1 };
208
done = 1;
209
}
210
}
211
END { if (!done) print name }' ${PATCHMAP}
212
}
213
214
stage_patches() {
215
mkdir -p ${DESTDIR}
216
rm -f ${DESTDIR}/*
217
local P
218
local name
219
local patch_list
220
patch_list=$(cd ${REGENNED} && find -s . -name "patch-*" 2>/dev/null)
221
for P in ${patch_list}; do
222
P=${P#./}
223
name=$(get_patch_name ${P})
224
[ -e ${COMMENTS}/${P} ] && cat ${COMMENTS}/${P} \
225
>> ${DESTDIR}/${name}
226
if [ "${P}" = "${name}" ]; then
227
echo "Generated ${P}"
228
else
229
echo "Generated ${P} >> ${name} (legacy)"
230
fi
231
cat ${REGENNED}/${P} >> ${DESTDIR}/${name}
232
done
233
}
234
235
compare_common_patches() {
236
[ -z "${old_patch_list}" ] && return
237
local archive_patch_list
238
local P
239
local ppatch
240
local ppatch_stripped
241
local cpatch
242
local cpatch_stripped
243
for P in ${old_patch_list}; do
244
if [ -e ${DESTDIR}/${P} ]; then
245
ppatch=${PATCHDIR}/${P}
246
cpatch=${DESTDIR}/${P}
247
ppatch_stripped=$(mktemp -t portpatch)
248
cpatch_stripped=$(mktemp -t portpatch)
249
sed -E -e '/^--- .+ UTC$/d; s/^(@@ [^@]* @@).*/\1/' \
250
${ppatch} > ${ppatch_stripped}
251
sed -E -e '/^--- .+ UTC$/d; s/^(@@ [^@]* @@).*/\1/' \
252
${cpatch} > ${cpatch_stripped}
253
# Don't replace patches with only metadata changes
254
if ! cmp -s ${ppatch_stripped} ${cpatch_stripped}; then
255
archive_patch_list="${archive_patch_list} ${P}"
256
else
257
echo "${P} only contains metadata changes; not replacing"
258
rm ${cpatch}
259
fi
260
rm ${ppatch_stripped}
261
rm ${cpatch_stripped}
262
fi
263
done
264
old_patch_list=${archive_patch_list}
265
}
266
267
conserve_old_patches() {
268
mkdir -p ${SAVEDIR}
269
rm -f ${SAVEDIR}/*
270
[ -z "${old_patch_list}" ] && return
271
272
local P
273
for P in ${old_patch_list}; do
274
mv ${PATCHDIR}/${P} ${SAVEDIR}/${P}
275
done
276
echo "The previous patches have been placed here:"
277
echo ${SAVEDIR}
278
}
279
280
install_regenerated_patches() {
281
local testdir
282
testdir=$(find ${DESTDIR} -empty)
283
if [ -z "${testdir}" ]; then
284
mkdir -p ${PATCHDIR}
285
find ${DESTDIR} -type f -exec mv {} ${PATCHDIR}/ \;
286
fi
287
}
288
289
old_patch_list=$(patchdir_files_list)
290
291
map_existing_patches
292
extract_comments
293
regenerate_patches
294
stage_patches
295
compare_common_patches
296
conserve_old_patches
297
install_regenerated_patches
298
299