tzdata2netbsd revision 1.2.4.2 1 # $NetBSD: tzdata2netbsd,v 1.2.4.2 2015/09/10 03:00:37 snj Exp $
2
3 # For use by NetBSD developers when updating to new versions of tzdata.
4 #
5 # 0. Be in an up-to-date checkout of src/external/public-domain/tz
6 # from NetBSD-current.
7 # 1. Edit OLDVER and NEWVER below.
8 # 2. Run this script. You will be prompted for confirmation before
9 # anything major (such as a cvs operation).
10 # 3. If something fails, abort the script and fix it.
11 # 4. Re-run this script until you are happy. It's designed to
12 # be re-run over and over, and later runs will try not to
13 # redo non-trivial work done by earlier runs.
14 #
15
16 OLDVER=2015e
17 NEWVER=2015f
18
19 # Uppercase variants of OLDVER and NEWVER
20 OLDVER_UC="$( echo "${OLDVER}" | tr '[a-z]' '[A-Z]' )"
21 NEWVER_UC="$( echo "${NEWVER}" | tr '[a-z]' '[A-Z]' )"
22
23 # Tags for use with version control systems
24 CVSOLDTAG="TZDATA${OLDVER_UC}"
25 CVSNEWTAG="TZDATA${NEWVER_UC}"
26 CVSBRANCHTAG="TZDATA"
27 GITHUBTAG="${NEWVER}"
28
29 # URLs for fetching distribution files, etc.
30 DISTURL="ftp://ftp.iana.org/tz/releases/tzdata${NEWVER}.tar.gz"
31 SIGURL="${DISTURL}.asc"
32 NEWSURL="https://github.com/eggert/tz/raw/${GITHUBTAG}/NEWS"
33
34 # Directories
35 REPODIR="src/external/public-domain/tz/dist" # relative to the NetBSD CVS repo
36 TZDISTDIR="$(pwd)/dist" # should be .../external/public-domain/tz/dist
37 WORKDIR="$(pwd)/update-work/${NEWVER}"
38 EXTRACTDIR="${WORKDIR}/extract"
39
40 # Files in the work directory
41 DISTFILE="${WORKDIR}/${DISTURL##*/}"
42 SIGFILE="${DISTFILE}.sig"
43 PGPVERIFYLOG="${WORKDIR}/pgpverify.log"
44 NEWSFILE="${WORKDIR}/NEWS"
45 NEWSTRIMFILE="${WORKDIR}/NEWS.trimmed"
46 IMPORTMSGFILE="${WORKDIR}/import.msg"
47 IMPORTDONEFILE="${WORKDIR}/import.done"
48 MERGSMSGFILE="${WORKDIR}/merge.msg"
49 MERGEDONEFILE="${WORKDIR}/merge.done"
50 COMMITMERGEDONEFILE="${WORKDIR}/commitmerge.done"
51
52 DOIT()
53 {
54 local really_do_it=false
55 local reply
56
57 echo "In directory $(pwd)"
58 echo "ABOUT TO DO:" "$(shell_quote "$@")"
59 read -p "Really do it? [yes/no/quit] " reply
60 case "${reply}" in
61 [yY]*) really_do_it=true ;;
62 [nN]*) really_do_it=false ;;
63 [qQ]*)
64 echo "Aborting"
65 return 1
66 ;;
67 esac
68 if $really_do_it; then
69 echo "REALLY DOING IT NOW..."
70 "$@"
71 else
72 echo "NOT REALLY DOING THE ABOVE COMMAND"
73 fi
74 }
75
76 # Quote args to make them safe in the shell.
77 # Usage: quotedlist="$(shell_quote args...)"
78 #
79 # After building up a quoted list, use it by evaling it inside
80 # double quotes, like this:
81 # eval "set -- $quotedlist"
82 # or like this:
83 # eval "\$command $quotedlist \$filename"
84 #
85 shell_quote()
86 {(
87 local result=''
88 local arg qarg
89 LC_COLLATE=C ; export LC_COLLATE # so [a-zA-Z0-9] works in ASCII
90 for arg in "$@" ; do
91 case "${arg}" in
92 '')
93 qarg="''"
94 ;;
95 *[!-./a-zA-Z0-9]*)
96 # Convert each embedded ' to '\'',
97 # then insert ' at the beginning of the first line,
98 # and append ' at the end of the last line.
99 # Finally, elide unnecessary '' pairs at the
100 # beginning and end of the result and as part of
101 # '\'''\'' sequences that result from multiple
102 # adjacent quotes in he input.
103 qarg="$(printf "%s\n" "$arg" | \
104 ${SED:-sed} -e "s/'/'\\\\''/g" \
105 -e "1s/^/'/" -e "\$s/\$/'/" \
106 -e "1s/^''//" -e "\$s/''\$//" \
107 -e "s/'''/'/g"
108 )"
109 ;;
110 *)
111 # Arg is not the empty string, and does not contain
112 # any unsafe characters. Leave it unchanged for
113 # readability.
114 qarg="${arg}"
115 ;;
116 esac
117 result="${result}${result:+ }${qarg}"
118 done
119 printf "%s\n" "$result"
120 )}
121
122 findcvsroot()
123 {
124 [ -n "${CVSROOT}" ] && return 0
125 CVSROOT="$( cat ./CVS/Root )"
126 [ -n "${CVSROOT}" ] && return 0
127 echo >&2 "Failed to set CVSROOT value"
128 return 1
129 }
130
131 mkworkdir()
132 {
133 mkdir -p "${WORKDIR}"
134 }
135
136 fetch()
137 {
138 [ -f "${DISTFILE}" ] || ftp -o "${DISTFILE}" "${DISTURL}"
139 [ -f "${SIGFILE}" ] || ftp -o "${SIGFILE}" "${SIGURL}"
140 [ -f "${NEWSFILE}" ] || ftp -o "${NEWSFILE}" "${NEWSURL}"
141 }
142
143 checksig()
144 {
145 { gpg --verify "${SIGFILE}" "${DISTFILE}"
146 echo gpg exit status $?
147 } 2>&1 | tee "${PGPVERIFYLOG}"
148
149 # The output should contain lines that match all the following regexps
150 #
151 while read line; do
152 if ! grep -q -e "^${line}\$" "${PGPVERIFYLOG}"; then
153 echo >&2 "Failed to verify signature: ${line}"
154 return 1
155 fi
156 done <<'EOF'
157 gpg: Signature made .* using RSA key ID 62AA7E34
158 gpg: Good signature from "Paul Eggert <eggert (a] cs.ucla.edu>"
159 Primary key fingerprint: 7E37 92A9 D8AC F7D6 33BC 1588 ED97 E90E 62AA 7E34
160 gpg exit status 0
161 EOF
162 }
163
164 extract()
165 {
166 [ -f "${EXTRACTDIR}/zone.tab" ] && return
167 mkdir -p "${EXTRACTDIR}"
168 tar -z -xf "${DISTFILE}" -C "${EXTRACTDIR}"
169 }
170
171 addnews()
172 {
173 [ -f "${EXTRACTDIR}/NEWS" ] && return
174 cp -p "${NEWSFILE}" "${EXTRACTDIR}"/NEWS
175 }
176
177 # Find the relevant part of the NEWS file for all releases between
178 # OLDVER and NEWVER, and save them to NEWSTRIMFILE.
179 #
180 trimnews()
181 {
182 [ -s "${NEWSTRIMFILE}" ] && return
183 awk -v oldver="${OLDVER}" -v newver="${NEWVER}" \
184 '
185 BEGIN {inrange = 0}
186 /^Release [0-9]+[a-z]+ - .*/ {
187 # "Release <version> - <date>"
188 inrange = ($2 > oldver && $2 <= newver)
189 }
190 // { if (inrange) print; }
191 ' \
192 <"${NEWSFILE}" >"${NEWSTRIMFILE}"
193 }
194
195 # Create IMPORTMSGFILE from NEWSTRIMFILE, by ignoring some sections,
196 # keeping only the first sentence from paragraphs in other sections,
197 # and changing the format.
198 #
199 # The result should be edited by hand before performing a cvs commit.
200 # A message to that effect is inserted at the beginning of the file.
201 #
202 mkimportmsg()
203 {
204 [ -s "${IMPORTMSGFILE}" ] && return
205 { cat <<EOF
206 EDIT ME: Edit this file and then delete the lines marked "EDIT ME".
207 EDIT ME: This file will be used as a log message for the "cvs commit" that
208 EDIT ME: imports tzdata${NEWVER}. The initial contents of this file were
209 EDIT ME: generated from ${NEWSFILE}.
210 EDIT ME:
211 EOF
212 awk -v oldver="${OLDVER}" -v newver="${NEWVER}" \
213 -v disturl="${DISTURL}" -v newsurl="${NEWSURL}" \
214 '
215 BEGIN {
216 bullet = " * ";
217 indent = " ";
218 blankline = 0;
219 goodsection = 0;
220 havesentence = 0;
221 print "Import tzdata"newver" from "disturl;
222 #print "and NEWS file from "newsurl;
223 }
224 /^Release/ {
225 # "Release <version> - <date>"
226 ver = $2;
227 date = gensub(".* - ", "", 1, $0);
228 print "";
229 print "Summary of changes in tzdata"ver \
230 " ("date"):";
231 }
232 /^$/ { blankline = 1; havesentence = 0; }
233 /^ Changes affecting/ { goodsection = 0; }
234 /^ Changes affecting.*time/ { goodsection = 1; }
235 /^ Changes affecting.*data/ { goodsection = 1; }
236 /^ Changes affecting.*documentation/ || \
237 /^ Changes affecting.*commentary/ {
238 t = gensub("^ *", "", 1, $0);
239 t = gensub("\\.*$", ".", 1, t);
240 print bullet t;
241 goodsection = 0;
242 }
243 /^ .*/ && goodsection {
244 # In a paragraph in a "good" section.
245 # Ignore leading spaces, and ignore anything
246 # after the first sentence.
247 # First line of paragraph gets a bullet.
248 t = gensub("^ *", "", 1, $0);
249 t = gensub("\\. .*", ".", 1, t);
250 if (blankline) print bullet t;
251 else if (! havesentence) print indent t;
252 havesentence = (havesentence || (t ~ "\\.$"));
253 }
254 /./ { blankline = 0; }
255 ' \
256 <"${NEWSTRIMFILE}"
257 } >"${IMPORTMSGFILE}"
258 }
259
260 editimportmsg()
261 {
262 if [ -s "${IMPORTMSGFILE}" ] \
263 && ! grep -q '^EDIT' "${IMPORTMSGFILE}"
264 then
265 return 0 # file has already been edited
266 fi
267 # Pass both IMPORTMSGFILE and NEWSFILE to the editor, so that the
268 # user can easily consult NEWSFILE while editing IMPORTMSGFILE.
269 vi "${IMPORTMSGFILE}" "${NEWSFILE}"
270 }
271
272 cvsimport()
273 {
274 if [ -e "${IMPORTDONEFILE}" ]; then
275 cat >&2 <<EOF
276 The CVS import has already been performed.
277 EOF
278 return 0
279 fi
280 if ! [ -s "${IMPORTMSGFILE}" ] \
281 || grep -q '^EDIT' "${IMPORTMSGFILE}"
282 then
283 cat >&2 <<EOF
284 The message file ${IMPORTMSGFILE}
285 has not been properly edited.
286 Not performing cvs import.
287 EOF
288 return 1
289 fi
290 ( cd "${EXTRACTDIR}" &&
291 DOIT cvs -d "${CVSROOT}" import -m "$(cat "${IMPORTMSGFILE}")" \
292 "${REPODIR}" "${CVSBRANCHTAG}" "${CVSNEWTAG}"
293 ) && touch "${IMPORTDONEFILE}"
294 }
295
296 cvsmerge()
297 {
298
299 cd "${TZDISTDIR}" || exit 1
300 if [ -e "${MERGEDONEFILE}" ]; then
301 cat >&2 <<EOF
302 The CVS merge has already been performed.
303 EOF
304 return 0
305 fi
306 DOIT cvs -d "${CVSROOT}" update -j"${CVSOLDTAG}" -j"${CVSNEWTAG}" \
307 && touch "${MERGEDONEFILE}"
308 }
309
310 resolveconflicts()
311 {
312 cd "${TZDISTDIR}" || exit 1
313 if grep -l '^[<=>][<=>][<=>]' *
314 then
315 cat <<EOF
316 There appear to be conflicts in the files listed above.
317 Resolve conflicts, then re-run this script.
318 EOF
319 return 1
320 fi
321 }
322
323 cvscommitmerge()
324 {
325 cd "${TZDISTDIR}" || exit 1
326 if grep -l '^[<=>][<=>][<=>]' *
327 then
328 cat >&2 <<EOF
329 There still appear to be conflicts in the files listed above.
330 Not performing cvs commit.
331 EOF
332 return 1
333 fi
334 if [ -e "${COMMITMERGEDONEFILE}" ]; then
335 cat >&2 <<EOF
336 The CVS commmit (of the merge result) has already been performed.
337 EOF
338 return 0
339 fi
340 DOIT cvs -d "${CVSROOT}" commit -m "Merge tzdata${NEWVER}" \
341 && touch "${COMMITMERGEDONEFILE}"
342 }
343
344 extra()
345 {
346 cat <<EOF
347 Also do the following:
348 * Edit src/doc/3RDPARTY
349 * Edit src/doc/CHANGES
350 * Edit src/distrib/sets/base/mi if the set of installed files has changed.
351 * Submit pullup requests for all active release branches.
352 * rm -rf ${WORKDIR}
353 EOF
354 }
355
356 main()
357 {
358 set -e
359 findcvsroot
360 mkworkdir
361 fetch
362 checksig
363 extract
364 addnews
365 trimnews
366 mkimportmsg
367 editimportmsg
368 cvsimport
369 cvsmerge
370 resolveconflicts
371 cvscommitmerge
372 extra
373 }
374
375 main "$@"
376