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