[CalendarServer-changes] [11172] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Mon May 13 12:19:53 PDT 2013
Revision: 11172
http://trac.calendarserver.org//changeset/11172
Author: cdaboo at apple.com
Date: 2013-05-13 12:19:53 -0700 (Mon, 13 May 2013)
Log Message:
-----------
Allow admins to update timezones via manage_timezones command line tool. This includes having timezone data stored in the
<config.DataRoot> directory.
Modified Paths:
--------------
CalendarServer/trunk/calendarserver/tap/test/test_caldav.py
CalendarServer/trunk/calendarserver/tap/util.py
CalendarServer/trunk/calendarserver/tools/managetimezones.py
CalendarServer/trunk/calendarserver/tools/test/deprovision/caldavd.plist
CalendarServer/trunk/calendarserver/tools/test/gateway/caldavd.plist
CalendarServer/trunk/calendarserver/tools/test/principals/caldavd.plist
CalendarServer/trunk/conf/caldavd-test.plist
CalendarServer/trunk/setup.py
CalendarServer/trunk/support/Apple.make
CalendarServer/trunk/twistedcaldav/stdconfig.py
CalendarServer/trunk/twistedcaldav/test/test_extensions.py
CalendarServer/trunk/twistedcaldav/test/test_timezones.py
CalendarServer/trunk/twistedcaldav/test/util.py
CalendarServer/trunk/twistedcaldav/timezones.py
CalendarServer/trunk/twistedcaldav/timezonestdservice.py
CalendarServer/trunk/twistedcaldav/zoneinfo/version.txt
Added Paths:
-----------
CalendarServer/trunk/doc/calendarserver_manage_timezones.8
Modified: CalendarServer/trunk/calendarserver/tap/test/test_caldav.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/test/test_caldav.py 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/calendarserver/tap/test/test_caldav.py 2013-05-13 19:19:53 UTC (rev 11172)
@@ -349,6 +349,7 @@
self.config.Memcached.Pools.Default.ClientEnabled = False
self.config.Memcached.Pools.Default.ServerEnabled = False
self.config.DirectoryAddressBook.Enabled = False
+ self.config.UsePackageTimezones = True
if self.configOptions:
self.config.update(self.configOptions)
Modified: CalendarServer/trunk/calendarserver/tap/util.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/util.py 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/calendarserver/tap/util.py 2013-05-13 19:19:53 UTC (rev 11172)
@@ -588,6 +588,10 @@
resource = FileResource(info["path"])
root.putChild(name, resource)
+ # Need timezone cache before setting up any timezone service
+ log.info("Setting up Timezone Cache")
+ TimezoneCache.create()
+
# Timezone service is optional
if config.EnableTimezoneService:
log.info("Setting up time zone service resource: %r"
@@ -678,9 +682,6 @@
#
# Configure ancillary data
#
- log.info("Setting up Timezone Cache")
- TimezoneCache.create()
-
log.info("Configuring authentication wrapper")
overrides = {}
Modified: CalendarServer/trunk/calendarserver/tools/managetimezones.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/managetimezones.py 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/calendarserver/tools/managetimezones.py 2013-05-13 19:19:53 UTC (rev 11172)
@@ -25,6 +25,9 @@
from twisted.internet.defer import inlineCallbacks
from twisted.python.filepath import FilePath
+from calendarserver.tools.util import loadConfig
+from twistedcaldav.config import ConfigurationError
+from twistedcaldav.timezones import TimezoneCache
from twistedcaldav.timezonestdservice import PrimaryTimezoneDatabase, \
SecondaryTimezoneDatabase
@@ -36,6 +39,7 @@
import tarfile
import tempfile
import urllib
+from twistedcaldav.stdconfig import DEFAULT_CONFIG_FILE
def _doPrimaryActions(action, tzpath, xmlfile, changed, tzvers):
@@ -68,10 +72,9 @@
print("Downloading latest data from IANA")
if tzvers:
- path = "http://www.iana.org/time-zones/repository/releases/tzdata%s.tar.gz" % (tzvers,)
+ path = "https://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(),)
+ path = "https://www.iana.org/time-zones/repository/tzdata-latest.tar.gz"
data = urllib.urlretrieve(path)
print("Extract data at: %s" % (data[0]))
rootdir = tempfile.mkdtemp()
@@ -79,7 +82,21 @@
os.mkdir(zonedir)
with tarfile.open(data[0], "r:gz") as t:
t.extractall(zonedir)
- print("Converting data at: %s" % (zonedir,))
+
+ # Get the version from the Makefile
+ try:
+ makefile = open(os.path.join(zonedir, "Makefile")).read()
+ lines = makefile.splitlines()
+ for line in lines:
+ if line.startswith("VERSION="):
+ tzvers = line[8:].strip()
+ break
+ except IOError:
+ pass
+
+ if not tzvers:
+ tzvers = PyCalendarDateTime.getToday().getText()
+ print("Converting data (version: %s) at: %s" % (tzvers, zonedir,))
startYear = 1800
endYear = PyCalendarDateTime.getToday().getYear() + 10
PyCalendar.sProdID = "-//calendarserver.org//Zonal//EN"
@@ -106,7 +123,7 @@
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,))
+ f.write(TimezoneCache.IANA_VERSION_PREFIX + tzvers)
@@ -212,26 +229,29 @@
print("""Usage: managetimezones [options]
Options:
-h Print this help and exit
- -f XML file path
+ -f config file path [REQUIRED]
+ -x XML file path
-z zoneinfo file path
+ --tzvers year/release letter of IANA data to refresh
+ default: use the latest release
+ --url URL or domain of secondary service
# Primary service
--refresh refresh data from IANA
+ --refreshpkg refresh package 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, or refresh iCalendar timezone from IANA (Olson).
+ This utility will create, update, or list an XML timezone database
+ summary file, or refresh iCalendar timezone from IANA (Olson). It can
+ also be used to update the server's own zoneinfo database from IANA.
""")
@@ -243,6 +263,7 @@
def main():
+ configFileName = DEFAULT_CONFIG_FILE
primary = False
secondary = False
action = None
@@ -251,13 +272,15 @@
changed = None
url = None
tzvers = None
+ updatepkg = False
# Get options
options, _ignore_args = getopt.getopt(
sys.argv[1:],
- "hf:z:",
+ "f:hx:z:",
[
"refresh",
+ "refreshpkg",
"create",
"update",
"list",
@@ -272,12 +295,18 @@
if option == "-h":
usage()
elif option == "-f":
+ configFileName = value
+ elif option == "-x":
xmlfile = value
elif option == "-z":
tzpath = value
elif option == "--refresh":
action = "refresh"
primary = True
+ elif option == "--refreshpkg":
+ action = "refresh"
+ primary = True
+ updatepkg = True
elif option == "--create":
action = "create"
primary = True
@@ -302,16 +331,29 @@
else:
usage("Unrecognized option: %s" % (option,))
+ if configFileName is None:
+ usage("A configuration file must be specified")
+ try:
+ loadConfig(configFileName)
+ except ConfigurationError, e:
+ sys.stdout.write("%s\n" % (e,))
+ sys.exit(1)
+
if action is None:
action = "list"
primary = True
if tzpath is None:
- try:
- import pkg_resources
- except ImportError:
- tzpath = os.path.join(os.path.dirname(__file__), "zoneinfo")
+ if updatepkg:
+ try:
+ import pkg_resources
+ except ImportError:
+ tzpath = os.path.join(os.path.dirname(__file__), "zoneinfo")
+ else:
+ tzpath = pkg_resources.resource_filename("twistedcaldav", "zoneinfo") #@UndefinedVariable
else:
- tzpath = pkg_resources.resource_filename("twistedcaldav", "zoneinfo") #@UndefinedVariable
+ # Setup the correct zoneinfo path based on the config
+ tzpath = TimezoneCache.getDBPath()
+ TimezoneCache.validatePath()
if xmlfile is None:
xmlfile = os.path.join(tzpath, "timezones.xml")
Modified: CalendarServer/trunk/calendarserver/tools/test/deprovision/caldavd.plist
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/deprovision/caldavd.plist 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/calendarserver/tools/test/deprovision/caldavd.plist 2013-05-13 19:19:53 UTC (rev 11172)
@@ -688,7 +688,10 @@
<key>EnableTimezoneService</key>
<true/>
+ <key>UsePackageTimezones</key>
+ <true/>
+
<!--
Miscellaneous items
-->
Modified: CalendarServer/trunk/calendarserver/tools/test/gateway/caldavd.plist
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/gateway/caldavd.plist 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/calendarserver/tools/test/gateway/caldavd.plist 2013-05-13 19:19:53 UTC (rev 11172)
@@ -666,6 +666,8 @@
<key>EnableTimezoneService</key>
<true/>
+ <key>UsePackageTimezones</key>
+ <true/>
<!--
Miscellaneous items
Modified: CalendarServer/trunk/calendarserver/tools/test/principals/caldavd.plist
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/principals/caldavd.plist 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/calendarserver/tools/test/principals/caldavd.plist 2013-05-13 19:19:53 UTC (rev 11172)
@@ -692,7 +692,10 @@
<key>EnableTimezoneService</key>
<true/>
+ <key>UsePackageTimezones</key>
+ <true/>
+
<!--
Miscellaneous items
-->
Modified: CalendarServer/trunk/conf/caldavd-test.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd-test.plist 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/conf/caldavd-test.plist 2013-05-13 19:19:53 UTC (rev 11172)
@@ -850,6 +850,9 @@
</dict>
</dict>
+ <key>UsePackageTimezones</key>
+ <true/>
+
<!-- Batch Upload via POST -->
<key>EnableBatchUpload</key>
<true/>
Added: CalendarServer/trunk/doc/calendarserver_manage_timezones.8
===================================================================
--- CalendarServer/trunk/doc/calendarserver_manage_timezones.8 (rev 0)
+++ CalendarServer/trunk/doc/calendarserver_manage_timezones.8 2013-05-13 19:19:53 UTC (rev 11172)
@@ -0,0 +1,107 @@
+.\"
+.\" Copyright (c) 2006-2013 Apple Inc. All rights reserved.
+.\"
+.\" Licensed under the Apache License, Version 2.0 (the "License");
+.\" you may not use this file except in compliance with the License.
+.\" You may obtain a copy of the License at
+.\"
+.\" http://www.apache.org/licenses/LICENSE-2.0
+.\"
+.\" Unless required by applicable law or agreed to in writing, software
+.\" distributed under the License is distributed on an "AS IS" BASIS,
+.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+.\" See the License for the specific language governing permissions and
+.\" limitations under the License.
+.\"
+.\" The following requests are required for all man pages.
+.Dd May 11, 2013
+.Dt CALENDARSERVER_MANAGE_TIMEZONES 8
+.Os
+.Sh NAME
+.Nm calendarserver_manage_timezones
+.Nd Calendar Server timezone database management utility
+.Sh SYNOPSIS
+.Nm
+.Op Fl f Ar file
+.Op Fl h
+.Op Fl x Ar file
+.Op Fl z Ar directory
+.Op Fl -tzvers Ar tzdb-version
+.Op Fl -url Ar url
+.Op Fl -refresh
+.Op Fl -refreshpkg
+.Op Fl -create
+.Op Fl -update
+.Op Fl -list
+.Op Fl -changed Ar date
+.Op Fl -cache
+.Sh DESCRIPTION
+.Nm
+This utility will create, update, or list an XML timezone database
+summary XML file, or refresh timezone data from IANA, or refresh
+timezone data from another timezone server.
+.Pp
+It can also be used to update the server's own zoneinfo database
+from IANA.
+.Pp
+It should be run as a user with the same privileges as the Calendar
+Server itself, as it needs to read and write data that belongs to the
+server. If using the --refreshpkg option it will need to write to
+the actual python package data so will need to be run as root.
+.Pp
+Actions to perform are specified via the options below. Only one
+action is allowed.
+.Sh OPTIONS
+.Bl -tag -width flag
+.It Fl h
+Displays usage information
+.It Fl f Ar FILE
+Use the Calendar Server configuration specified in the given file.
+Defaults to /etc/caldavd/caldavd.plist.
+.It Fl x Ar FILE
+Update the timezone database XML file at the specified location.
+Defaults to timezones.xml in the zoneinfo directory.
+.It Fl z Ar DIRECTORY
+Path to a zoneinfo directory where timezone data is stored.
+Defaults to the configuration file's Data/zoneinfo directory.
+.It Fl -tzvers Ar version
+Name of IANA timezone data version to use (e.g., '2013a').
+.It Fl -url
+If the server is configured as a secondary timezone zone, use this URL
+as the URL of the secondary server to pull timezone data from.
+.El
+.Sh ACTIONS
+.Bl -tag -width flag
+.It Fl -refresh
+Update the zoneinfo data from the IANA registry.
+.It Fl -refreshpkg
+Update the server's zoneinfo package data from the IANA registry.
+This updates twistedcaldav.zoneinfo and should only be used by
+server developers wishing to update the server repository.
+.It Fl -create
+Create a new timezone database XML file based on the timezone data
+currently in the zoneinfo directory.
+.It Fl -update
+Update the timezone database XML file based on the timezone data
+currently in the zoneinfo directory.
+.It Fl -list
+List the timezones specified in the timezone database XML file.
+.It Fl -changed Ar date
+List the timezones in the timezone database XML file that have changed
+since the specified date value (YYYYMMHH).
+.It Fl -cache
+Update the server's timezone database by pulling data from a primary
+timezone server.
+.El
+.Sh EXAMPLES
+Update the server's timezone data from the latest IANA data:
+.Pp
+.Dl "calendarserver_manage_timezones --refesh"
+.Pp
+.Sh FILES
+.Bl -tag -width flag
+.It /etc/caldavd/caldavd.plist
+The Calendar Server configuration file.
+.El
+.Sh SEE ALSO
+.Xr caldavd 8
Modified: CalendarServer/trunk/setup.py
===================================================================
--- CalendarServer/trunk/setup.py 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/setup.py 2013-05-13 19:19:53 UTC (rev 11172)
@@ -144,7 +144,7 @@
#"bin/calendarserver_manage_postgres",
"bin/calendarserver_manage_principals",
"bin/calendarserver_manage_push",
- #"bin/calendarserver_manage_timezones",
+ "bin/calendarserver_manage_timezones",
"bin/calendarserver_migrate_resources",
#"bin/calendarserver_monitor_amp_notifications",
#"bin/calendarserver_monitor_notifications",
Modified: CalendarServer/trunk/support/Apple.make
===================================================================
--- CalendarServer/trunk/support/Apple.make 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/support/Apple.make 2013-05-13 19:19:53 UTC (rev 11172)
@@ -102,6 +102,7 @@
$(_v) $(INSTALL_FILE) "$(Sources)/doc/calendarserver_purge_principals.8" "$(DSTROOT)$(SIPP)$(MANDIR)/man8"
$(_v) $(INSTALL_FILE) "$(Sources)/doc/calendarserver_manage_push.8" "$(DSTROOT)$(SIPP)$(MANDIR)/man8"
$(_v) $(INSTALL_FILE) "$(Sources)/doc/calendarserver_shell.8" "$(DSTROOT)$(SIPP)$(MANDIR)/man8"
+ $(_v) $(INSTALL_FILE) "$(Sources)/doc/calendarserver_manage_timezones.8" "$(DSTROOT)$(SIPP)$(MANDIR)/man8"
$(_v) gzip -9 -f "$(DSTROOT)$(SIPP)$(MANDIR)/man8/"*.[0-9]
@echo "Installing launchd config..."
$(_v) $(INSTALL_DIRECTORY) "$(DSTROOT)$(NSLOCALDIR)/$(NSLIBRARYSUBDIR)/Server/Calendar and Contacts"
Modified: CalendarServer/trunk/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/stdconfig.py 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/twistedcaldav/stdconfig.py 2013-05-13 19:19:53 UTC (rev 11172)
@@ -548,7 +548,7 @@
"TimezoneService" : { # New standard timezone service
"Enabled" : False, # Overall on/off switch
"Mode" : "primary", # Can be "primary" or "secondary"
- "BasePath" : "", # Path to zoneinfo - if None use default package path
+ "BasePath" : "", # Path to directory containing a zoneinfo - if None use default package path
# secondary service MUST define its own writable path
"XMLInfoPath" : "", # Path to db cache info - if None use default package path
# secondary service MUST define its own writable path if
@@ -564,6 +564,7 @@
},
"EnableTimezonesByReference" : False, # Strip out VTIMEZONES that are known
+ "UsePackageTimezones" : False, # Use timezone data from twistedcaldav.zoneinfo - don't copy to Data directory
"EnableBatchUpload" : True, # POST batch uploads
"MaxResourcesBatchUpload" : 100, # Maximum number of resources in a batch POST
Modified: CalendarServer/trunk/twistedcaldav/test/test_extensions.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_extensions.py 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/twistedcaldav/test/test_extensions.py 2013-05-13 19:19:53 UTC (rev 11172)
@@ -16,17 +16,18 @@
##
from twext.python.filepath import CachingFilePath as FilePath
-from txdav.xml.element import WebDAVElement, ResourceType
-from txdav.xml.parser import WebDAVDocument
from twext.web2.http_headers import MimeType
from twext.web2.static import MetaDataMixin
from twisted.internet.defer import inlineCallbacks, Deferred, succeed
-from twisted.trial.unittest import TestCase
from twisted.web.microdom import parseString
from twistedcaldav.extensions import DAVFile, DAVResourceWithChildrenMixin, extractCalendarServerPrincipalSearchData
+from twistedcaldav.test.util import TestCase
+from txdav.xml.element import WebDAVElement, ResourceType
+from txdav.xml.parser import WebDAVDocument
+
from xml.etree.cElementTree import XML
class UnicodeProperty(WebDAVElement):
@@ -39,6 +40,7 @@
allowed_children = {}
+
class StrProperty(WebDAVElement):
"""
An element with a unicode name.
@@ -74,7 +76,7 @@
def browserHTML2ETree(htmlString):
"""
Loosely interpret an HTML string as XML and return an ElementTree object for it.
-
+
We're not promising strict XML (in fact, we're specifically saying HTML) in
the content-type of certain responses, but it's much easier to work with
the ElementTree data structures present in Python 2.5+ for testing; so
@@ -222,6 +224,7 @@
self.assertEquals(result[1], ['burger'])
+
class CalendarServerPrincipalSearchTests(TestCase):
def test_extractCalendarServerPrincipalSearchData(self):
"""
@@ -237,13 +240,12 @@
</B:calendarserver-principal-search>
"""
doc = WebDAVDocument.fromString(data)
- tokens, context, applyTo, clientLimit, propElement = extractCalendarServerPrincipalSearchData(doc.root_element)
+ tokens, context, applyTo, clientLimit, _ignore_propElement = extractCalendarServerPrincipalSearchData(doc.root_element)
self.assertEquals(tokens, ["morgen"])
self.assertEquals(context, "attendee")
self.assertFalse(applyTo)
self.assertEquals(clientLimit, None)
-
data = """<B:calendarserver-principal-search xmlns:A="DAV:" xmlns:B="http://calendarserver.org/ns/">
<B:search-token>morgen</B:search-token>
<B:search-token>sagen</B:search-token>
@@ -258,7 +260,7 @@
</B:calendarserver-principal-search>
"""
doc = WebDAVDocument.fromString(data)
- tokens, context, applyTo, clientLimit, propElement = extractCalendarServerPrincipalSearchData(doc.root_element)
+ tokens, context, applyTo, clientLimit, _ignore_propElement = extractCalendarServerPrincipalSearchData(doc.root_element)
self.assertEquals(tokens, ["morgen", "sagen"])
self.assertEquals(context, None)
self.assertTrue(applyTo)
Modified: CalendarServer/trunk/twistedcaldav/test/test_timezones.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_timezones.py 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/twistedcaldav/test/test_timezones.py 2013-05-13 19:19:53 UTC (rev 11172)
@@ -15,6 +15,7 @@
##
import twistedcaldav.test.util
+from twistedcaldav.config import config
from twistedcaldav.ical import Component
from twistedcaldav.timezones import TimezoneCache, TimezoneException
from twistedcaldav.timezones import readTZ, listTZs
@@ -33,16 +34,18 @@
def tearDown(self):
TimezoneCache.clear()
TimezoneCache.create()
-
+
+
def doTest(self, filename, dtstart, dtend, testEqual=True):
-
+
if testEqual:
testMethod = self.assertEqual
else:
testMethod = self.assertNotEqual
calendar = Component.fromStream(file(os.path.join(self.data_dir, filename)))
- if calendar.name() != "VCALENDAR": self.fail("Calendar is not a VCALENDAR")
+ if calendar.name() != "VCALENDAR":
+ self.fail("Calendar is not a VCALENDAR")
instances = calendar.expandTimeRanges(PyCalendarDateTime(2100, 1, 1))
for key in instances:
@@ -51,14 +54,15 @@
end = instance.end
testMethod(start, dtstart)
testMethod(end, dtend)
- break;
+ break
+
def test_truncatedApr(self):
"""
- Properties in components
+ Custom VTZ with truncated standard time - 2006. Daylight 2007 OK.
"""
-
- TimezoneCache.create("")
+
+ TimezoneCache.create(empty=True)
TimezoneCache.clear()
self.doTest(
@@ -67,11 +71,13 @@
PyCalendarDateTime(2007, 04, 01, 17, 0, 0, PyCalendarTimezone(utc=True))
)
+
def test_truncatedDec(self):
"""
- Properties in components
+ Custom VTZ valid from 2007. Daylight 2007 OK.
"""
- TimezoneCache.create("")
+
+ TimezoneCache.create(empty=True)
TimezoneCache.clear()
self.doTest(
@@ -80,12 +86,13 @@
PyCalendarDateTime(2007, 12, 10, 18, 0, 0, PyCalendarTimezone(utc=True))
)
+
def test_truncatedAprThenDecFail(self):
"""
- Properties in components
+ Custom VTZ with truncated standard time - 2006 loaded first. Daylight 2007 OK, standard 2007 wrong.
"""
- TimezoneCache.create("")
+ TimezoneCache.create(empty=True)
TimezoneCache.clear()
self.doTest(
@@ -100,10 +107,12 @@
testEqual=False
)
+
def test_truncatedAprThenDecOK(self):
"""
- Properties in components
+ VTZ loaded from std timezone DB. 2007 OK.
"""
+
TimezoneCache.create()
self.doTest(
@@ -117,11 +126,13 @@
PyCalendarDateTime(2007, 12, 10, 18, 0, 0, PyCalendarTimezone(utc=True)),
)
+
def test_truncatedDecThenApr(self):
"""
- Properties in components
+ Custom VTZ valid from 2007 loaded first. Daylight 2007 OK.
"""
- TimezoneCache.create("")
+
+ TimezoneCache.create(empty=True)
TimezoneCache.clear()
self.doTest(
@@ -135,6 +146,8 @@
PyCalendarDateTime(2007, 04, 01, 17, 0, 0, PyCalendarTimezone(utc=True))
)
+
+
class TimezoneCacheTest (twistedcaldav.test.util.TestCase):
"""
Timezone support tests
@@ -143,13 +156,14 @@
data_dir = os.path.join(os.path.dirname(__file__), "data")
def test_basic(self):
-
+
TimezoneCache.create()
self.assertTrue(readTZ("America/New_York"))
self.assertTrue(readTZ("US/Eastern"))
+
def test_not_in_cache(self):
-
+
TimezoneCache.create()
data = """BEGIN:VCALENDAR
@@ -183,7 +197,8 @@
"""
calendar = Component.fromString(data)
- if calendar.name() != "VCALENDAR": self.fail("Calendar is not a VCALENDAR")
+ if calendar.name() != "VCALENDAR":
+ self.fail("Calendar is not a VCALENDAR")
instances = calendar.expandTimeRanges(PyCalendarDateTime(2100, 1, 1))
for key in instances:
instance = instances[key]
@@ -191,8 +206,10 @@
end = instance.end
self.assertEqual(start, PyCalendarDateTime(2007, 12, 25, 05, 0, 0, PyCalendarTimezone(utc=True)))
self.assertEqual(end, PyCalendarDateTime(2007, 12, 25, 06, 0, 0, PyCalendarTimezone(utc=True)))
- break;
+ break
+
+
class TimezonePackageTest (twistedcaldav.test.util.TestCase):
"""
Timezone support tests
@@ -201,30 +218,59 @@
def setUp(self):
TimezoneCache.clear()
TimezoneCache.create()
-
+
+
def test_ReadTZ(self):
-
+
self.assertTrue(readTZ("America/New_York").find("TZID:America/New_York") != -1)
self.assertRaises(TimezoneException, readTZ, "America/Pittsburgh")
+
def test_ReadTZCached(self):
-
+
self.assertTrue(readTZ("America/New_York").find("TZID:America/New_York") != -1)
self.assertTrue(readTZ("America/New_York").find("TZID:America/New_York") != -1)
self.assertRaises(TimezoneException, readTZ, "America/Pittsburgh")
self.assertRaises(TimezoneException, readTZ, "America/Pittsburgh")
+
def test_ListTZs(self):
-
+
results = listTZs()
self.assertTrue("America/New_York" in results)
self.assertTrue("Europe/London" in results)
self.assertTrue("GB" in results)
+
def test_ListTZsCached(self):
-
+
results = listTZs()
self.assertTrue("America/New_York" in results)
self.assertTrue("Europe/London" in results)
self.assertTrue("GB" in results)
-
+
+
+ def test_copyPackage(self):
+ """
+ Test that copying of the tz package works.
+ """
+
+ self.patch(config, "UsePackageTimezones", True)
+ TimezoneCache.clear()
+ TimezoneCache.create()
+
+ self.assertFalse(os.path.exists(os.path.join(config.DataRoot, "zoneinfo")))
+ self.assertFalse(os.path.exists(os.path.join(config.DataRoot, "zoneinfo", "America", "New_York.ics")))
+
+ pkg_tz = readTZ("America/New_York")
+
+ self.patch(config, "UsePackageTimezones", False)
+ TimezoneCache.clear()
+ TimezoneCache.create()
+
+ self.assertTrue(os.path.exists(os.path.join(config.DataRoot, "zoneinfo")))
+ self.assertTrue(os.path.exists(os.path.join(config.DataRoot, "zoneinfo", "America", "New_York.ics")))
+
+ copy_tz = readTZ("America/New_York")
+
+ self.assertEqual(str(pkg_tz), str(copy_tz))
Modified: CalendarServer/trunk/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/util.py 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/twistedcaldav/test/util.py 2013-05-13 19:19:53 UTC (rev 11172)
@@ -252,6 +252,7 @@
memcacher.Memcacher.allowTestCache = True
memcacher.Memcacher.memoryCacheInstance = None
config.DirectoryAddressBook.Enabled = False
+ config.UsePackageTimezones = True
accounts = FilePath(config.DataRoot).child("accounts.xml")
accounts.setContent(xmlFile.getContent())
@@ -338,6 +339,7 @@
memcacher.Memcacher.allowTestCache = True
memcacher.Memcacher.memoryCacheInstance = None
config.DirectoryAddressBook.Enabled = False
+ config.UsePackageTimezones = True
@property
Modified: CalendarServer/trunk/twistedcaldav/timezones.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/timezones.py 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/twistedcaldav/timezones.py 2013-05-13 19:19:53 UTC (rev 11172)
@@ -18,6 +18,8 @@
from twext.python.log import Logger
+from twisted.python.filepath import FilePath
+
from twistedcaldav.config import config
from pycalendar.timezonedb import PyCalendarTimezoneDatabase
@@ -47,9 +49,13 @@
class TimezoneException(Exception):
pass
+
+
class TimezoneCache(object):
-
+
dirName = None
+ version = "Unknown"
+ IANA_VERSION_PREFIX = "IANA Timezone Registry: "
@staticmethod
def _getPackageDBPath():
@@ -60,22 +66,86 @@
else:
return pkg_resources.resource_filename("twistedcaldav", "zoneinfo") #@UndefinedVariable
+
@staticmethod
def getDBPath():
if TimezoneCache.dirName is None:
if config.TimezoneService.Enabled and config.TimezoneService.BasePath:
TimezoneCache.dirName = config.TimezoneService.BasePath
+ elif config.UsePackageTimezones:
+ TimezoneCache.dirName = TimezoneCache._getPackageDBPath()
else:
- TimezoneCache.dirName = TimezoneCache._getPackageDBPath()
-
+ TimezoneCache.dirName = os.path.join(config.DataRoot, "zoneinfo")
+
return TimezoneCache.dirName
+
@staticmethod
- def create(dbpath=None):
- TimezoneCache.dirName = dbpath
+ def create(empty=False):
+ """
+ Create a timezone database from the files pointed to by the config. The empty option is used
+ only for testing and will point the DB at an empty directory - i.e., no standard timezones are used.
+
+ @param empty: set to C{True} when doing certain tests that do not want the standard timezone database used.
+ @type empty: C{bool}
+ """
+ if empty:
+ TimezoneCache.dirName = ""
+ else:
+ TimezoneCache.dirName = None
+ TimezoneCache.validatePath()
+ TimezoneCache.version = TimezoneCache.getTZVersion(TimezoneCache.getDBPath())
PyCalendarTimezoneDatabase.createTimezoneDatabase(TimezoneCache.getDBPath())
-
+
+
@staticmethod
+ def getTZVersion(dbpath):
+ try:
+ return open(os.path.join(dbpath, "version.txt")).read().strip()
+ except IOError:
+ return TimezoneCache.IANA_VERSION_PREFIX + "Unknown"
+
+
+ class FilteredFilePath(FilePath):
+ """
+ A FilePath that does a directory copy ignoring dot-prefixed files or directories.
+ """
+
+ def copyFilteredDirectoryTo(self, destination):
+ if self.isdir():
+ if not destination.exists():
+ destination.createDirectory()
+ for child in self.children():
+ if child.basename()[0] != ".":
+ destChild = destination.child(child.basename())
+ child = TimezoneCache.FilteredFilePath(child.path)
+ child.copyFilteredDirectoryTo(destChild)
+ elif self.isfile():
+ self.copyTo(destination)
+
+
+ @staticmethod
+ def validatePath():
+ dbpath = FilePath(TimezoneCache.getDBPath())
+ if not dbpath.exists():
+ # Move package data to the path
+ pkgpath = TimezoneCache.FilteredFilePath(TimezoneCache._getPackageDBPath())
+ log.info("Copying timezones from %s to %s" % (pkgpath.path, dbpath.path,))
+ pkgpath.copyFilteredDirectoryTo(dbpath)
+ else:
+ # Check if pkg is more recent and copy over
+ pkgversion = TimezoneCache.getTZVersion(TimezoneCache._getPackageDBPath())
+ dbversion = TimezoneCache.getTZVersion(dbpath.path)
+ if pkgversion > dbversion:
+ dbpath.remove()
+ pkgpath = TimezoneCache.FilteredFilePath(TimezoneCache._getPackageDBPath())
+ log.info("Updating timezones at %s with %s" % (dbpath.path, pkgpath.path,))
+ pkgpath.copyFilteredDirectoryTo(dbpath)
+ else:
+ log.info("Valid timezones at %s" % (dbpath.path,))
+
+
+ @staticmethod
def clear():
PyCalendarTimezoneDatabase.clearTimezoneDatabase()
@@ -94,6 +164,8 @@
readVTZ(tzid)
return True
+
+
def addVTZ(tzid, tzcal):
"""
Add a VTIMEZONE component to the cache.
@@ -101,37 +173,43 @@
if tzid not in cachedVTZs:
cachedVTZs[tzid] = tzcal
cachedTZs[tzid] = str(tzcal)
-
+
+
+
def readVTZ(tzid):
"""
Try to load the specified TZID as a calendar object from the database. Raise if not found.
"""
if tzid not in cachedVTZs:
-
+
tzcal = PyCalendarTimezoneDatabase.getTimezoneInCalendar(tzid)
if tzcal:
cachedVTZs[tzid] = tzcal
else:
raise TimezoneException("Unknown time zone: %s" % (tzid,))
-
+
return cachedVTZs[tzid]
+
+
def readTZ(tzid):
"""
Try to load the specified TZID as text from the database. Raise if not found.
"""
if tzid not in cachedTZs:
-
+
tzcal = readVTZ(tzid)
if tzcal:
cachedTZs[tzid] = str(tzcal)
else:
raise TimezoneException("Unknown time zone: %s" % (tzid,))
-
+
return cachedTZs[tzid]
+
+
def listTZs(path=""):
"""
List all timezones in the database.
@@ -146,7 +224,7 @@
result.extend(listTZs(os.path.join(path, item)))
elif item.endswith(".ics"):
result.append(os.path.join(path, item[:-4]))
-
+
if not path:
cachedTZIDs.extend(result)
return result
Modified: CalendarServer/trunk/twistedcaldav/timezonestdservice.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/timezonestdservice.py 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/twistedcaldav/timezonestdservice.py 2013-05-13 19:19:53 UTC (rev 11172)
@@ -98,7 +98,7 @@
self.timezones.createNewDatabase()
else:
self.timezones.readDatabase()
- self.info_source = "Primary"
+ self.info_source = TimezoneCache.version
def _initSecondaryService(self):
@@ -250,6 +250,7 @@
result = {
"info" : {
+ "version": "1",
"primary-source" if self.primary else "secondary_source": self.info_source,
"contacts" : [],
},
Modified: CalendarServer/trunk/twistedcaldav/zoneinfo/version.txt
===================================================================
--- CalendarServer/trunk/twistedcaldav/zoneinfo/version.txt 2013-05-13 19:02:29 UTC (rev 11171)
+++ CalendarServer/trunk/twistedcaldav/zoneinfo/version.txt 2013-05-13 19:19:53 UTC (rev 11172)
@@ -1 +1 @@
-Olson data source: Latest (20130508)
+IANA Timezone Registry: 2013c
\ No newline at end of file
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130513/cf40aefa/attachment-0001.html>
More information about the calendarserver-changes
mailing list