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