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