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