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