blob: f06dac341dc4f4e4649151057adab63eebb9aaa7 [file] [log] [blame]
Elliott Hughes5d967e42012-07-20 16:52:39 -07001#!/usr/bin/python
Elliott Hughes5b1497a2012-10-19 14:47:37 -07002
3"""Updates the tzdata file."""
Elliott Hughesd40e63e2011-02-17 16:20:07 -08004
Elliott Hughes5d967e42012-07-20 16:52:39 -07005import ftplib
Elliott Hughesf8dff7d2013-04-22 11:11:43 -07006import httplib
Elliott Hughes5d967e42012-07-20 16:52:39 -07007import os
8import re
Elliott Hughes21da42e2013-04-22 13:44:50 -07009import socket
Elliott Hughes5d967e42012-07-20 16:52:39 -070010import subprocess
11import sys
12import tarfile
13import tempfile
Elliott Hughesd40e63e2011-02-17 16:20:07 -080014
Elliott Hughes5d967e42012-07-20 16:52:39 -070015# Find the bionic directory, searching upward from this script.
16bionic_libc_tools_zoneinfo_dir = os.path.realpath(os.path.dirname(sys.argv[0]))
17bionic_libc_tools_dir = os.path.dirname(bionic_libc_tools_zoneinfo_dir)
18bionic_libc_dir = os.path.dirname(bionic_libc_tools_dir)
19bionic_dir = os.path.dirname(bionic_libc_dir)
20bionic_libc_zoneinfo_dir = '%s/libc/zoneinfo' % bionic_dir
Elliott Hughes5b1497a2012-10-19 14:47:37 -070021
22if not os.path.isdir(bionic_libc_tools_zoneinfo_dir):
Elliott Hughes5d967e42012-07-20 16:52:39 -070023 print "Couldn't find bionic/libc/tools/zoneinfo!"
24 sys.exit(1)
Elliott Hughes5b1497a2012-10-19 14:47:37 -070025if not os.path.isdir(bionic_libc_zoneinfo_dir):
26 print "Couldn't find bionic/libc/zoneinfo!"
27 sys.exit(1)
28
Elliott Hughes5d967e42012-07-20 16:52:39 -070029print 'Found bionic in %s...' % bionic_dir
Elliott Hughesd40e63e2011-02-17 16:20:07 -080030
Elliott Hughes5d967e42012-07-20 16:52:39 -070031
Elliott Hughes5b1497a2012-10-19 14:47:37 -070032regions = ['africa', 'antarctica', 'asia', 'australasia', 'backward',
33 'etcetera', 'europe', 'northamerica', 'southamerica']
Elliott Hughes5d967e42012-07-20 16:52:39 -070034
35
Elliott Hughes21da42e2013-04-22 13:44:50 -070036def DisableIpv6():
37 """Replaces socket.getaddrinfo with a version that only requests IPv4 addresses."""
38 __real_getaddrinfo = socket.getaddrinfo
39 def __ipv4_getaddrinfo(host, port, family=0, socktype=0, proto=0, flags=0):
40 return __real_getaddrinfo(host, port, socket.AF_INET, socktype, proto, flags)
41 socket.getaddrinfo = __ipv4_getaddrinfo
42
43
Elliott Hughes5b1497a2012-10-19 14:47:37 -070044def GetCurrentTzDataVersion():
Elliott Hughese3063f42012-11-05 08:53:28 -080045 return open('%s/tzdata' % bionic_libc_zoneinfo_dir).read().split('\x00', 1)[0]
Elliott Hughes5d967e42012-07-20 16:52:39 -070046
47
Elliott Hughes5b1497a2012-10-19 14:47:37 -070048def WriteSetupFile():
Elliott Hughese3063f42012-11-05 08:53:28 -080049 """Writes the list of zones that ZoneCompactor should process."""
Elliott Hughes5b1497a2012-10-19 14:47:37 -070050 links = []
51 zones = []
52 for region in regions:
53 for line in open('extracted/%s' % region):
54 fields = line.split()
Elliott Hughese3063f42012-11-05 08:53:28 -080055 if fields:
56 if fields[0] == 'Link':
57 links.append('%s %s %s\n' % (fields[0], fields[1], fields[2]))
58 zones.append(fields[2])
59 elif fields[0] == 'Zone':
60 zones.append(fields[1])
Elliott Hughes5b1497a2012-10-19 14:47:37 -070061 zones.sort()
62
63 setup = open('setup', 'w')
64 for link in links:
65 setup.write(link)
66 for zone in zones:
67 setup.write('%s\n' % zone)
68 setup.close()
Elliott Hughes5d967e42012-07-20 16:52:39 -070069
70
Elliott Hughesf8dff7d2013-04-22 11:11:43 -070071def SwitchToNewTemporaryDirectory():
Elliott Hughes5d967e42012-07-20 16:52:39 -070072 tmp_dir = tempfile.mkdtemp('-tzdata')
73 os.chdir(tmp_dir)
74 print 'Created temporary directory "%s"...' % tmp_dir
75
Elliott Hughesf8dff7d2013-04-22 11:11:43 -070076
77def FtpRetrieve(ftp, filename):
78 ftp.retrbinary('RETR %s' % filename, open(filename, 'wb').write)
79
80
81def FtpUpgrade(ftp, data_filename):
82 """Downloads and repackages the given data from the given FTP server."""
83 SwitchToNewTemporaryDirectory()
84
Elliott Hughes5d2ef872012-11-26 13:44:49 -080085 print 'Downloading data...'
Elliott Hughesf8dff7d2013-04-22 11:11:43 -070086 FtpRetrieve(ftp, data_filename)
Elliott Hughes5d2ef872012-11-26 13:44:49 -080087
88 print 'Downloading signature...'
89 signature_filename = '%s.asc' % data_filename
Elliott Hughesf8dff7d2013-04-22 11:11:43 -070090 FtpRetrieve(ftp, signature_filename)
Elliott Hughese3063f42012-11-05 08:53:28 -080091
Elliott Hughesf8dff7d2013-04-22 11:11:43 -070092 ExtractAndCompile(data_filename)
93
94
Elliott Hughes676e66d2013-04-22 11:41:57 -070095def HttpRetrieve(http, path, output_filename):
96 http.request("GET", path)
97 f = open(output_filename, 'wb')
98 f.write(http.getresponse().read())
99 f.close()
100
101
Elliott Hughesf8dff7d2013-04-22 11:11:43 -0700102def HttpUpgrade(http, data_filename):
103 """Downloads and repackages the given data from the given HTTP server."""
104 SwitchToNewTemporaryDirectory()
105
Elliott Hughes676e66d2013-04-22 11:41:57 -0700106 path = "/time-zones/repository/releases/%s" % data_filename
107
Elliott Hughesf8dff7d2013-04-22 11:11:43 -0700108 print 'Downloading data...'
Elliott Hughes676e66d2013-04-22 11:41:57 -0700109 HttpRetrieve(http, path, data_filename)
110
111 print 'Downloading signature...'
112 signature_filename = '%s.asc' % data_filename
113 HttpRetrieve(http, "%s.asc" % path, signature_filename)
Elliott Hughesf8dff7d2013-04-22 11:11:43 -0700114
115 ExtractAndCompile(data_filename)
116
117
118def ExtractAndCompile(data_filename):
119 new_version = re.search('(tzdata.+)\\.tar\\.gz', data_filename).group(1)
120
Elliott Hughes676e66d2013-04-22 11:41:57 -0700121 signature_filename = '%s.asc' % data_filename
122 print 'Verifying signature...'
123 # If this fails for you, you probably need to import Paul Eggert's public key:
124 # gpg --recv-keys ED97E90E62AA7E34
125 subprocess.check_call(['gpg', '--trusted-key=ED97E90E62AA7E34', '--verify',
126 signature_filename, data_filename])
127
Elliott Hughes5d967e42012-07-20 16:52:39 -0700128 print 'Extracting...'
129 os.mkdir('extracted')
Elliott Hughese3063f42012-11-05 08:53:28 -0800130 tar = tarfile.open(data_filename, 'r')
Elliott Hughes5d967e42012-07-20 16:52:39 -0700131 tar.extractall('extracted')
132
133 print 'Calling zic(1)...'
134 os.mkdir('data')
135 for region in regions:
136 if region != 'backward':
137 subprocess.check_call(['zic', '-d', 'data', 'extracted/%s' % region])
138
Elliott Hughes5b1497a2012-10-19 14:47:37 -0700139 WriteSetupFile()
Elliott Hughes5d967e42012-07-20 16:52:39 -0700140
Elliott Hughes5b1497a2012-10-19 14:47:37 -0700141 print 'Calling ZoneCompactor to update bionic to %s...' % new_version
Elliott Hugheseb061292012-10-19 12:05:24 -0700142 libcore_src_dir = '%s/../libcore/luni/src/main/java/' % bionic_dir
Elliott Hughes5d967e42012-07-20 16:52:39 -0700143 subprocess.check_call(['javac', '-d', '.',
144 '%s/ZoneCompactor.java' % bionic_libc_tools_zoneinfo_dir,
Elliott Hugheseb061292012-10-19 12:05:24 -0700145 '%s/libcore/util/ZoneInfo.java' % libcore_src_dir,
146 '%s/libcore/io/BufferIterator.java' % libcore_src_dir])
Elliott Hughes5b1497a2012-10-19 14:47:37 -0700147 subprocess.check_call(['java', 'ZoneCompactor',
Elliott Hughes23935352012-10-22 14:47:58 -0700148 'setup', 'data', 'extracted/zone.tab',
149 bionic_libc_zoneinfo_dir, new_version])
Elliott Hughes5d967e42012-07-20 16:52:39 -0700150
Elliott Hughesd40e63e2011-02-17 16:20:07 -0800151
Elliott Hughes5b1497a2012-10-19 14:47:37 -0700152# Run with no arguments from any directory, with no special setup required.
Elliott Hughese3063f42012-11-05 08:53:28 -0800153# See http://www.iana.org/time-zones/ for more about the source of this data.
Elliott Hughes5b1497a2012-10-19 14:47:37 -0700154def main():
Elliott Hughes5b1497a2012-10-19 14:47:37 -0700155 print 'Looking for new tzdata...'
Elliott Hughesf8dff7d2013-04-22 11:11:43 -0700156
Elliott Hughes5b1497a2012-10-19 14:47:37 -0700157 tzdata_filenames = []
Elliott Hughesf8dff7d2013-04-22 11:11:43 -0700158
159 # The FTP server lets you download intermediate releases, and also lets you
Elliott Hughes21da42e2013-04-22 13:44:50 -0700160 # download the signatures for verification, so it's your best choice.
Elliott Hughesf8dff7d2013-04-22 11:11:43 -0700161 use_ftp = True
Elliott Hughes21da42e2013-04-22 13:44:50 -0700162 DisableIpv6() # I've been unable to talk to the FTP server over IPv6 (2013-04).
Elliott Hughesf8dff7d2013-04-22 11:11:43 -0700163
164 if use_ftp:
165 ftp = ftplib.FTP('ftp.iana.org')
166 ftp.login()
167 ftp.cwd('tz/releases')
168 for filename in ftp.nlst():
169 if filename.startswith('tzdata20') and filename.endswith('.tar.gz'):
170 tzdata_filenames.append(filename)
171 tzdata_filenames.sort()
172 else:
173 http = httplib.HTTPConnection('www.iana.org')
174 http.request("GET", "/time-zones")
175 index_lines = http.getresponse().read().split('\n')
176 for line in index_lines:
177 m = re.compile('.*href="/time-zones/repository/releases/(tzdata20\d\d\c\.tar\.gz)".*').match(line)
178 if m:
179 tzdata_filenames.append(m.group(1))
Elliott Hughesbcb2eda2011-10-24 10:47:25 -0700180
Elliott Hughes5b1497a2012-10-19 14:47:37 -0700181 # If you're several releases behind, we'll walk you through the upgrades
182 # one by one.
183 current_version = GetCurrentTzDataVersion()
184 current_filename = '%s.tar.gz' % current_version
185 for filename in tzdata_filenames:
186 if filename > current_filename:
187 print 'Found new tzdata: %s' % filename
Elliott Hughesf8dff7d2013-04-22 11:11:43 -0700188 if use_ftp:
189 FtpUpgrade(ftp, filename)
190 else:
191 HttpUpgrade(http, filename)
Elliott Hughes5b1497a2012-10-19 14:47:37 -0700192 sys.exit(0)
Elliott Hughesd40e63e2011-02-17 16:20:07 -0800193
Elliott Hughes5b1497a2012-10-19 14:47:37 -0700194 print 'You already have the latest tzdata (%s)!' % current_version
195 sys.exit(0)
196
197
198if __name__ == '__main__':
199 main()