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