1 # $NetBSD: tzdata2netbsd,v 1.21 2026/07/18 09:46:28 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 "$( hg 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 # Don't repeat the above if there are unresolved conflicts, 1032 # Rather hgcommitmerge() will refuse to proceed until they 1033 # are fixed. 1034 touch "${MERGEDONEFILE}" 1035 exit 1 1036 } 1037 1038 resolveconflicts() 1039 { 1040 cd -P "${TZDISTDIR}" || exit 1 1041 if grep -l '^[<=>][<=>][<=>]' * 1042 then 1043 cat <<EOF 1044 There appear to be conflicts in the files listed above. 1045 Resolve conflicts, then re-run this script. 1046 EOF 1047 return 1 1048 fi 1049 } 1050 1051 checkfilecontents() 1052 ( 1053 if [ -e "${FILECONTENTCHECKDONE}" ] 1054 then 1055 printf 'Repository file contents checked already\n' 1056 exit 0 1057 fi 1058 1059 set +e +f 1060 1061 auto=false 1062 1063 cd -P "${EXTRACTDIR}" || exit 1 1064 set -- * 1065 1066 if test "$1" = '*' 1067 then 1068 if [ "$#" -eq 1 ] && ! [ -e "$1" ] 1069 then 1070 printf 'No files in "%s" !!\nAborting.\n' \ 1071 "${EXTRACTDIR}" 1072 exit 1 1073 fi 1074 printf \ 1075 'A file named "*" exists in "%s" !!\nDanger!!\nAborting.\n'\ 1076 "${EXTRACTDIR}" 1077 exit 1 1078 fi 1079 1080 unset -v LESS MORE 1081 1082 exit=0 1083 cd -P "${TZDISTDIR}" || exit 1 1084 1085 for file 1086 do 1087 case "${file}" in 1088 *.orig | *.rej) continue;; # Patch noise 1089 esac 1090 if ! test -e "${file}" 1091 then 1092 printf 'In distribution but not in new tree: %s\n' \ 1093 "${file}" 1094 cp "${EXTRACTDIR}${file}" . 1095 if "${Hg:-false}" 1096 then 1097 DOIT hg add "${file}" 1098 else 1099 DOIT cvs -d "${CVSROOT}" add \ 1100 -m "Added by ${NEWVER}" "${file}" 1101 fi 1102 continue 1103 fi 1104 1105 printf 'Checking for differences in %s\n' "${file}" 1106 cmp -s "${EXTRACTDIR}/${file}" "${file}" && continue 1107 1108 if "${auto}" 1109 then 1110 cp -p "${EXTRACTDIR}/${file}" "${file}" 1111 continue 1112 fi 1113 1114 printf 'Differences in "%s" (- existing + updated)\n\n' \ 1115 "${file}" 1116 diff -u "${file}" "${EXTRACTDIR}/${file}" | more 1117 read -rp "Update ${file} to new version? (y/n/all)" reply 1118 case "${reply}" in 1119 ([Nn]*) continue;; 1120 ([Yy]*|[Aa]|[Aa]ll) ;; 1121 ([Qq]*) exit 1;; 1122 (*) printf 'Unexpected reply, abort.\n' 1123 exit 1;; 1124 esac 1125 1126 cp -p "${EXTRACTDIR}/${file}" "${file}" 1127 1128 case "${reply}" in 1129 ([Aa]*) auto=true;; 1130 esac 1131 done 1132 1133 set -- * 1134 LIST= 1135 for file # nb: continue if there are no files, $1='*' 1136 do 1137 if test "${file}" = TZDATA_VERSION || 1138 test "${file}" = CVS || 1139 test -e "${EXTRACTDIR}/${file}" 1140 then 1141 continue 1142 fi 1143 printf 'File "%s" no longer exists in %s\n' \ 1144 "${file}" "${NEWVER}" 1145 LIST="${LIST} '${file}'" 1146 done 1147 1148 eval set -- ${LIST} 1149 while : 1150 do 1151 case $# in 1152 (0) break;; 1153 (1) M='this file';; 1154 (*) M='these files';; 1155 esac 1156 1157 read -rp "OK to remove $M from the repository? " reply 1158 case "${reply}" in 1159 ([Yy]*) ;; 1160 ([Nn]*) break;; 1161 (*) exit 1;; 1162 esac 1163 1164 if "${Hg:-false}" 1165 then 1166 DOIT hg remove "$@" || continue 1167 else 1168 rm -f "$@" 1169 DOIT cvs -d "${CVSROOT}" remove "${@}" || continue 1170 fi 1171 break 1172 done 1173 1174 touch "${FILECONTENTCHECKDONE}" || exit 1 1175 1176 exit "${exit}" 1177 ) 1178 1179 cvscommitmerge() 1180 { 1181 cd -P "${TZDISTDIR}" || exit 1 1182 if grep -l '^[<=>][<=>][<=>]' * 1183 then 1184 cat >&2 <<EOF 1185 There still appear to be conflicts in the files listed above. 1186 Not performing cvs commit. 1187 EOF 1188 return 1 1189 fi 1190 if [ -e "${COMMITMERGEDONEFILE}" ]; then 1191 cat >&2 <<EOF 1192 The CVS commit (of the merge result) has already been performed. 1193 EOF 1194 return 0 1195 fi 1196 DOIT cvs -d "${CVSROOT}" commit -m "Merge tzdata${NEWVER}" && 1197 touch "${COMMITMERGEDONEFILE}" 1198 } 1199 1200 hgcommitmerge() 1201 { 1202 cd -P "${TZDISTDIR}" || exit 1 1203 1204 if ! hg resolve -l 1205 then 1206 cat >&2 <<EOF 1207 1208 There still appear to be conflicts in the files listed above. 1209 1210 Not performing hg commit. 1211 1212 Resolve conflicts first. Use: 1213 hg resolve -l 1214 to discover what remains to be done (marked 'U') and then: 1215 hg resolve -m file... 1216 as each conflict has been fixed, until no unresolved conflicts remain. 1217 EOF 1218 exit 1 1219 fi 1220 if [ -e "${COMMITMERGEDONEFILE}" ]; then 1221 cat >&2 <<EOF 1222 The hg commit (of the merge result) has already been performed. 1223 EOF 1224 return 0 1225 fi 1226 DOIT hg commit -m "Merge tzdata${NEWVER}" && 1227 touch "${COMMITMERGEDONEFILE}" 1228 } 1229 1230 setlistupdate() 1231 { 1232 if [ -s "${WORKDIR}"/addedzones ] || 1233 [ -s "${WORKDIR}"/removedzones ] 1234 then ( 1235 # Do all the preparatory work first, so 1236 # when we get to manipulating the sets list file 1237 # it all happens quickly... 1238 1239 while read file 1240 do 1241 printf '\\!zoneinfo/%s!{ %s ; %s ; }\n' \ 1242 "${file}" \ 1243 's/sys-share /obsolete /' \ 1244 's/ share$/ obsolete/' 1245 done < "${WORKDIR}"/removedzones > "${WORKDIR}/sedcmds" 1246 1247 while read file 1248 do 1249 P=./usr/share/zoneinfo/"${file}" 1250 T2=' ' 1251 case "$(( 48 - ${#P} ))" in 1252 (-*|0) T2=' ' T=' ' ;; 1253 ([12345678]) T=' ' ;; 1254 (9|1[0123456]) T=' ';; 1255 (1[789]|2[01234]) T=' ';; 1256 (2[5-9]|3[012]) 1257 T=' ';; 1258 # the following cases can't happen, 1259 # but for completeness... 1260 (3[3-9]) 1261 T=' ';; 1262 (*) T=' ' 1263 T="${T} " ;; 1264 esac 1265 1266 if [ -d "${WORKDIR}/newzones/${file}" ] 1267 then 1268 printf '%s%sbase-sys-share\n' \ 1269 "${P}" "${T}" 1270 continue 1271 fi 1272 1273 printf '%s%sbase-sys-share%sshare\n' \ 1274 "${P}" "${T}" "${T2}" 1275 1276 # Deal with possibility that a new file 1277 # might have previously existed, and then 1278 # been deleted - marked obsolete 1279 printf '\\!^%s .*obsolete!d\n' "${P}" \ 1280 >> "${WORKDIR}/sedcmds" 1281 1282 done < "${WORKDIR}"/addedzones > "${WORKDIR}/setadded" 1283 1284 printf '$r %s\n' "${WORKDIR}/setadded" \ 1285 >> "${WORKDIR}/sedcmds" 1286 1287 if ! [ -s "${WORKDIR}/sedcmds" ] # impossible? 1288 then 1289 exit 0 1290 fi 1291 1292 MSG=$( 1293 printf 'tzdata update to %s\n' "$NEWVER" 1294 if [ -s "${WORKDIR}"/addedzones ] 1295 then 1296 printf '\nAdded zoneinfo files:\n' 1297 sed 's/^/ /' \ 1298 < "${WORKDIR}"/addedzones 1299 fi 1300 if [ -s "${WORKDIR}"/removedzones ] 1301 then 1302 printf '\nRemoved zoneinfo files:\n' 1303 sed 's/^/ /' \ 1304 < "${WORKDIR}"/removedzones 1305 fi 1306 printf '\nX' 1307 ) 1308 MSG=${MSG%X} 1309 1310 # Now is where the changes start happening... 1311 1312 cd -P "${NETBSDSRCDIR}/distrib/sets" || exit 1 1313 cd -P lists/base || exit 2 1314 "${Hg:-false}" || 1315 cvs -d "${CVSROOT}" -q update -A mi || exit 3 1316 cp -p mi mi.unsorted || exit 4 1317 sh ../../sort-list mi || exit 5 1318 cmp -s mi mi.unsorted || { 1319 if "${Hg:-false}" 1320 then 1321 DOIT hg commit -m 'Sort (NFCI)' mi || 1322 exit 6 1323 else 1324 DOIT cvs -d "${CVSROOT}" -q commit \ 1325 -m 'Sort (NFCI)' mi || exit 6 1326 fi 1327 } 1328 rm -f mi.unsorted 1329 sed -f "${WORKDIR}/sedcmds" < mi > mi.new || exit 7 1330 ! test -s mi.new || cmp -s mi mi.new && { 1331 printf 'Failed to make changes to set lists\n' 1332 exit 8 1333 } 1334 mv mi.new mi || exit 9 1335 sh ../../sort-list mi || exit 10 1336 if "${Hg:-false}" 1337 then 1338 DOIT hg commit -m "${MSG}" mi || exit 11 1339 else 1340 DOIT cvs -d "${CVSROOT}" commit -m "${MSG}" mi|| 1341 exit 11 1342 fi 1343 printf 'Sets list successfully updated\n' 1344 exit 0 1345 ) || { 1346 printf '%s: %d\n%s %s\n' 'Sets list update failed' "$?"\ 1347 'Update the sets list' \ 1348 '(src/distrib/sets/lists/base/mi) manually' 1349 if [ -s "${WORKDIR}"/removedzones ] 1350 then 1351 printf 'Removed Zones:\n' 1352 sed 's/^/ /' < "${WORKDIR}"/removedzones 1353 fi 1354 if [ -s "${WORKDIR}"/addedzones ] 1355 then 1356 printf 'Added Zones:\n' 1357 sed 's/^/ /' < "${WORKDIR}"/addedzones 1358 fi 1359 } 1360 fi 1361 } 1362 1363 docupdate() 1364 { 1365 cd -P "${TZBASE}" 1366 1367 MSG='CHANGES and 3RDPARTY must be updated manually' 1368 1369 cd -P "${NETBSDSRCDIR:-/nowhere/at/all}" 2>/dev/null || { 1370 printf >&2 '%s\n' "${MSG}" 1371 return 1 1372 } 1373 1374 if ! [ -d doc ] 1375 then 1376 printf '%s\n' "No doc directory in ${PWD}" "${MSG}" 1377 return 1 1378 fi 1379 cd -P doc 1380 if ! "${Hg:-false}" && ! [ -d CVS ] 1381 then 1382 printf '%s\n' "No CVS directory in ${PWD}" "${MSG}" 1383 return 1 1384 fi 1385 1386 if ! "${Hg:-false}" 1387 then 1388 printf 'Making sure doc/CHANGES and doc/3RDPARTY are up to date\n' 1389 cvs -d "${CVSROOT}" -q update -A CHANGES 3RDPARTY 1390 fi 1391 1392 local commit=false 1393 1394 if grep "tzdata: Updated to ${NEWVER}" CHANGES 1395 then 1396 printf 'doc/CHANGES has already been updated\n' 1397 else 1398 { 1399 printf '\ttzdata: Updated to %s' "${NEWVER}" 1400 "${GLOBAL}" && printf ' (using %sgtz)' "${NEWVER}" 1401 date -u +" [${LOGNAME} %Y%m%d]" 1402 commit=true 1403 } >> CHANGES 1404 fi 1405 1406 if grep "^Version: tzcode[^ ]* / tzdata${NEWVER}" 3RDPARTY 1407 then 1408 printf 'doc/3RDPARTY has already been updated\n' 1409 else 1410 # These just make the sed script below manageable. 1411 C=tzcode D=tzdata V=${NEWVER} T=${CVSNEWTAG} 1412 1413 G=$V 1414 "${GLOBAL}" && G=${G}gtz 1415 1416 sed < 3RDPARTY > 3RDPARTY.new \ 1417 -e '1,/^Package: tz$/{p;d;}' \ 1418 -e '/^Notes:/,${p;d;}' \ 1419 -e "/^Version: /s, / ${D}.*, / ${D}${G}," \ 1420 -e "/^Current Vers:/s,tz.*$,${C}${V} / ${D}${V}," && { 1421 1422 mv 3RDPARTY.new 3RDPARTY 1423 commit=true 1424 } 1425 fi 1426 1427 if "${commit}" 1428 then 1429 printf 'These are the changes that will be made:\n\n' 1430 1431 if "${Hg:-false}" 1432 then 1433 hg diff CHANGES 3RDPARTY || : # Ugh -e! 1434 else 1435 cvs -d "${CVSROOT}" diff -u CHANGES 3RDPARTY || : 1436 fi 1437 1438 read -p $'\nAre those OK? [y/n] ' reply 1439 1440 MSG="Note tzdata${NEWVER} update" 1441 if "${GLOBAL}" 1442 then 1443 MSG="${MSG} (via ${NEWVER}gtz)" 1444 fi 1445 case "${reply}" in 1446 ([Yy]*) 1447 if "${Hg:-false}" 1448 then 1449 DOIT hg commit -m "${MSG}" CHANGES 3RDPARTY 1450 else 1451 DOIT cvs -d "${CVSROOT}" commit -m "${MSG}" \ 1452 CHANGES 3RDPARTY 1453 fi 1454 ;; 1455 (*) printf '%s\n' \ 1456 'OK, correct and commit those files manually' \ 1457 'The changes shown above have been made to the files' 1458 ;; 1459 esac 1460 fi 1461 return 0 1462 } 1463 1464 extra() 1465 { 1466 cat <<EOF 1467 Also do the following: 1468 * Submit pullup requests for all active release branches. 1469 * rm -rf ${WORK_PFX} (optional) 1470 * Verify that 1471 ${UPDATE_FROM} 1472 * no longer exists. 1473 1474 And if necessary (if not already done by the script): 1475 * Edit and commit src/distrib/sets/lists/base/mi 1476 * Edit and commit src/doc/3RDPARTY 1477 * Edit and commit src/doc/CHANGES 1478 EOF 1479 1480 rm -f "${UPDATE_FROM}" # just to try to make sure, as we're done! 1481 } 1482 1483 main() 1484 { 1485 set -e 1486 validate_pwd 1487 1488 find_netbsdsrc 1489 findcvsroot 1490 hginit 1491 1492 if ! [ -f "${UPDATE_FROM}" ] 1493 then 1494 cvsupdate || fail 'working directory (dist) update failed:'" $?" 1495 fi 1496 1497 mkworkpfx 1498 1499 argparse "$@" 1500 1501 setup_versions 1502 mkworkdir 1503 fetch 1504 "${GLOBAL}" || checksig 1505 extract 1506 1507 zonelists 1508 1509 addnews 1510 trimnews 1511 mkimportmsg 1512 editimportmsg 1513 1514 if "${Hg:-false}" 1515 then 1516 hgimport 1517 hgmerge 1518 else 1519 cvsimport 1520 cvsmerge 1521 resolveconflicts 1522 fi 1523 checkfilecontents 1524 if "${Hg:-false}" 1525 then 1526 hgcommitmerge 1527 else 1528 cvscommitmerge 1529 fi 1530 updatedzones 1531 1532 setlistupdate 1533 1534 rm -f "${UPDATE_FROM}" 1535 rm -fr "${WORK_PFX}"/oldzones \ 1536 "${WORK_PFX}"/newzones \ 1537 "${WORK_PFX}"/updzones 1538 1539 docupdate 1540 1541 if "${hg:-false}" 1542 then 1543 DOIT hg push # Publish it all! 1544 fi 1545 1546 extra 1547 } 1548 1549 main "$@" 1550