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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
|
# $NetBSD: tzdata2netbsd,v 1.7 2015/08/11 18:10:13 apb Exp $
# For use by NetBSD developers when updating to new versions of tzdata.
#
# 0. Be in an up-to-date checkout of src/external/public-domain/tz
# from NetBSD-current.
# 1. Edit OLDVER and NEWVER below.
# 2. Run this script. You will be prompted for confirmation before
# anything major (such as a cvs operation).
# 3. If something fails, abort the script and fix it.
# 4. Re-run this script until you are happy. It's designed to
# be re-run over and over, and later runs will try not to
# redo non-trivial work done by earlier runs.
#
OLDVER=2015e
NEWVER=2015f
# Uppercase variants of OLDVER and NEWVER
OLDVER_UC="$( echo "${OLDVER}" | tr '[a-z]' '[A-Z]' )"
NEWVER_UC="$( echo "${NEWVER}" | tr '[a-z]' '[A-Z]' )"
# Tags for use with version control systems
CVSOLDTAG="TZDATA${OLDVER_UC}"
CVSNEWTAG="TZDATA${NEWVER_UC}"
CVSBRANCHTAG="TZDATA"
GITHUBTAG="${NEWVER}"
# URLs for fetching distribution files, etc.
DISTURL="ftp://ftp.iana.org/tz/releases/tzdata${NEWVER}.tar.gz"
SIGURL="${DISTURL}.asc"
NEWSURL="https://github.com/eggert/tz/raw/${GITHUBTAG}/NEWS"
# Directories
REPODIR="src/external/public-domain/tz/dist" # relative to the NetBSD CVS repo
TZDISTDIR="$(pwd)/dist" # should be .../external/public-domain/tz/dist
WORKDIR="$(pwd)/update-work/${NEWVER}"
EXTRACTDIR="${WORKDIR}/extract"
# Files in the work directory
DISTFILE="${WORKDIR}/${DISTURL##*/}"
SIGFILE="${DISTFILE}.sig"
PGPVERIFYLOG="${WORKDIR}/pgpverify.log"
NEWSFILE="${WORKDIR}/NEWS"
NEWSTRIMFILE="${WORKDIR}/NEWS.trimmed"
IMPORTMSGFILE="${WORKDIR}/import.msg"
IMPORTDONEFILE="${WORKDIR}/import.done"
MERGSMSGFILE="${WORKDIR}/merge.msg"
MERGEDONEFILE="${WORKDIR}/merge.done"
COMMITMERGEDONEFILE="${WORKDIR}/commitmerge.done"
DOIT()
{
local really_do_it=false
local reply
echo "In directory $(pwd)"
echo "ABOUT TO DO:" "$(shell_quote "$@")"
read -p "Really do it? [yes/no/quit] " reply
case "${reply}" in
[yY]*) really_do_it=true ;;
[nN]*) really_do_it=false ;;
[qQ]*)
echo "Aborting"
return 1
;;
esac
if $really_do_it; then
echo "REALLY DOING IT NOW..."
"$@"
else
echo "NOT REALLY DOING THE ABOVE COMMAND"
fi
}
# Quote args to make them safe in the shell.
# Usage: quotedlist="$(shell_quote args...)"
#
# After building up a quoted list, use it by evaling it inside
# double quotes, like this:
# eval "set -- $quotedlist"
# or like this:
# eval "\$command $quotedlist \$filename"
#
shell_quote()
{(
local result=''
local arg qarg
LC_COLLATE=C ; export LC_COLLATE # so [a-zA-Z0-9] works in ASCII
for arg in "$@" ; do
case "${arg}" in
'')
qarg="''"
;;
*[!-./a-zA-Z0-9]*)
# Convert each embedded ' to '\'',
# then insert ' at the beginning of the first line,
# and append ' at the end of the last line.
# Finally, elide unnecessary '' pairs at the
# beginning and end of the result and as part of
# '\'''\'' sequences that result from multiple
# adjacent quotes in he input.
qarg="$(printf "%s\n" "$arg" | \
${SED:-sed} -e "s/'/'\\\\''/g" \
-e "1s/^/'/" -e "\$s/\$/'/" \
-e "1s/^''//" -e "\$s/''\$//" \
-e "s/'''/'/g"
)"
;;
*)
# Arg is not the empty string, and does not contain
# any unsafe characters. Leave it unchanged for
# readability.
qarg="${arg}"
;;
esac
result="${result}${result:+ }${qarg}"
done
printf "%s\n" "$result"
)}
findcvsroot()
{
[ -n "${CVSROOT}" ] && return 0
CVSROOT="$( cat ./CVS/Root )"
[ -n "${CVSROOT}" ] && return 0
echo >&2 "Failed to set CVSROOT value"
return 1
}
mkworkdir()
{
mkdir -p "${WORKDIR}"
}
fetch()
{
[ -f "${DISTFILE}" ] || ftp -o "${DISTFILE}" "${DISTURL}"
[ -f "${SIGFILE}" ] || ftp -o "${SIGFILE}" "${SIGURL}"
[ -f "${NEWSFILE}" ] || ftp -o "${NEWSFILE}" "${NEWSURL}"
}
checksig()
{
{ gpg --verify "${SIGFILE}" "${DISTFILE}"
echo gpg exit status $?
} 2>&1 | tee "${PGPVERIFYLOG}"
# The output should contain lines that match all the following regexps
#
while read line; do
if ! grep -q -e "^${line}\$" "${PGPVERIFYLOG}"; then
echo >&2 "Failed to verify signature: ${line}"
return 1
fi
done <<'EOF'
gpg: Signature made .* using RSA key ID 62AA7E34
gpg: Good signature from "Paul Eggert <eggert@cs.ucla.edu>"
Primary key fingerprint: 7E37 92A9 D8AC F7D6 33BC 1588 ED97 E90E 62AA 7E34
gpg exit status 0
EOF
}
extract()
{
[ -f "${EXTRACTDIR}/zone.tab" ] && return
mkdir -p "${EXTRACTDIR}"
tar -z -xf "${DISTFILE}" -C "${EXTRACTDIR}"
}
addnews()
{
[ -f "${EXTRACTDIR}/NEWS" ] && return
cp -p "${NEWSFILE}" "${EXTRACTDIR}"/NEWS
}
# Find the relevant part of the NEWS file for all releases between
# OLDVER and NEWVER, and save them to NEWSTRIMFILE.
#
trimnews()
{
[ -s "${NEWSTRIMFILE}" ] && return
awk -v oldver="${OLDVER}" -v newver="${NEWVER}" \
'
BEGIN {inrange = 0}
/^Release [0-9]+[a-z]+ - .*/ {
# "Release <version> - <date>"
inrange = ($2 > oldver && $2 <= newver)
}
// { if (inrange) print; }
' \
<"${NEWSFILE}" >"${NEWSTRIMFILE}"
}
# Create IMPORTMSGFILE from NEWSTRIMFILE, by ignoring some sections,
# keeping only the first sentence from paragraphs in other sections,
# and changing the format.
#
# The result should be edited by hand before performing a cvs commit.
# A message to that effect is inserted at the beginning of the file.
#
mkimportmsg()
{
[ -s "${IMPORTMSGFILE}" ] && return
{ cat <<EOF
EDIT ME: Edit this file and then delete the lines marked "EDIT ME".
EDIT ME: This file will be used as a log message for the "cvs commit" that
EDIT ME: imports tzdata${NEWVER}. The initial contents of this file were
EDIT ME: generated from ${NEWSFILE}.
EDIT ME:
EOF
awk -v oldver="${OLDVER}" -v newver="${NEWVER}" \
-v disturl="${DISTURL}" -v newsurl="${NEWSURL}" \
'
BEGIN {
bullet = " * ";
indent = " ";
blankline = 0;
goodsection = 0;
havesentence = 0;
print "Import tzdata"newver" from "disturl;
#print "and NEWS file from "newsurl;
}
/^Release/ {
# "Release <version> - <date>"
ver = $2;
date = gensub(".* - ", "", 1, $0);
print "";
print "Summary of changes in tzdata"ver \
" ("date"):";
}
/^$/ { blankline = 1; havesentence = 0; }
/^ Changes affecting/ { goodsection = 0; }
/^ Changes affecting.*time/ { goodsection = 1; }
/^ Changes affecting.*data/ { goodsection = 1; }
/^ Changes affecting.*documentation/ || \
/^ Changes affecting.*commentary/ {
t = gensub("^ *", "", 1, $0);
t = gensub("\\.*$", ".", 1, t);
print bullet t;
goodsection = 0;
}
/^ .*/ && goodsection {
# In a paragraph in a "good" section.
# Ignore leading spaces, and ignore anything
# after the first sentence.
# First line of paragraph gets a bullet.
t = gensub("^ *", "", 1, $0);
t = gensub("\\. .*", ".", 1, t);
if (blankline) print bullet t;
else if (! havesentence) print indent t;
havesentence = (havesentence || (t ~ "\\.$"));
}
/./ { blankline = 0; }
' \
<"${NEWSTRIMFILE}"
} >"${IMPORTMSGFILE}"
}
editimportmsg()
{
if [ -s "${IMPORTMSGFILE}" ] \
&& ! grep -q '^EDIT' "${IMPORTMSGFILE}"
then
return 0 # file has already been edited
fi
# Pass both IMPORTMSGFILE and NEWSFILE to the editor, so that the
# user can easily consult NEWSFILE while editing IMPORTMSGFILE.
vi "${IMPORTMSGFILE}" "${NEWSFILE}"
}
cvsimport()
{
if [ -e "${IMPORTDONEFILE}" ]; then
cat >&2 <<EOF
The CVS import has already been performed.
EOF
return 0
fi
if ! [ -s "${IMPORTMSGFILE}" ] \
|| grep -q '^EDIT' "${IMPORTMSGFILE}"
then
cat >&2 <<EOF
The message file ${IMPORTMSGFILE}
has not been properly edited.
Not performing cvs import.
EOF
return 1
fi
( cd "${EXTRACTDIR}" &&
DOIT cvs -d "${CVSROOT}" import -m "$(cat "${IMPORTMSGFILE}")" \
"${REPODIR}" "${CVSBRANCHTAG}" "${CVSNEWTAG}"
) && touch "${IMPORTDONEFILE}"
}
cvsmerge()
{
cd "${TZDISTDIR}" || exit 1
if [ -e "${MERGEDONEFILE}" ]; then
cat >&2 <<EOF
The CVS merge has already been performed.
EOF
return 0
fi
DOIT cvs -d "${CVSROOT}" update -j"${CVSOLDTAG}" -j"${CVSNEWTAG}" \
&& touch "${MERGEDONEFILE}"
}
resolveconflicts()
{
cd "${TZDISTDIR}" || exit 1
if grep -l '^[<=>][<=>][<=>]' *
then
cat <<EOF
There appear to be conflicts in the files listed above.
Resolve conflicts, then re-run this script.
EOF
return 1
fi
}
cvscommitmerge()
{
cd "${TZDISTDIR}" || exit 1
if grep -l '^[<=>][<=>][<=>]' *
then
cat >&2 <<EOF
There still appear to be conflicts in the files listed above.
Not performing cvs commit.
EOF
return 1
fi
if [ -e "${COMMITMERGEDONEFILE}" ]; then
cat >&2 <<EOF
The CVS commmit (of the merge result) has already been performed.
EOF
return 0
fi
DOIT cvs -d "${CVSROOT}" commit -m "Merge tzdata${NEWVER}" \
&& touch "${COMMITMERGEDONEFILE}"
}
extra()
{
cat <<EOF
Also do the following:
* Edit src/doc/3RDPARTY
* Edit src/doc/CHANGES
* Edit src/distrib/sets/base/mi if the set of installed files has changed.
* Submit pullup requests for all active release branches.
* rm -rf ${WORKDIR}
EOF
}
main()
{
set -e
findcvsroot
mkworkdir
fetch
checksig
extract
addnews
trimnews
mkimportmsg
editimportmsg
cvsimport
cvsmerge
resolveconflicts
cvscommitmerge
extra
}
main "$@"
|