[CalendarServer-changes] [9843] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon Sep 24 08:52:07 PDT 2012


Revision: 9843
          http://trac.calendarserver.org//changeset/9843
Author:   cdaboo at apple.com
Date:     2012-09-24 08:52:07 -0700 (Mon, 24 Sep 2012)
Log Message:
-----------
Add option to update timezone data direct from IANA with conversion of Olson data to iCalendar.

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/tools/managetimezones.py
    CalendarServer/trunk/support/build.sh

Modified: CalendarServer/trunk/calendarserver/tools/managetimezones.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/managetimezones.py	2012-09-23 03:36:01 UTC (rev 9842)
+++ CalendarServer/trunk/calendarserver/tools/managetimezones.py	2012-09-24 15:52:07 UTC (rev 9843)
@@ -15,7 +15,7 @@
 # limitations under the License.
 ##
 
-from twistedcaldav.timezonestdservice import PrimaryTimezoneDatabase,\
+from twistedcaldav.timezonestdservice import PrimaryTimezoneDatabase, \
     SecondaryTimezoneDatabase
 from sys import stdout, stderr
 import getopt
@@ -24,48 +24,147 @@
 from twisted.python.log import addObserver, removeObserver
 import sys
 import os
+import urllib
+import tarfile
+import tempfile
+from pycalendar.calendar import PyCalendar
+from zonal.tzconvert import tzconvert
+from twisted.python.filepath import FilePath
+from pycalendar.datetime import PyCalendarDateTime
 
-def _doPrimaryActions(action, tzpath, xmlfile, changed):
 
+def _doPrimaryActions(action, tzpath, xmlfile, changed, tzvers):
+
     tzdb = PrimaryTimezoneDatabase(tzpath, xmlfile)
-    if action == "create":
-        print "Creating new XML file at: %s" % (xmlfile, )
-        tzdb.createNewDatabase()
-        print "Current total: %d" % (len(tzdb.timezones), )
+    if action == "refresh":
+        _doRefresh(tzpath, xmlfile, tzdb, tzvers)
 
+    elif action == "create":
+        _doCreate(xmlfile, tzdb)
+
     elif action == "update":
-        print "Updating XML file at: %s" % (xmlfile, )
-        tzdb.readDatabase()
-        tzdb.updateDatabase()
-        print "Current total: %d" % (len(tzdb.timezones), )
-        print "Total Changed: %d" % (tzdb.changeCount, )
-        if tzdb.changeCount:
-            print "Changed:"
-            for k in sorted(tzdb.changed):
-                print "  %s" % (k, )
-    
+        _doUpdate(xmlfile, tzdb)
+
     elif action == "list":
-        print "Listing XML file at: %s" % (xmlfile, )
-        tzdb.readDatabase()
-        print "Current timestamp: %s" % (tzdb.dtstamp, )
-        print "Timezones:"
-        for k in sorted(tzdb.timezones.keys()):
-            print "  %s" % (k, )
-    
+        _doList(xmlfile, tzdb)
+
     elif action == "changed":
-        print "Changes from XML file at: %s" % (xmlfile, )
-        tzdb.readDatabase()
-        print "Check timestamp: %s" % (changed, )
-        print "Current timestamp: %s" % (tzdb.dtstamp, )
-        results = [k for k, v in tzdb.timezones.items() if v.dtstamp > changed]
-        print "Total Changed: %d" % (len(results), )
-        if results:
-            print "Changed:"
-            for k in sorted(results):
-                print "  %s" % (k, )
+        _doChanged(xmlfile, changed, tzdb)
+
     else:
-        usage("Invalid action: %s" % (action, ))
+        usage("Invalid action: %s" % (action,))
 
