[CalendarServer-changes] [13621] PyCalendar/trunk/src/zonal/tzconvert.py
source_changes at macosforge.org
source_changes at macosforge.org
Mon Jun 9 13:26:58 PDT 2014
Revision: 13621
http://trac.calendarserver.org//changeset/13621
Author: cdaboo at apple.com
Date: 2014-06-09 13:26:58 -0700 (Mon, 09 Jun 2014)
Log Message:
-----------
Support automatic download of the latest IANA tz db during conversion. Also, add in Unicode Windows' timezone aliases
into the set of links that IANA tz db has - that can be automatically downloaded too.
Modified Paths:
--------------
PyCalendar/trunk/src/zonal/tzconvert.py
Modified: PyCalendar/trunk/src/zonal/tzconvert.py
===================================================================
--- PyCalendar/trunk/src/zonal/tzconvert.py 2014-06-09 16:25:14 UTC (rev 13620)
+++ PyCalendar/trunk/src/zonal/tzconvert.py 2014-06-09 20:26:58 UTC (rev 13621)
@@ -16,14 +16,18 @@
##
from __future__ import with_statement
+from __future__ import print_function
-from difflib import unified_diff
from pycalendar.icalendar.calendar import Calendar
+from xml.etree.cElementTree import ParseError as XMLParseError
import cStringIO as StringIO
import getopt
import os
import rule
import sys
+import tarfile
+import urllib
+import xml.etree.cElementTree as XML
import zone
"""
@@ -72,7 +76,7 @@
else:
break
except:
- print "Failed to parse file %s" % (file,)
+ print("Failed to parse file %s" % (file,))
raise
@@ -112,6 +116,26 @@
self.links[linkTo] = linkFrom
+ def parseWindowsAliases(self, aliases):
+
+ try:
+ xmlfile = open(aliases)
+ xmlroot = XML.ElementTree(file=xmlfile).getroot()
+ except (IOError, XMLParseError):
+ raise ValueError("Unable to open or read windows alias file: {}".format(aliases))
+
+ # Extract the mappings
+ try:
+ for elem in xmlroot.findall("./windowsZones/mapTimezones/mapZone"):
+ if elem.get("territory", "") == "001":
+ if elem.get("other") not in self.links:
+ self.links[elem.get("other")] = elem.get("type")
+ else:
+ print("Ignoring duplicate Windows alias: {}".format(elem.get("other")))
+ except (ValueError, KeyError):
+ raise ValueError("Unable to parse windows alias file: {}".format(aliases))
+
+
def expandZone(self, zonename, minYear, maxYear=2018):
"""
Expand a zones transition dates up to the specified year.
@@ -136,7 +160,7 @@
return cal.getText()
- def generateZoneinfoFiles(self, outputdir, minYear, maxYear=2018, links=True, filterzones=None):
+ def generateZoneinfoFiles(self, outputdir, minYear, maxYear=2018, links=True, windowsAliases=None, filterzones=None):
# Empty current directory
try:
@@ -162,16 +186,19 @@
with open(fpath, "w") as f:
f.write(icsdata)
if self.verbose:
- print "Write path: %s" % (fpath,)
+ print("Write path: %s" % (fpath,))
if links:
+ if windowsAliases is not None:
+ self.parseWindowsAliases(windowsAliases)
+
link_list = []
- for linkTo, linkFrom in self.links.iteritems():
+ for linkTo, linkFrom in sorted(self.links.iteritems(), key=lambda x: x[0]):
# Check for existing output file
fromPath = os.path.join(outputdir, linkFrom + ".ics")
if not os.path.exists(fromPath):
- print "Missing link from: %s to %s" % (linkFrom, linkTo,)
+ print("Missing link from: %s to %s" % (linkFrom, linkTo,))
continue
with open(fromPath) as f:
@@ -184,7 +211,7 @@
with open(toPath, "w") as f:
f.write(icsdata)
if self.verbose:
- print "Write link: %s" % (linkTo,)
+ print("Write link: %s" % (linkTo,))
link_list.append("%s\t%s" % (linkTo, linkFrom,))
@@ -196,9 +223,9 @@
def usage(error_msg=None):
if error_msg:
- print error_msg
+ print(error_msg)
- print """Usage: tzconvert [options] [DIR]
+ print("""Usage: tzconvert [options] [DIR]
Options:
-h Print this help and exit
--prodid PROD-ID string to use
@@ -213,7 +240,7 @@
This utility convert Olson-style timezone data in iCalendar.
VTIMEZONE objects, one .ics file per-timezone.
-"""
+""")
if error_msg:
raise ValueError(error_msg)
@@ -225,11 +252,12 @@
# Set the PRODID value used in generated iCalendar data
prodid = "-//mulberrymail.com//Zonal//EN"
- rootdir = "../../stuff/temp"
+ rootdir = "../../temp"
startYear = 1800
endYear = 2018
+ windowsAliases = None
- options, args = getopt.getopt(sys.argv[1:], "h", ["prodid=", "root=", "start=", "end=", ])
+ options, args = getopt.getopt(sys.argv[1:], "h", ["prodid=", "root=", "start=", "end=", "windows="])
for option, value in options:
if option == "-h":
@@ -237,20 +265,35 @@
elif option == "--prodid":
prodid = value
elif option == "--root":
- rootdir = value
+ rootdir = os.path.expanduser(value)
elif option == "--start":
startYear = int(value)
elif option == "--end":
endYear = int(value)
+ elif option == "--windows":
+ windowsAliases = os.path.expanduser(value)
else:
usage("Unrecognized option: %s" % (option,))
- # Process arguments
- if len(args) > 1:
- usage("Must have only one argument")
- if len(args) == 1:
- rootdir = os.path.expanduser(args[0])
+ if not os.path.exists(rootdir):
+ os.makedirs(rootdir)
+ zonedir = os.path.join(rootdir, "tzdata")
+ if not os.path.exists(zonedir):
+ print("Downloading and extracting IANA timezone database")
+ os.mkdir(zonedir)
+ iana = "https://www.iana.org/time-zones/repository/tzdata-latest.tar.gz"
+ data = urllib.urlretrieve(iana)
+ print("Extract data at: %s" % (data[0]))
+ with tarfile.open(data[0], "r:gz") as t:
+ t.extractall(zonedir)
+ if windowsAliases is None:
+ windowsAliases = os.path.join(rootdir, "windowsZones.xml")
+ if not os.path.exists(windowsAliases):
+ print("Downloading Unicode database")
+ unicode = "http://unicode.org/repos/cldr/tags/latest/common/supplemental/windowsZones.xml"
+ data = urllib.urlretrieve(unicode, windowsAliases)
+
Calendar.sProdID = prodid
zonedir = os.path.join(rootdir, "tzdata")
@@ -270,41 +313,13 @@
for file in zonefiles:
parser.parse(os.path.join(zonedir, file))
- if 1:
- parser.generateZoneinfoFiles(os.path.join(rootdir, "zoneinfo"), startYear, endYear, filterzones=(
- #"America/Montevideo",
- #"Europe/Paris",
- #"Africa/Cairo",
- ))
-
- if 0:
- checkName = "EST"
- parsed = parser.vtimezones(1800, 2018, filterzones=(
- checkName,
- ))
-
- icsdir = "../2008i/zoneinfo"
- cal = Calendar()
- for file in (checkName,):
- fin = open(os.path.join(icsdir, file + ".ics"), "r")
- cal.parse(fin)
-
- for vtz in cal.getVTimezoneDB():
- #from pycalendar.vtimezoneelement import VTimezoneElement
- #vtz.mEmbedded.sort(VTimezoneElement.sort_dtstart)
- for embedded in vtz.mEmbedded:
- embedded.finalise()
- vtz.finalise()
-
- os = StringIO.StringIO()
- cal.generate(os, False)
- actual = os.getvalue()
-
- print "-- ACTUAL --"
- print actual
- print
- print "-- PARSED --"
- print parsed
- print
- print "-- DIFF --"
- print "\n".join([line for line in unified_diff(actual.split("\n"), parsed.split("\n"))])
+ parser.generateZoneinfoFiles(
+ os.path.join(rootdir, "zoneinfo"),
+ startYear,
+ endYear,
+ windowsAliases=windowsAliases,
+ filterzones=(
+ #"America/Montevideo",
+ #"Europe/Paris",
+ #"Africa/Cairo",
+ ))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140609/772f8654/attachment.html>
More information about the calendarserver-changes
mailing list