tzdata2netbsd revision 1.18 1 # $NetBSD: tzdata2netbsd,v 1.18 2026/03/16 11:51:35 kre 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. Make sure that you have Paul Eggert's 4K RSA public key in your
8 # keyring (62AA7E34, eggert (a] cs.ucla.edu) It is not required that it be trusted.
9 # 2. Run this script. You will be prompted for confirmation before
10 # anything major (such as a cvs operation). The tz versions can be
11 # specified as args (new version first, and the previous second) if
12 # needed to override the calculated values
13 # 3. If something fails, abort the script and fix it.
14 # 4. Re-run this script until you are happy. It's designed to
15 # be re-run over and over, and later runs will try not to
16 # redo non-trivial work done by earlier runs.
17 #
18
19 VERS_PATTERN='2[0-9][0-9][0-9][a-z]'
20 # This needs to be updated twice every millennium to allow for the
21 # new millenium's years.
22 # First in the late xx90's sometime, allow the new one by changing the leading
23 # digit from a specific value to the class containing the current and
24 # following values (eg: in 2098 or so, change '2' to be '[23]').
25 # Then in the following early xx00's sometime, delete the class, and
26 # leave only the current value as valid (eg: in 3001 or 3002,
27 # change '[23]' to be just '3'
28 # Doing it this way helps guard against invalid specifications.
29 # We could automate this, but it is (IMO) not worth the cost, to avoid a
30 # twice a millenium edit requirement.
31 # A more significant (and harder) change will be needed in the late 9990's
32 # If this script lasts until then, send me a postcard, I'll be waiting for it!
33 # Things get easier again after that until the late 99990's (etc.)
34
35 # Note the pattern is used on both the old and new version specifiers,
36 # so it must be able to cope with the shift from one form (eg 2999g)
37 # to the new one (eg: 3000a) without failing (or the code that uses it
38 # below needs to be updated).
39
40 # Also note that the option of having a second alpha (1997aa or something)
41 # to handle years with much activity is handled below, the pattern does not
42 # need to match those.
43 # If that convention changes (as of date of writing, it has never been
44 # exercised) then code changes below will be required.
45 # Note it doesn't matter (here) if nnnnz is followed by nnnnaa or nnnnza
46
47 DIST_HOST=ftp.iana.org
48 DIST_PATH=tz
49 DIST_FILES=releases
50
51 GTZURL=https://github.com/JodaOrg/global-tz/releases/download
52
53 EDITOR=${EDITOR:-vi}
54
55 TZBASE=$(pwd) || fail "Cannot find myself (${PWD})"
56 cd -P "$TZBASE" || fail "Cannot return home: ${TZBASE}"
57
58 if [ "${TZBASE}" != "${PWD}" ]
59 then
60 fail "TZBASE!=PWD ?? TZBASE='${TZBASE}' PWD='${PWD}'"
61 fi
62
63 WORK_PFX=${TZBASE}/update-work
64 UPDATE_FROM=${WORK_PFX}/updating.from.version
65
66 usage()
67 {
68 printf >&2 '%s\n' '' \
69 "Usage: $0 [new-version-id [old-version-id]]" '' \
70 " where a version-id is of the form YYYYx (eg: 2018c)" \
71 " or '' for new-version-id (to specify only the old)" \
72 " and where new-version-id can have =fetch-version-id" \
73 " appended to specify fetching that version instead" \
74 " where the 'fetch-version-id' can be omitted if it" \
75 " is \${new-version-id}gtz - and simply using '=' means" \
76 " to work out the new-version-id but then use the gtz fork"
77
78 printf >&2 '\nUsually use:\n\t\tsh %s =\n' "${0##*/}"
79
80 exit 2
81 }
82
83 fail()
84 {
85 local IFS=' '
86
87 printf >&2 '%s\n' "Error detected:" " $*" "Aborting."
88 exit 1
89 }
90
91 find_netbsdsrc()
92 {
93 while ! [ -f UPDATING ] || ! [ -f BUILDING ]
94 do
95 if [ "${PWD}" = / ]
96 then
97 printf '%s\n' 'Unable to find NETBSDSRCDIR'
98 return 1
99 fi
100 cd -P ..
101 done
102 NETBSDSRCDIR=${PWD}
103 cd -P "${TZBASE:-/nowhere/that/exists}" ||
104 fail 'Unable to return to TZBASE:' "${TZBASE}"
105 }
106
107 valid_vers()
108 {
109 case "$2" in
110 # The IANA (Eggert) standard version names
111 ( ${VERS_PATTERN} | ${VERS_PATTERN}[a-z] )
112 ;;
113 # The alternate (more rational) fork "global timezone" version
114 ( ${VERS_PATTERN}gtz | ${VERS_PATTERN}[a-z]gtz )
115 ;;
116 (*) printf >&2 '%s: %s\n' \
117 "Bad form for $1 version specifier '$2'" \
118 "should (usually) be 'YYYYx'"
119 return 1
120 ;;
121 esac
122 return 0
123 }
124
125 get_curvers()
126 {
127 local LF=''
128 local LIST=iana-listing
129 local SED_SCRIPT='
130 /tzdata-latest.*-> /{
131 s/^.*-> //
132 s/\..*$//
133 s;^releases/tzdata;;p
134 q
135 }
136 d'
137
138 test -d "${WORK_PFX}" &&
139 test -s "${WORK_PFX}/${LIST}" &&
140 test "${WORK_PFX}/${LIST}" -nt dist/CVS &&
141 LF=$(find "${WORK_PFX}" -name "${LIST}" -mtime -1 -print) &&
142 test -n "${LF}" &&
143 NEWVER=$(sed -n < "${LF}" "${SED_SCRIPT}") &&
144 valid_vers new "${NEWVER}" ||
145
146 ftp >/dev/null 2>&1 -ia "${DIST_HOST}" <<- EOF &&
147 dir ${DIST_PATH} ${WORK_PFX}/${LIST}
148 quit
149 EOF
150 test -s "${WORK_PFX}/${LIST}" &&
151 NEWVER=$(sed -n < "${WORK_PFX}/${LIST}" "${SED_SCRIPT}") &&
152 valid_vers new "${NEWVER}" ||
153
154 {
155 rm -f "${WORK_PFX}/${LIST}"
156 fail "Cannot fetch current tzdata version from ${DIST_HOST}"
157 }
158
159 printf 'Updating from %s to %s\n' "${OLDVER}" "${NEWVER}"
160 }
161
162 argparse()
163 {
164 local OVF OV NV OVy OVs NVy NVs
165
166 if OVF=$(find "${WORK_PFX}" -name "${UPDATE_FROM##*/}" -mtime +2 -print)
167 then
168 # delete anything old
169 test -n "${OVF}" && rm -f "${OVF}"
170 fi
171
172 case "$#" in
173 ( 0 | 1 )
174 # once we have obtained OLDVER once, never guess it again.
175 if [ -f "${UPDATE_FROM}" ]
176 then
177 OLDVER=$(cat "${UPDATE_FROM}")
178 elif [ -f dist/TZDATA_VERSION ]
179 then
180 OLDVER=$(cat dist/TZDATA_VERSION)
181 elif [ -f dist/version ]
182 then
183 OLDVER=$(cat dist/version)
184 fi
185 OLDVER=${OLDVER#tzdata} # TZDATA_VERS is tzdata-nnnnX
186 OLDVER=${OLDVER#-} # but the '-' is optional
187 OLDVERGTZ=${OLDVER} # This would have been the cvs tag
188 OLDVER=${OLDVER%gtz} # want the base version elsewhere
189
190 if [ -z "${OLDVER}" ]
191 then
192 printf >&2 '%s\n' \
193 'Cannot determine current installed version' \
194 'Specify it on the command line.' \
195 ''
196 usage
197 fi
198
199 valid_vers old "${OLDVER}" ||
200 fail "Calculated bad OLDVER, give as 2nd arg"
201 ;;
202
203 ( 2 ) valid_vers old "$2" && OLDVER="$2" || usage
204 ;;
205
206 ( * ) usage
207 ;;
208 esac
209
210 GLOBAL=false
211 case "$#:$1" in
212 ( 0: | 1: | 2: )
213 ;;
214 ( 1:= | 2:= )
215 GLOBAL=true;;
216 ( 1:=?* | 2:=?* )
217 valid_vers fetch "${1#=}" && FETCHVER="${1#=}" || usage
218 ;;
219 ( 1:*=?* | 2:*=?* )
220 set -- "{$1%=*}" "${1#*=}"
221 valid_vers fetch "$2" && FETCHVER="$2" || usage
222 valid_vers new "$1" && NEWVER="$1" || usage
223 ;;
224 ( 1:?* | 2:?* )
225 valid_vers new "$1" && NEWVER="$1" || usage
226 ;;
227 ( * ) usage
228 ;;
229 esac
230
231 test -z "${NEWVER}" && get_curvers
232
233 if [ -z "${FETCHVER}" ]
234 then
235 if "${GLOBAL}"
236 then
237 FETCHVER=${NEWVER}gtz
238 else
239 FETCHVER=${NEWVER}
240 fi
241 fi
242
243 case "${FETCHVER}" in
244 ( *gtz ) GLOBAL=true;;
245 ( * ) GLOBAL=false;;
246 esac
247
248 if [ "${NEWVER}" = "${OLDVER}" ]
249 then
250 printf 'New and old versions both %s; nothing to do\n' \
251 "${NEWVER}"
252 docupdate
253 exit 0
254 fi
255
256 if ! "${GLOBAL}"
257 then
258 local reply
259
260 printf 'This will not use the GTZ variant of tzdata.\n'
261 read -r -p 'Is that intended? ' reply
262 case "${reply}" in
263 ([Yy]*) ;;
264 (*) printf 'Aborting after doing nothing\n'; exit 1;;
265 esac
266 fi
267
268 printf '%s\n' "${OLDVER}" > "${UPDATE_FROM}" ||
269 fail "Unable to preserve old version ${OLDVER} in ${UPDATE_FROM}"
270
271 # Do version upgrade test using base version names, ignoring
272 # the "gtz" in the "global timezone" versions, so we can
273 # switch back and forth between use of those as circumstances change
274 OV=${OLDVER%gtz}
275 NV=${NEWVER%gtz}
276
277 OVy=${OV%%[!0-9]*}
278 OVs=${OV#${OVy}}
279 NVy=${NV%%[!0-9]*}
280 NVs=${NV#${NVy}}
281
282 # To get all the permutations correct, we need to separate
283 # the year and suffix parts of the version IDs (done just above)
284 # and then compare them separately. The suffix is only relevant
285 # to the result when the years are the same.
286
287 # We compare the length of the suffix separately to the suffix
288 # itself, a multi-char suffix has never happened (and is never
289 # likely to) - but in the event that prediction is wrong, we don't
290 # know (yet) what is to come after 'z' - it might be 'za' 'zb'
291 # ... to 'zz" then 'zza' ... or it might be 'aa' 'ab' ... 'az' 'ba'...
292 # we need to handle both possibilities. Two things stand out from
293 # those: 1. a longer suffix is always going to be for a newer version
294 # than a shorter one; 2. equal length suffixes can be compared as
295 # strings
296
297 if [ "${OVy}" -gt "${NVy}" ] || {
298 [ "${OVy}" -eq "${NVy}" ] && {
299 [ "${#OVs}" -gt "${#NVs}" ] ||
300 LC_COLLATE=C [ "${OVs}" '>' "${NVs}" ]
301 }
302 } then
303 local reply
304
305 printf '%s\n' "Update would revert ${OLDVER} to ${NEWVER}"
306 read -p "Is reversion intended? " reply
307 case "${reply}" in
308 ([Yy]*) ;;
309 (*) printf '%s\n' OK. Aborted.
310 rm -f "${UPDATE_FROM}"
311 exit 1
312 ;;
313 esac
314 fi
315
316 return 0
317 }
318
319 setup_versions()
320 {
321 # Uppercase variants of OLDVER and NEWVER
322 OLDVER_UC="$( printf '%s\n' "${OLDVERGTZ}" | tr 'a-z' 'A-Z' )"
323 NEWVER_UC="$( printf '%s\n' "${NEWVER}" | tr 'a-z' 'A-Z' )"
324
325 # Tags for use with version control systems
326 CVSOLDTAG="TZDATA${OLDVER_UC}"
327 CVSNEWTAG="TZDATA${NEWVER_UC}"
328 CVSBRANCHTAG="TZDATA"
329 GITHUBTAG="${NEWVER}"
330
331 if "${GLOBAL}" && [ "${CVSNEWTAG%GTZ}" = "${CVSNEWTAG}" ]
332 then
333 CVSNEWTAG=${CVSNEWTAG}GTZ
334 fi
335
336 # URLs for fetching distribution files, etc.
337 if "${GLOBAL}"
338 then
339 DISTURL=${GTZURL}/${FETCHVER}/tzdata${FETCHVER}.tar.gz
340 unset SIGURL
341 else
342 DISTURL="ftp://${DIST_HOST}/${DIST_PATH}/${DIST_FILES}"
343 DISTURL="${DISTURL}/tzdata${NEWVER}.tar.gz"
344 SIGURL="${DISTURL}.asc"
345 fi
346 NEWSURL="https://github.com/eggert/tz/raw/${GITHUBTAG}/NEWS"
347
348 # Directories
349 REPODIR="src/external/public-domain/tz/dist"
350 # relative to the NetBSD CVS repo
351 TZDISTDIR="$(pwd)/dist" # should be .../external/public-domain/tz/dist
352 WORKDIR="${WORK_PFX}/${NEWVER}"
353 EXTRACTDIR="${WORKDIR}/extract"
354
355 # Files in the work directory
356 DISTFILE="${WORKDIR}/${DISTURL##*/}"
357 SIGFILE="${DISTFILE}.asc"
358 PGPVERIFYLOG="${WORKDIR}/pgpverify.log"
359 NEWSFILE="${WORKDIR}/NEWS"
360 NEWSTRIMFILE="${WORKDIR}/NEWS.trimmed"
361 IMPORTMSGFILE="${WORKDIR}/import.msg"
362 IMPORTDONEFILE="${WORKDIR}/import.done"
363 MERGSMSGFILE="${WORKDIR}/merge.msg"
364 MERGEDONEFILE="${WORKDIR}/merge.done"
365 FILECONTENTCHECKDONE="${WORKDIR}/filecheck.done"
366 COMMITMERGEDONEFILE="${WORKDIR}/commitmerge.done"
367
368 printf '%s\n' "${CVSOLDTAG}" > "${WORK_PFX}/updating_from"
369 }
370
371 DOIT()
372 {
373 local really_do_it=false
374 local reply
375
376 printf 'In directory %s\n' "$(pwd)"
377 printf 'ABOUT TO DO: %s\n' "$(shell_quote "$@")"
378 read -p "Really do it? [yes/no/quit] " reply
379 case "${reply}" in
380 ([yY]*) really_do_it=true ;;
381 ([nN]*) really_do_it=false ;;
382 ([qQ]*)
383 printf 'Aborting\n'
384 return 1
385 ;;
386 (*) printf 'Huh?\n'
387 return 1
388 ;;
389 esac
390 if "$really_do_it"; then
391 printf 'REALLY DOING IT NOW...\n'
392 "$@"
393 else
394 printf 'NOT DOING THE ABOVE COMMAND\n'
395 fi
396 }
397
398 # Quote args to make them safe in the shell.
399 # Usage: quotedlist="$(shell_quote args...)"
400 #
401 # After building up a quoted list, use it by evaling it inside
402 # double quotes, like this:
403 # eval "set -- $quotedlist"
404 # or like this:
405 # eval "\$command $quotedlist \$filename"
406 #
407 shell_quote()
408 (
409 local result=''
410 local arg qarg
411 LC_COLLATE=C ; export LC_COLLATE # so [a-zA-Z0-9] works in ASCII
412 for arg in "$@" ; do
413 case "${arg}" in
414 ('')
415 qarg="''"
416 ;;
417 (*[!-./a-zA-Z0-9]*)
418 # Convert each embedded ' to '\'',
419 # then insert ' at the beginning of the first line,
420 # and append ' at the end of the last line.
421 # Finally, elide unnecessary '' pairs at the
422 # beginning and end of the result and as part of
423 # '\'''\'' sequences that result from multiple
424 # adjacent quotes in the input.
425 qarg="$(printf '%s\n' "$arg" | \
426 ${SED:-sed} -e "s/'/'\\\\''/g" \
427 -e "1s/^/'/" -e "\$s/\$/'/" \
428 -e "1s/^''//" -e "\$s/''\$//" \
429 -e "s/'''/'/g"
430 )"
431 ;;
432 (*)
433 # Arg is not the empty string, and does not contain
434 # any unsafe characters. Leave it unchanged for
435 # readability.
436 qarg="${arg}"
437 ;;
438 esac
439 result="${result}${result:+ }${qarg}"
440 done
441 printf '%s\n' "$result"
442 )
443
444 validate_pwd()
445 {
446 local P="$(pwd)" || return 1
447
448 test -d "${P}" &&
449 test -d "${P}/dist" &&
450 test -f "${P}/dist/zone.tab" &&
451 test -f "${P}/tzdata2netbsd" || {
452 printf >&2 '%s\n' 'Please change to the correct directory' \
453 'It is the one (in src) containing the tzdata2netbsd script, and dist subdir'
454 return 1
455 }
456 }
457
458 check_branch()
459 {
460 local P="$(pwd)" || return 1
461
462 if ${Hg:-false}
463 then
464 if [ "$(hg branch)" = trunk ]
465 then
466 return 0
467 fi
468 printf >&2 '%s\n' \
469 "This script should be run in a checkout of trunk only"
470 return 1
471
472 fi
473 test -f "${P}/CVS/Tag" && {
474
475 # Here (for local use only) if needed for private branch work
476 # insert tests for the value of $(cat "${P}/CVS/Tag") and
477 # allow your private branch tag to pass. Eg:
478
479 # case "$(cat "${P}/CVS/Tag")" in
480 # (my-branch-name) return 0;;
481 # esac
482
483 # Do not commit a version of this script modified that way,
484 # (not even on the private branch) - keep it as a local
485 # modified file. (This script will not commit it.)
486
487 printf >&2 '%s\n' \
488 "This script should be run in a checkout of HEAD only"
489 return 1
490 }
491
492 return 0
493 }
494
495 findcvsroot()
496 {
497 Hg=false
498 if HGREPO=$(hg paths default 2>/dev/null)
499 then
500 test -n "${HGREPO}" && Hg=true && return 0
501 fi
502 [ -n "${CVSROOT}" ] && return 0
503 CVSROOT="$( cat ./CVS/Root 2>/dev/null )" || {
504 printf 'No CVS/Root or Hg repository in %s\n' "$(pwd)"
505 return 1
506 }
507 [ -n "${CVSROOT}" ] && return 0
508 printf >&2 'Failed to set CVSROOT value\n'
509 return 1
510 }
511
512 hginit()
513 {
514 local P=
515
516 if ! "${Hg:-false}"
517 then
518 return 0
519 fi
520
521 P=$(cd -P "${NETBSDSRCDIR}/.." && pwd) ||
522 fail 'Unable to name parent of NETBSDSRCDIR'
523
524 TZDATASRC=${P}/tzdatasrc
525
526 if ! [ -d "${TZDATASRC}" ]
527 then
528 printf 2>&1 '%s\n' \
529 'Make the tzdatasrc clone of src first.' \
530 'It should be a sibling of src in the filesys:' \
531 " ${TZDATASRC}" \
532 'It should contain just the TZDATA branch.'
533
534 exit 3
535 fi
536
537 if [ "$( ls "${TZDATASRC}" )" != external ] ||
538 [ "$( ls "${TZDATASRC}/external" )" != public-domain ] ||
539 [ "$( ls "${TZDATASRC}/external/public-domain" )" != tz ] ||
540 [ "$( ls "${TZDATASRC}/external/public-domain/tz" )" != dist ] ||
541 ! [ -d "${TZDATASRC}/external/public-domain/tz/dist" ]
542 then
543 printf 2>&1 '%s\n' \
544 "TZDATASRC (${TZDATASRC}) set up improperly" \
545 'Correct it and restart.' \
546 'It should contain only the TZDATA branch'
547 exit 4
548 fi
549
550 WORK_PFX=${P}/tzdata-update-work
551 UPDATE_FROM=${WORK_PFX}/updating.from.version
552 }
553
554 mkworkpfx()
555 {
556 mkdir -p "${WORK_PFX}" || fail "Unable to make missing ${WORK_PFX}"
557 }
558 mkworkdir()
559 {
560 mkdir -p "${WORKDIR}" || fail "Unable to make missing ${WORKDIR}"
561 }
562
563 cvsupdate()
564 (
565 # Make sure our working directory is up to date (and HEAD)
566
567 if "${Hg:-false}"
568 then
569 if [ -n "$(hg status | sed 1q)" ]
570 then
571 printf 'There are modified files in the tree:\n'
572 hg status
573 printf 'Commit, revert, or shelve any modified files\n'
574 return 1
575 fi
576
577 if [ hg outgoing >/dev/null 2>&1 ]
578 then
579 printf 'There are unpushed changesets in the tree:\n'
580 hg outgoing | sed -e 1,2d
581 printf \
582 'These changes will be pushed as part of the update\n'
583 read -r -p 'Is that OK? [Y/n] ' reply
584 case ${reply} in
585 [Yy]*) ;;
586 *) printf 'Aborting. Nothing has changed\n'
587 exit 1
588 ;;
589 esac
590 fi
591 hg pull -u -b trunk "${HGREPO}"
592 return 0
593 fi
594
595 (
596 cd -P "${TZBASE}/dist" || exit 1
597 cvs -d "${CVSROOT}" -q update -AdP || exit 2
598 ) || exit $?
599 )
600
601 fetch()
602 {
603 [ -f "${DISTFILE}" ] || ftp -o "${DISTFILE}" "${DISTURL}" ||
604 fail "fetch of ${DISTFILE} failed"
605
606 if [ -n "${SIGURL}" ]
607 then
608 [ -f "${SIGFILE}" ] || ftp -o "${SIGFILE}" "${SIGURL}" ||
609 fail "fetch of ${SIGFILE} failed"
610 fi
611
612 [ -f "${NEWSFILE}" ] || ftp -o "${NEWSFILE}" "${NEWSURL}" ||
613 fail "fetch of ${NEWSFILE} failed"
614 }
615
616 checksig()
617 {
618 {
619 gpg --verify "${SIGFILE}" "${DISTFILE}"
620 printf 'gpg exit status %s\n' "$?"
621 } 2>&1 |
622 tee "${PGPVERIFYLOG}"
623
624 # The output should contain lines that match all the following regexps
625 #
626 while read line
627 do
628 if ! grep -E -q -e "^${line}\$" "${PGPVERIFYLOG}"
629 then
630 printf >&2 'Failed to verify signature: %s\n' "${line}"
631 return 1
632 fi
633 done <<'EOF'
634 gpg: Signature made .* using RSA key ID (62AA7E34|44AD418C)
635 gpg: Good signature from "Paul Eggert <eggert (a] cs.ucla.edu>"
636 gpg exit status 0
637 EOF
638 }
639
640 extract()
641 {
642 [ -f "${EXTRACTDIR}/zone.tab" ] && return
643 mkdir -p "${EXTRACTDIR}"
644 tar -z -xf "${DISTFILE}" -C "${EXTRACTDIR}"
645 }
646
647 rflist()
648 (
649 test "${1}" && cd -P "${1}" && find * -print | sort
650 )
651
652 zonelists()
653 {
654 [ -f "${WORKDIR}"/addedzones ] && return
655
656 rm -fr "${WORK_PFX}"/oldzones "${WORK_PFX}"/newzones
657
658 (
659 cd -P "${TZBASE}/share/zoneinfo" || exit 1
660
661 make TOOL_ZIC=/usr/sbin/zic \
662 DESTDIR= \
663 TZBUILDDIR="${WORK_PFX}"/oldzones \
664 TZDIR="${WORK_PFX}"/oldzones \
665 TZDISTDIR="${TZBASE}"/dist \
666 posix_only >/dev/null 2>&1
667
668 ) || fail 'Unable to compile old zone data files'
669
670 (
671 cd -P "${TZBASE}/share/zoneinfo" || exit 1
672
673 make TOOL_ZIC=/usr/sbin/zic \
674 DESTDIR= \
675 TZBUILDDIR="${WORK_PFX}"/newzones \
676 TZDIR="${WORK_PFX}"/newzones \
677 TZDISTDIR="${EXTRACTDIR}" \
678 posix_only >/dev/null 2>&1
679
680 ) || fail 'Unable to compile new zone data files'
681
682 rflist "${WORK_PFX}"/oldzones > "${WORKDIR}"/oldzones
683 rflist "${WORK_PFX}"/newzones > "${WORKDIR}"/newzones
684
685 if cmp -s "${WORKDIR}"/oldzones "${WORKDIR}"/newzones >/dev/null
686 then
687 printf 'No zones added or deleted by this update\n'
688 > "${WORKDIR}"/removedzones
689 > "${WORKDIR}"/addedzones
690 return 0
691 fi
692
693 comm -23 "${WORKDIR}"/oldzones "${WORKDIR}"/newzones \
694 > "${WORKDIR}"/removedzones
695
696 test "${REMOVEOK:-no}" != yes && test -s "${WORKDIR}"/removedzones && {
697 printf '%s\n' 'This update wants to remove these zone files:' ''
698 sed 's/^/ /' < "${WORKDIR}"/removedzones
699 printf '%s\n' '' 'It probably should not' ''
700
701 printf 'If this is OK, rerun this script with REMOVEOK=yes\n'
702 printf 'Otherwise, fix the problem, and then rerun the script\n'
703 exit 1
704 }
705
706 comm -13 "${WORKDIR}"/oldzones "${WORKDIR}"/newzones \
707 > "${WORKDIR}"/addedzones
708
709 test -s "${WORKDIR}"/addedzones && {
710 printf '%s\n' '' '********************************* NOTE:' \
711 '********************************* New Zones Created' \
712 ''
713 sed 's/^/ /' < "${WORKDIR}"/addedzones
714 printf '%s\n' '' '*********************************' ''
715 }
716
717 return 0
718 }
719
720 updatedzones()
721 {
722 [ -f "${WORKDIR}"/.zonesOK ] && return
723
724 rm -fr "${WORK_PFX}"/updzones
725
726 (
727 cd -P "${TZBASE}/share/zoneinfo" || exit 1
728
729 make TOOL_ZIC=/usr/sbin/zic \
730 DESTDIR= \
731 TZBUILDDIR="${WORK_PFX}"/updzones \
732 TZDIR="${WORK_PFX}"/updzones \
733 TZDISTDIR="${TZBASE}"/dist \
734 posix_only >/dev/null 2>&1
735
736 ) || fail 'Unable to compile updated zone data. HELP'
737
738 rflist "${WORK_PFX}"/updzones > "${WORKDIR}"/updzones
739
740 cmp -s "${WORKDIR}"/newzones "${WORKDIR}"/updzones || {
741
742 printf '%s\n' '' '*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*' \
743 'After cvs work, zones created are not as intended' \
744 '-------------------------------------------------' \
745 'Zones not created but should have been:'
746 comm -23 "${WORKDIR}"/newzones "${WORKDIR}"/updzones |
747 sed 's/^/ /'
748 printf '%s\n' \
749 '-------------------------------------------------' \
750 'Zones created that should not have been:'
751 comm -13 "${WORKDIR}"/newzones "${WORKDIR}"/updzones |
752 sed 's/^/ /'
753 printf '%s\n' \
754 '-------------------------------------------------'
755
756 fail 'cvs import/merge/update/commit botch'
757 }
758
759 > "${WORKDIR}"/.zonesOK
760 }
761
762 addnews()
763 {
764 [ -f "${EXTRACTDIR}/NEWS" ] && return
765 cp -p "${NEWSFILE}" "${EXTRACTDIR}"/NEWS
766 }
767
768 # Find the relevant part of the NEWS file for all releases between
769 # OLDVER and NEWVER, and save them to NEWSTRIMFILE.
770 #
771 trimnews()
772 {
773 [ -s "${NEWSTRIMFILE}" ] && return
774 awk -v oldver="${OLDVER}" -v newver="${NEWVER}" \
775 '
776 BEGIN {inrange = 0}
777 /^Release [0-9]+[a-z]+ - .*/ {
778 # "Release <version> - <date>"
779 # Note: must handle transition from 2018z to 2018aa
780 # Assumptions: OLDVER and NEWVER have been sanitized,
781 # and format of NEWS file does not alter (and
782 # contains valid data)
783 inrange = ((length($2) > length(oldver) || \
784 $2 > oldver) && \
785 (length($2) < newver || $2 <= newver))
786 }
787 // { if (inrange) print; }
788 ' \
789 <"${NEWSFILE}" >"${NEWSTRIMFILE}"
790
791 if "${GLOBAL}"
792 then
793 printf '%s\n' "tzdata-${NEWVER}gtz"
794 else
795 printf '%s\n' "tzdata-${NEWVER}"
796 fi > "${TZDISTDIR}/TZDATA_VERSION"
797 }
798
799 # Create IMPORTMSGFILE from NEWSTRIMFILE, by ignoring some sections,
800 # keeping only the first sentence from paragraphs in other sections,
801 # and changing the format.
802 #
803 # The result should be edited by hand before performing a cvs commit.
804 # A message to that effect is inserted at the beginning of the file.
805 #
806 mkimportmsg()
807 {
808 [ -s "${IMPORTMSGFILE}" ] && return
809 { cat <<EOF
810 EDIT ME: Edit this file and then delete the lines marked "EDIT ME".
811 EDIT ME: This file will be used as a log message for the "cvs commit" that
812 EDIT ME: imports tzdata${NEWVER}. The initial contents of this file were
813 EDIT ME: generated from ${NEWSFILE}.
814 EDIT ME:
815 EOF
816 awk -v oldver="${OLDVER}" -v newver="${NEWVER}" \
817 -v disturl="${DISTURL}" -v newsurl="${NEWSURL}" \
818 '
819 BEGIN {
820 bullet = " * ";
821 indent = " ";
822 blankline = 0;
823 goodsection = 0;
824 havesentence = 0;
825 print "Import tzdata"newver" from "disturl;
826 #print "and NEWS file from "newsurl;
827 }
828 /^Release/ {
829 # "Release <version> - <date>"
830 ver = $2;
831 date = gensub(".* - ", "", 1, $0);
832 print "";
833 print "Summary of changes in tzdata"ver \
834 " ("date"):";
835 }
836 /^$/ { blankline = 1; havesentence = 0; }
837 /^ Changes / { goodsection = 0; }
838 /^ Changes to future timestamps/ { goodsection = 1; }
839 /^ Changes to past timestamps/ { goodsection = 1; }
840 /^ Changes to documentation/ || \
841 /^ Changes to commentary/ {
842 t = gensub("^ *", "", 1, $0);
843 t = gensub("\\.*$", ".", 1, t);
844 print bullet t;
845 goodsection = 0;
846 }
847 /^ .*/ && goodsection {
848 # In a paragraph in a "good" section.
849 # Ignore leading spaces, and ignore anything
850 # after the first sentence.
851 # First line of paragraph gets a bullet.
852 t = gensub("^ *", "", 1, $0);
853 t = gensub("\\. .*", ".", 1, t);
854 if (blankline) print bullet t;
855 else if (! havesentence) print indent t;
856 havesentence = (havesentence || (t ~ "\\.$"));
857 }
858 /./ { blankline = 0; }
859 ' \
860 <"${NEWSTRIMFILE}"
861 } >"${IMPORTMSGFILE}"
862
863 if [ -s "${WORKDIR}"/addedzones ]
864 then
865 printf '%s\n' '' 'Zones added by this update:'
866 sed 's/^/ /' < "${WORKDIR}"/addedzones
867 fi >> "${IMPORTMSGFILE}"
868
869 if [ -s "${WORKDIR}"/removedzones ]
870 then
871 printf '%s\n' '' 'Zones removed by this update:'
872 sed 's/^/ /' < "${WORKDIR}"/removedzones
873 fi >> "${IMPORTMSGFILE}"
874
875 }
876
877 editimportmsg()
878 {
879 if [ -s "${IMPORTMSGFILE}" ] && ! grep -q '^EDIT' "${IMPORTMSGFILE}"
880 then
881 return 0 # file has already been edited
882 fi
883 # Pass both IMPORTMSGFILE and NEWSFILE to the editor, so that the
884 # user can easily consult NEWSFILE while editing IMPORTMSGFILE.
885 ${EDITOR} "${IMPORTMSGFILE}" "${NEWSFILE}"
886 }
887
888 cvsimport()
889 {
890 if [ -e "${IMPORTDONEFILE}" ]; then
891 cat >&2 <<EOF
892 The CVS import has already been performed.
893 EOF
894 return 0
895 fi
896 if ! [ -s "${IMPORTMSGFILE}" ] || grep -q '^EDIT' "${IMPORTMSGFILE}"
897 then
898 cat >&2 <<EOF
899 The message file ${IMPORTMSGFILE}
900 has not been properly edited.
901 Not performing cvs import.
902 EOF
903 return 1
904 fi
905 ( cd -P "${EXTRACTDIR}" &&
906 DOIT cvs -d "${CVSROOT}" import -I ! -m "$(cat "${IMPORTMSGFILE}")" \
907 "${REPODIR}" "${CVSBRANCHTAG}" "${CVSNEWTAG}"
908 ) && touch "${IMPORTDONEFILE}"
909 }
910
911 hgimport()
912 (
913 set -e # Just to make sure
914
915 if [ -e "${IMPORTDONEFILE}" ]; then
916 cat >&2 <<EOF
917 The hg TZDATA branch update has already been performed.
918 EOF
919 return 0
920 fi
921 if ! [ -s "${IMPORTMSGFILE}" ] || grep -q '^EDIT' "${IMPORTMSGFILE}"
922 then
923 cat >&2 <<EOF
924 The message file ${IMPORTMSGFILE}
925 has not been properly edited.
926 Not performing hg import.
927 EOF
928 return 1
929 fi
930
931 RELPATH=${TZBASE#${NETBSDSRCDIR}/}
932
933 cd -P "${TZDATASRC}/${RELPATH}/dist"
934
935 ls -1 > "${WORKDIR}"/old-dist-files
936 ls -1 "${EXTRACTDIR}" >"${WORKDIR}"/new-dist-files
937
938 rm -f *
939 cp -f ${EXTRACTDIR}/* .
940
941 if cmp "${WORKDIR}"/old-dist-files "${WORKDIR}"/new-dist-files
942 then
943 DOIT hg commit -l "${IMPORTMSGFILE}" &&
944 touch "${IMPORTDONEFILE}"
945 return
946 fi
947
948 NEW=$(comm -13 "${WORKDIR}"/old-dist-files "${WORKDIR}"/new-dist-files)
949 OLD=$(comm -23 "${WORKDIR}"/old-dist-files "${WORKDIR}"/new-dist-files)
950
951 if [ -n "${NEW}" ]
952 then
953 printf '\nThe following files have been added:\n%s\n' "${NEW}"\
954 >>"${IMPORTMSGFILE}"
955 fi
956 if [ -n "${OLD}" ]
957 then
958 printf '\nThe following files have been removed:\n%s\n' \
959 "${OLD}" >>"${IMPORTMSGFILE}"
960
961 test -n "${NEW}" &&
962 printf '\nThe following files have been added:\n%s\n' "${NEW}"
963 printf '\nThe following files have been removed:\n%s\n' \
964 "${OLD}"
965
966 read -r -p 'Do you want to do this ? ' reply
967 case $reply in
968 [Yy]*) ;;
969 *) return 1;;
970 esac
971 fi
972
973 DOIT hg addremove -s 90 &&
974 DOIT hg commit -l "${IMPORTMSGFILE}" &&
975 touch "${IMPORTDONEFILE}"
976 )
977
978 cvsmerge()
979 {
980
981 cd -P "${TZDISTDIR}" || exit 1
982 if [ -e "${MERGEDONEFILE}" ]
983 then
984 cat >&2 <<EOF
985 The CVS merge has already been performed.
986 EOF
987 return 0
988 fi
989 DOIT cvs -d "${CVSROOT}" update -j"${CVSOLDTAG}" -j"${CVSNEWTAG}" &&
990 touch "${MERGEDONEFILE}"
991 printf '%s\n' ================================== \
992 'The following differences exist between the merge results' \
993 'and the imported files:' '================================='
994 diff -ur "${EXTRACTDIR}" . || :
995 printf '%s\n' ==================================
996 }
997
998 hgmerge()
999 {
1000 cd -P "${TZDISTDIR}" || exit 1
1001 if [ -e "${MERGEDONEFILE}" ]
1002 then
1003 cat >&2 <<EOF
1004 The hg merge has already been performed.
1005 EOF
1006 return 0
1007 fi
1008 DOIT hg merge TZDATA &&
1009 touch "${MERGEDONEFILE}" &&
1010 return 0
1011
1012 if [ -z "$( ht resolve -l | grep -v '^R' >/dev/null 2>&1 )" ]
1013 then
1014 # All conflicts already resolved, just note that
1015 printf 'Auto-resolving merge "conflicts"\n.'
1016 hg resolve -m &&
1017 touch "${MERGEDONEFILE}"
1018 return 0
1019 fi
1020
1021 printf '\n*********************************** CONFLICTS\n'
1022 printf 'The following files have conflicts:\n'
1023
1024 hg resolve -l
1025
1026 printf '%s\n' \
1027 'Resolve these issues, and run\n\thg resolve -m file...' \
1028 'as each file listed above is corrected.' '' \
1029 'Then re-run this script.'
1030
1031 touch "${MERGEDONEFILE}"
1032 exit 1
1033 }
1034
1035 resolveconflicts()
1036 {
1037 cd -P "${TZDISTDIR}" || exit 1
1038 if grep -l '^[<=>][<=>][<=>]' *
1039 then
1040 cat <<EOF
1041 There appear to be conflicts in the files listed above.
1042 Resolve conflicts, then re-run this script.
1043 EOF
1044 return 1
1045 fi
1046 }
1047
1048 checkfilecontents()
1049 (
1050 if [ -e "${FILECONTENTCHECKDONE}" ]
1051 then
1052 printf 'Repository file contents checked already\n'
1053 exit 0
1054 fi
1055
1056 set +e +f
1057
1058 auto=false
1059
1060 cd -P "${EXTRACTDIR}" || exit 1
1061 set -- *
1062
1063 if test "$1" = '*'
1064 then
1065 if [ "$#" -eq 1 ] && ! [ -e "$1" ]
1066 then
1067 printf 'No files in "%s" !!\nAborting.\n' \
1068 "${EXTRACTDIR}"
1069 exit 1
1070 fi
1071 printf \
1072 'A file named "*" exists in "%s" !!\nDanger!!\nAborting.\n'\
1073 "${EXTRACTDIR}"
1074 exit 1
1075 fi
1076
1077 unset -v LESS MORE
1078
1079 exit=0
1080 cd -P "${TZDISTDIR}" || exit 1
1081
1082 for file
1083 do
1084 if ! test -e "${file}"
1085 then
1086 printf 'In distribution but not in new tree: %s\n' \
1087 "${file}"
1088 cp "${EXTRACTDIR}${file}" .
1089 if "${Hg:-false}"
1090 then
1091 DOIT hg add "${file}"
1092 else
1093 DOIT cvs -d "${CVSROOT}" add \
1094 -m "Added by ${NEWVER}" "${file}"
1095 fi
1096 continue
1097 fi
1098
1099 cmp -s "${EXTRACTDIR}/${file}" "${file}" && continue
1100
1101 if "${auto}"
1102 then
1103 cp -p "${EXTRACTDIR}/${file}" "${file}"
1104 continue
1105 fi
1106
1107 printf 'Differences in "%s" (- existing + updated)\n\n' \
1108 "${file}"
1109 diff -u "${file}" "${EXTRACTDIR}/${file}" | more
1110 read -rp "Update ${file} to new version? (y/n/all)" reply
1111 case "${reply}" in
1112 ([Nn]*) continue;;
1113 ([Yy]*|[Aa]|[Aa]ll) ;;
1114 ([Qq]*) exit 1;;
1115 (*) printf 'Unexpected reply, abort.\n'
1116 exit 1;;
1117 esac
1118
1119 cp -p "${EXTRACTDIR}/${file}" "${file}"
1120
1121 case "${reply}" in
1122 ([Aa]*) auto=true;;
1123 esac
1124 done
1125
1126 set -- *
1127 LIST=
1128 for file # nb: continue if there are no files, $1='*'
1129 do
1130 if test "${file}" = TZDATA_VERSION ||
1131 test "${file}" = CVS ||
1132 test -e "${EXTRACTDIR}/${file}"
1133 then
1134 continue
1135 fi
1136 printf 'File "%s" no longer exists in %s\n' \
1137 "${file}" "${NEWVER}"
1138 LIST="${LIST} '${file}'"
1139 done
1140
1141 eval set -- ${LIST}
1142 while :
1143 do
1144 case $# in
1145 (0) break;;
1146 (1) M='this file';;
1147 (*) M='these files';;
1148 esac
1149
1150 read -rp "OK to remove $M from the repository? " reply
1151 case "${reply}" in
1152 ([Yy]*) ;;
1153 ([Nn]*) break;;
1154 (*) exit 1;;
1155 esac
1156
1157 if "${Hg:-false}"
1158 then
1159 DOIT hg remove "$@" || continue
1160 else
1161 rm -f "$@"
1162 DOIT cvs -d "${CVSROOT}" remove "${@}" || continue
1163 fi
1164 break
1165 done
1166
1167 touch "${FILECONTENTCHECKDONE}" || exit 1
1168
1169 exit "${exit}"
1170 )
1171
1172 cvscommitmerge()
1173 {
1174 cd -P "${TZDISTDIR}" || exit 1
1175 if grep -l '^[<=>][<=>][<=>]' *
1176 then
1177 cat >&2 <<EOF
1178 There still appear to be conflicts in the files listed above.
1179 Not performing cvs commit.
1180 EOF
1181 return 1
1182 fi
1183 if [ -e "${COMMITMERGEDONEFILE}" ]; then
1184 cat >&2 <<EOF
1185 The CVS commit (of the merge result) has already been performed.
1186 EOF
1187 return 0
1188 fi
1189 DOIT cvs -d "${CVSROOT}" commit -m "Merge tzdata${NEWVER}" &&
1190 touch "${COMMITMERGEDONEFILE}"
1191 }
1192
1193 hgcommitmerge()
1194 {
1195 cd -P "${TZDISTDIR}" || exit 1
1196
1197 if ! hg resolve -l
1198 then
1199 cat >&2 <<EOF
1200 There still appear to be conflicts in the files listed above.
1201 Not performing hg commit. Resolve conflicts first.
1202 EOF
1203 return 1
1204 fi
1205 if [ -e "${COMMITMERGEDONEFILE}" ]; then
1206 cat >&2 <<EOF
1207 The hg commit (of the merge result) has already been performed.
1208 EOF
1209 return 0
1210 fi
1211 DOIT hg commit -m "Merge tzdata${NEWVER}" &&
1212 touch "${COMMITMERGEDONEFILE}"
1213 }
1214
1215 setlistupdate()
1216 {
1217 if [ -s "${WORKDIR}"/addedzones ] ||
1218 [ -s "${WORKDIR}"/removedzones ]
1219 then (
1220 # Do all the preparatory work first, so
1221 # when we get to manipulating the sets list file
1222 # it all happens quickly...
1223
1224 while read file
1225 do
1226 printf '\\!zoneinfo/%s!{ %s ; %s ; }\n' \
1227 "${file}" \
1228 's/sys-share /obsolete /' \
1229 's/ share$/ obsolete/'
1230 done < "${WORKDIR}"/removedzones > "${WORKDIR}/sedcmds"
1231
1232 while read file
1233 do
1234 P=./usr/share/zoneinfo/"${file}"
1235 T2=' '
1236 case "$(( 48 - ${#P} ))" in
1237 (-*|0) T2=' ' T=' ' ;;
1238 ([12345678]) T=' ' ;;
1239 (9|1[0123456]) T=' ';;
1240 (1[789]|2[01234]) T=' ';;
1241 (2[5-9]|3[012])
1242 T=' ';;
1243 # the following cases can't happen,
1244 # but for completeness...
1245 (3[3-9])
1246 T=' ';;
1247 (*) T=' '
1248 T="${T} " ;;
1249 esac
1250
1251 if [ -d "${WORKDIR}/newzones/${file}" ]
1252 then
1253 printf '%s%sbase-sys-share\n' \
1254 "${P}" "${T}"
1255 continue
1256 fi
1257
1258 printf '%s%sbase-sys-share%sshare\n' \
1259 "${P}" "${T}" "${T2}"
1260
1261 # Deal with possibility that a new file
1262 # might have previously existed, and then
1263 # been deleted - marked obsolete
1264 printf '\\!^%s .*obsolete!d\n' "${P}" \
1265 >> "${WORKDIR}/sedcmds"
1266
1267 done < "${WORKDIR}"/addedzones > "${WORKDIR}/setadded"
1268
1269 printf '$r %s\n' "${WORKDIR}/setadded" \
1270 >> "${WORKDIR}/sedcmds"
1271
1272 if ! [ -s "${WORKDIR}/sedcmds" ] # impossible?
1273 then
1274 exit 0
1275 fi
1276
1277 MSG=$(
1278 printf 'tzdata update to %s\n' "$NEWVER"
1279 if [ -s "${WORKDIR}"/addedzones ]
1280 then
1281 printf 'Added zoneinfo files:\n'
1282 sed 's/^/ /' \
1283 < "${WORKDIR}"/addedzones
1284 fi
1285 if [ -s "${WORKDIR}"/removedzones ]
1286 then
1287 printf 'Removed zoneinfo files:\n'
1288 sed 's/^/ /' \
1289 < "${WORKDIR}"/removedzones
1290 fi
1291 printf '\nX'
1292 )
1293 MSG=${MSG%X}
1294
1295 # Now is where the changes start happening...
1296
1297 cd -P "${NETBSDSRCDIR}/distrib/sets" || exit 1
1298 cd -P lists/base || exit 2
1299 "${Hg:-false}" ||
1300 cvs -d "${CVSROOT}" -q update -A mi || exit 3
1301 cp -p mi mi.unsorted || exit 4
1302 sh ../../sort-list mi || exit 5
1303 cmp -s mi mi.unsorted || {
1304 if "${Hg:-false}"
1305 then
1306 DOIT hg commit -m 'Sort (NFCI)' mi ||
1307 exit 6
1308 else
1309 DOIT cvs -d "${CVSROOT}" -q commit \
1310 -m 'Sort (NFCI)' mi || exit 6
1311 fi
1312 }
1313 rm -f mi.unsorted
1314 sed -f "${WORKDIR}/sedcmds" < mi > mi.new || exit 7
1315 ! test -s mi.new || cmp -s mi mi.new && {
1316 printf 'Failed to make changes to set lists'
1317 exit 8
1318 }
1319 mv mi.new mi || exit 9
1320 sh ../../sort-list mi || exit 10
1321 if "${Hg:-false}"
1322 then
1323 DOIT hg commit -m "${MSG}" mi || exit 11
1324 else
1325 DOIT cvs -d "${CVSROOT}" commit -m "${MSG}" mi||
1326 exit 11
1327 fi
1328 printf 'Sets list successfully updated'
1329 exit 0
1330 ) || {
1331 printf '%s: %d\n%s %s\n' 'Sets list update failed' "$?"\
1332 'Update the sets list' \
1333 '(src/distrib/sets/lists/base/mi) manually'
1334 if [ -s "${WORKDIR}"/removedzones ]
1335 then
1336 printf 'Removed Zones:'
1337 sed 's/^/ /' < "${WORKDIR}"/removedzones
1338 fi
1339 if [ -s "${WORKDIR}"/addedzones ]
1340 then
1341 printf 'Added Zones:'
1342 sed 's/^/ /' < "${WORKDIR}"/addedzones
1343 fi
1344 }
1345 fi
1346 }
1347
1348 docupdate()
1349 {
1350 cd -P "${TZBASE}"
1351
1352 MSG='CHANGES and 3RDPARTY must be updated manually'
1353
1354 cd -P "${NETBSDSRCDIR:-/nowhere/at/all}" 2>/dev/null || {
1355 printf >&2 '%s\n' "${MSG}"
1356 return 1
1357 }
1358
1359 if ! [ -d doc ]
1360 then
1361 printf '%s\n' "No doc directory in ${PWD}" "${MSG}"
1362 return 1
1363 fi
1364 cd -P doc
1365 if ! "${Hg:-false}" && ! [ -d CVS ]
1366 then
1367 printf '%s\n' "No CVS directory in ${PWD}" "${MSG}"
1368 return 1
1369 fi
1370
1371 if ! "${Hg:-false}"
1372 then
1373 printf 'Making sure doc/CHANGES and doc/3RDPARTY are up to date\n'
1374 cvs -d "${CVSROOT}" -q update -A CHANGES 3RDPARTY
1375 fi
1376
1377 local commit=false
1378
1379 if grep "tzdata: Updated to ${NEWVER}" CHANGES
1380 then
1381 printf 'doc/CHANGES has already been updated\n'
1382 else
1383 {
1384 printf '\ttzdata: Updated to %s' "${NEWVER}"
1385 "${GLOBAL}" && printf ' (using %sgtz)' "${NEWVER}"
1386 date -u +" [${LOGNAME} %Y%m%d]"
1387 commit=true
1388 } >> CHANGES
1389 fi
1390
1391 if grep "^Version: tzcode[^ ]* / tzdata${NEWVER}" 3RDPARTY
1392 then
1393 printf 'doc/3RDPARTY has already been updated\n'
1394 else
1395 # These just make the sed script below manageable.
1396 C=tzcode D=tzdata V=${NEWVER} T=${CVSNEWTAG}
1397
1398 G=$V
1399 "${GLOBAL}" && G=${G}gtz
1400
1401 sed < 3RDPARTY > 3RDPARTY.new \
1402 -e '1,/^Package: tz$/{p;d;}' \
1403 -e '/^Notes:/,${p;d;}' \
1404 -e "/^Version: /s, / ${D}.*, / ${D}${G}," \
1405 -e "/^Current Vers:/s,tz.*$,${C}${V} / ${D}${V}," && {
1406
1407 mv 3RDPARTY.new 3RDPARTY
1408 commit=true
1409 }
1410 fi
1411
1412 if "${commit}"
1413 then
1414 printf 'These are the changes that will be made:\n\n'
1415
1416 if "${Hg:-false}"
1417 then
1418 hg diff CHANGES 3RDPARTY || : # Ugh -e!
1419 else
1420 cvs -d "${CVSROOT}" diff -u CHANGES 3RDPARTY || :
1421 fi
1422
1423 read -p $'\nAre those OK? [y/n] ' reply
1424
1425
1426 if "${GLOBAL}"
1427 then
1428 MSG="${MSG} (via ${NEWVER}gtz)"
1429 fi
1430 case "${reply}" in
1431 ([Yy]*)
1432 if "${Hg:-false}"
1433 then
1434 DOIT hg commit -m "${MSG}" CHANGES 3RDPARTY
1435 else
1436 DOIT cvs -d "${CVSROOT}" commit -m "${MSG}" \
1437 CHANGES 3RDPARTY
1438 fi
1439 ;;
1440 (*) printf '%s\n' \
1441 'OK, correct and commit those files manually' \
1442 'The changes shown above have been made to the files'
1443 ;;
1444 esac
1445 fi
1446 return 0
1447 }
1448
1449 extra()
1450 {
1451 cat <<EOF
1452 Also do the following:
1453 * Submit pullup requests for all active release branches.
1454 * rm -rf ${WORK_PFX} (optional)
1455 * Verify that
1456 ${UPDATE_FROM}
1457 * no longer exists.
1458
1459 And if necessary (if not already done by the script):
1460 * Edit and commit src/distrib/sets/lists/base/mi
1461 * Edit and commit src/doc/3RDPARTY
1462 * Edit and commit src/doc/CHANGES
1463 EOF
1464
1465 rm -f "${UPDATE_FROM}" # just to try to make sure, as we're done!
1466 }
1467
1468 main()
1469 {
1470 set -e
1471 validate_pwd
1472
1473 find_netbsdsrc
1474 findcvsroot
1475 hginit
1476
1477 if ! [ -f "${UPDATE_FROM}" ]
1478 then
1479 cvsupdate || fail 'working directory (dist) update failed:'" $?"
1480 fi
1481
1482 mkworkpfx
1483
1484 argparse "$@"
1485
1486 setup_versions
1487 mkworkdir
1488 fetch
1489 "${GLOBAL}" || checksig
1490 extract
1491
1492 zonelists
1493
1494 addnews
1495 trimnews
1496 mkimportmsg
1497 editimportmsg
1498
1499 if "${Hg:-false}"
1500 then
1501 hgimport
1502 hgmerge
1503 else
1504 cvsimport
1505 cvsmerge
1506 resolveconflicts
1507 fi
1508 checkfilecontents
1509 if "${Hg:-false}"
1510 then
1511 hgcommitmerge
1512 else
1513 cvscommitmerge
1514 fi
1515 updatedzones
1516
1517 setlistupdate
1518
1519 rm -f "${UPDATE_FROM}"
1520 rm -fr "${WORK_PFX}"/oldzones \
1521 "${WORK_PFX}"/newzones \
1522 "${WORK_PFX}"/updzones
1523
1524 docupdate
1525
1526 if "${hg:-false}"
1527 then
1528 DOIT hg push # Publish it all!
1529 fi
1530
1531 extra
1532 }
1533
1534 main "$@"
1535