+
+
+def _doRefresh(tzpath, xmlfile, tzdb, tzvers):
+    """
+    Refresh data from IANA.
+    """
+
+    print "Downloading latest data from IANA"
+    if tzvers:
+        path = "http://www.iana.org/time-zones/repository/releases/tzdata%s.tar.gz" % (tzvers,)
+    else:
+        path = "http://www.iana.org/time-zones/repository/tzdata-latest.tar.gz"
+        tzvers = "Latest (%s)" % (PyCalendarDateTime.getToday().getText(),)
+    data = urllib.urlretrieve(path)
+    print "Extract data at: %s" % (data[0])
+    rootdir = tempfile.mkdtemp()
+    zonedir = os.path.join(rootdir, "tzdata")
+    os.mkdir(zonedir)
+    with tarfile.open(data[0], "r:gz") as t:
+        t.extractall(zonedir)
+    print "Converting data at: %s" % (zonedir,)
+    startYear = 1800
+    endYear = 2018
+    PyCalendar.sProdID = "-//calendarserver.org//Zonal//EN"
+    zonefiles = "northamerica", "southamerica", "europe", "africa", "asia", "australasia", "antarctica", "etcetera", "backward"
+    parser = tzconvert()
+    for file in zonefiles:
+        parser.parse(os.path.join(zonedir, file))
+
+    parser.generateZoneinfoFiles(os.path.join(rootdir, "zoneinfo"), startYear, endYear, filterzones=())
+    print "Copy new zoneinfo to destination: %s" % (tzpath,)
+    z = FilePath(os.path.join(rootdir, "zoneinfo"))
+    tz = FilePath(tzpath)
+    z.copyTo(tz)
+    print "Updating XML file at: %s" % (xmlfile,)
+    tzdb.readDatabase()
+    tzdb.updateDatabase()
+    print "Current total: %d" % (len(tzdb.timezones),)
+    print "Total Changed: %d" % (tzdb.changeCount,)
+    if tzdb.changeCount:
+        print "Changed:"
+        for k in sorted(tzdb.changed):
+            print "  %s" % (k,)
+
+    versfile = os.path.join(os.path.dirname(xmlfile), "version.txt")
+    print "Updating version file at: %s" % (versfile,)
+    with open(versfile, "w") as f:
+        f.write("Olson data source: %s\n" % (tzvers,))
+
+
+
+def _doCreate(xmlfile, tzdb):
+    """
+    Create new xml file.
+    """
+
+    print "Creating new XML file at: %s" % (xmlfile,)
+    tzdb.createNewDatabase()
+    print "Current total: %d" % (len(tzdb.timezones),)
+
+
+
+def _doUpdate(xmlfile, tzdb):
+    """
+    Update xml file.
+    """
+
+    print "Updating XML file at: %s" % (xmlfile,)
+    tzdb.readDatabase()
+    tzdb.updateDatabase()
+    print "Current total: %d" % (len(tzdb.timezones),)
+    print "Total Changed: %d" % (tzdb.changeCount,)
+    if tzdb.changeCount:
+        print "Changed:"
+        for k in sorted(tzdb.changed):
+            print "  %s" % (k,)
+
+
+
+def _doList(xmlfile, tzdb):
+    """
+    List current timezones from xml file.
+    """
+
+    print "Listing XML file at: %s" % (xmlfile,)
+    tzdb.readDatabase()
+    print "Current timestamp: %s" % (tzdb.dtstamp,)
+    print "Timezones:"
+    for k in sorted(tzdb.timezones.keys()):
+        print "  %s" % (k,)
+
+
+
+def _doChanged(xmlfile, changed, tzdb):
+    """
+    Check for local timezone changes.
+    """
+
+    print "Changes from XML file at: %s" % (xmlfile,)
+    tzdb.readDatabase()
+    print "Check timestamp: %s" % (changed,)
+    print "Current timestamp: %s" % (tzdb.dtstamp,)
+    results = [k for k, v in tzdb.timezones.items() if v.dtstamp > changed]
+    print "Total Changed: %d" % (len(results),)
+    if results:
+        print "Changed:"
+        for k in sorted(results):
+            print "  %s" % (k,)
+
+
+
 class StandardIOObserver (object):
     """
     Log observer that writes to standard I/O.
@@ -86,25 +185,31 @@
         output.write(text)
         output.flush()
 
+
     def start(self):
         addObserver(self.emit)
 
+
     def stop(self):
         removeObserver(self.emit)
 
+
+
 @inlineCallbacks
 def _runInReactor(tzdb):
-    
+
     try:
         new, changed = yield tzdb.syncWithServer()
-        print "New:           %d" % (new, )
-        print "Changed:       %d" % (changed, )
-        print "Current total: %d" % (len(tzdb.timezones), )
+        print "New:           %d" % (new,)
+        print "Changed:       %d" % (changed,)
+        print "Current total: %d" % (len(tzdb.timezones),)
     except Exception, e:
         print "Could not sync with server: %s" % (str(e),)
     finally:
         reactor.stop()
 
+
+
 def _doSecondaryActions(action, tzpath, xmlfile, url):
 
     tzdb = SecondaryTimezoneDatabase(tzpath, xmlfile, url)
@@ -113,39 +218,45 @@
     except:
         pass
     if action == "cache":
-        print "Caching from secondary server: %s" % (url, )
+        print "Caching from secondary server: %s" % (url,)
 
         observer = StandardIOObserver()
         observer.start()
         reactor.callLater(0, _runInReactor, tzdb)
         reactor.run()
     else:
-        usage("Invalid action: %s" % (action, ))
+        usage("Invalid action: %s" % (action,))
 
+
+
 def usage(error_msg=None):
     if error_msg:
         print error_msg
         print
 
-    print """Usage: timezonestdservice [options]
+    print """Usage: managetimezones [options]
 Options:
     -h            Print this help and exit
     -f            XML file path
     -z            zoneinfo file path
 
     # Primary service
+    --refresh     refresh data from IANA
     --create      create new XML file
     --update      update XML file
     --list        list timezones in XML file
     --changed     changed since timestamp
-    
+
+    --tzvers      year/release letter of IANA data to refresh
+                  default: use the latest release
+
     # Secondary service
     --url         URL or domain of service
     --cache       Cache data from service
 
 Description:
     This utility will create, update or list an XML timezone database
-    summary file.
+    summary file, or refresh iCalendar timezone from IANA (Olson).
 
 """
 
