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