1# $NetBSD: tzdata2netbsd,v 1.7 2015/08/11 18:10:13 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/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 16OLDVER=2015e 17NEWVER=2015f 18 19# Uppercase variants of OLDVER and NEWVER 20OLDVER_UC="$( echo "${OLDVER}" | tr '[a-z]' '[A-Z]' )" 21NEWVER_UC="$( echo "${NEWVER}" | tr '[a-z]' '[A-Z]' )" 22 23# Tags for use with version control systems 24CVSOLDTAG="TZDATA${OLDVER_UC}" 25CVSNEWTAG="TZDATA${NEWVER_UC}" 26CVSBRANCHTAG="TZDATA" 27GITHUBTAG="${NEWVER}" 28 29# URLs for fetching distribution files, etc. 30DISTURL="ftp://ftp.iana.org/tz/releases/tzdata${NEWVER}.tar.gz" 31SIGURL="${DISTURL}.asc" 32NEWSURL="https://github.com/eggert/tz/raw/${GITHUBTAG}/NEWS" 33 34# Directories 35REPODIR="src/external/public-domain/tz/dist" # relative to the NetBSD CVS repo 36TZDISTDIR="$(pwd)/dist" # should be .../external/public-domain/tz/dist 37WORKDIR="$(pwd)/update-work/${NEWVER}" 38EXTRACTDIR="${WORKDIR}/extract" 39 40# Files in the work directory 41DISTFILE="${WORKDIR}/${DISTURL##*/}" 42SIGFILE="${DISTFILE}.sig" 43PGPVERIFYLOG="${WORKDIR}/pgpverify.log" 44NEWSFILE="${WORKDIR}/NEWS" 45NEWSTRIMFILE="${WORKDIR}/NEWS.trimmed" 46IMPORTMSGFILE="${WORKDIR}/import.msg" 47IMPORTDONEFILE="${WORKDIR}/import.done" 48MERGSMSGFILE="${WORKDIR}/merge.msg" 49MERGEDONEFILE="${WORKDIR}/merge.done" 50COMMITMERGEDONEFILE="${WORKDIR}/commitmerge.done" 51 52DOIT() 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# 85shell_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 122findcvsroot() 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 131mkworkdir() 132{ 133 mkdir -p "${WORKDIR}" 134} 135 136fetch() 137{ 138 [ -f "${DISTFILE}" ] || ftp -o "${DISTFILE}" "${DISTURL}" 139 [ -f "${SIGFILE}" ] || ftp -o "${SIGFILE}" "${SIGURL}" 140 [ -f "${NEWSFILE}" ] || ftp -o "${NEWSFILE}" "${NEWSURL}" 141} 142 143checksig() 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' 157gpg: Signature made .* using RSA key ID 62AA7E34 158gpg: Good signature from "Paul Eggert <eggert@cs.ucla.edu>" 159Primary key fingerprint: 7E37 92A9 D8AC F7D6 33BC 1588 ED97 E90E 62AA 7E34 160gpg exit status 0 161EOF 162} 163 164extract() 165{ 166 [ -f "${EXTRACTDIR}/zone.tab" ] && return 167 mkdir -p "${EXTRACTDIR}" 168 tar -z -xf "${DISTFILE}" -C "${EXTRACTDIR}" 169} 170 171addnews() 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# 180trimnews() 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# 202mkimportmsg() 203{ 204 [ -s "${IMPORTMSGFILE}" ] && return 205 { cat <<EOF 206EDIT ME: Edit this file and then delete the lines marked "EDIT ME". 207EDIT ME: This file will be used as a log message for the "cvs commit" that 208EDIT ME: imports tzdata${NEWVER}. The initial contents of this file were 209EDIT ME: generated from ${NEWSFILE}. 210EDIT ME: 211EOF 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 260editimportmsg() 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 272cvsimport() 273{ 274 if [ -e "${IMPORTDONEFILE}" ]; then 275 cat >&2 <<EOF 276The CVS import has already been performed. 277EOF 278 return 0 279 fi 280 if ! [ -s "${IMPORTMSGFILE}" ] \ 281 || grep -q '^EDIT' "${IMPORTMSGFILE}" 282 then 283 cat >&2 <<EOF 284The message file ${IMPORTMSGFILE} 285has not been properly edited. 286Not performing cvs import. 287EOF 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 296cvsmerge() 297{ 298 299 cd "${TZDISTDIR}" || exit 1 300 if [ -e "${MERGEDONEFILE}" ]; then 301 cat >&2 <<EOF 302The CVS merge has already been performed. 303EOF 304 return 0 305 fi 306 DOIT cvs -d "${CVSROOT}" update -j"${CVSOLDTAG}" -j"${CVSNEWTAG}" \ 307 && touch "${MERGEDONEFILE}" 308} 309 310resolveconflicts() 311{ 312 cd "${TZDISTDIR}" || exit 1 313 if grep -l '^[<=>][<=>][<=>]' * 314 then 315 cat <<EOF 316There appear to be conflicts in the files listed above. 317Resolve conflicts, then re-run this script. 318EOF 319 return 1 320 fi 321} 322 323cvscommitmerge() 324{ 325 cd "${TZDISTDIR}" || exit 1 326 if grep -l '^[<=>][<=>][<=>]' * 327 then 328 cat >&2 <<EOF 329There still appear to be conflicts in the files listed above. 330Not performing cvs commit. 331EOF 332 return 1 333 fi 334 if [ -e "${COMMITMERGEDONEFILE}" ]; then 335 cat >&2 <<EOF 336The CVS commmit (of the merge result) has already been performed. 337EOF 338 return 0 339 fi 340 DOIT cvs -d "${CVSROOT}" commit -m "Merge tzdata${NEWVER}" \ 341 && touch "${COMMITMERGEDONEFILE}" 342} 343 344extra() 345{ 346 cat <<EOF 347Also 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} 353EOF 354} 355 356main() 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 375main "$@" 376