@@ -154,6 +265,8 @@
     else:
         sys.exit(0)
 
+
+
 def main():
     primary = False
     secondary = False
@@ -162,18 +275,21 @@
     xmlfile = None
     changed = None
     url = None
-    
+    tzvers = None
+
     # Get options
     options, _ignore_args = getopt.getopt(
         sys.argv[1:],
         "hf:z:",
         [
+            "refresh",
             "create",
             "update",
             "list",
             "changed=",
             "url=",
             "cache",
+            "tzvers=",
         ]
     )
 
@@ -184,6 +300,9 @@
             xmlfile = value
         elif option == "-z":
             tzpath = value
+        elif option == "--refresh":
+            action = "refresh"
+            primary = True
         elif option == "--create":
             action = "create"
             primary = True
@@ -203,9 +322,11 @@
         elif option == "--cache":
             action = "cache"
             secondary = True
+        elif option == "--tzvers":
+            tzvers = value
         else:
             usage("Unrecognized option: %s" % (option,))
-    
+
     if action is None:
         action = "list"
         primary = True
@@ -228,7 +349,7 @@
         usage("Cannot use primary and secondary options together")
 
     if primary:
-        _doPrimaryActions(action, tzpath, xmlfile, changed)
+        _doPrimaryActions(action, tzpath, xmlfile, changed, tzvers)
     else:
         _doSecondaryActions(action, tzpath, xmlfile, url)
 

Modified: CalendarServer/trunk/support/build.sh
===================================================================
--- CalendarServer/trunk/support/build.sh	2012-09-23 03:36:01 UTC (rev 9842)
+++ CalendarServer/trunk/support/build.sh	2012-09-24 15:52:07 UTC (rev 9843)
@@ -743,7 +743,7 @@
     "${pypi}/p/python-ldap/${ld}.tar.gz";
 
   # XXX actually PyCalendar should be imported in-place.
-  py_dependency -fe -i "src" -r 212 \
+  py_dependency -fe -i "src" -r 214 \
     "pycalendar" "pycalendar" "pycalendar" \
     "http://svn.mulberrymail.com/repos/PyCalendar/branches/server";
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120924/904224f0/attachment-0001.html>


More information about the calendarserver-changes mailing list