[CalendarServer-changes] [5589] CalendarServer/branches/users/wsanchez/transations

source_changes at macosforge.org source_changes at macosforge.org
Tue May 11 02:55:41 PDT 2010


Revision: 5589
          http://trac.macosforge.org/projects/calendarserver/changeset/5589
Author:   glyph at apple.com
Date:     2010-05-11 02:55:35 -0700 (Tue, 11 May 2010)
Log Message:
-----------
Checkpoint: all of twistedcaldav.test passing with all calendar creation going through the new API.

Modified Paths:
--------------
    CalendarServer/branches/users/wsanchez/transations/twistedcaldav/method/mkcalendar.py
    CalendarServer/branches/users/wsanchez/transations/twistedcaldav/resource.py
    CalendarServer/branches/users/wsanchez/transations/twistedcaldav/static.py
    CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_calendarquery.py
    CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_collectioncontents.py
    CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_mkcalendar.py
    CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_multiget.py
    CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_props.py
    CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_wrapping.py
    CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/util.py
    CalendarServer/branches/users/wsanchez/transations/txcaldav/calendarstore/file.py
    CalendarServer/branches/users/wsanchez/transations/txcaldav/icalendarstore.py

Modified: CalendarServer/branches/users/wsanchez/transations/twistedcaldav/method/mkcalendar.py
===================================================================
--- CalendarServer/branches/users/wsanchez/transations/twistedcaldav/method/mkcalendar.py	2010-05-11 01:34:27 UTC (rev 5588)
+++ CalendarServer/branches/users/wsanchez/transations/twistedcaldav/method/mkcalendar.py	2010-05-11 09:55:35 UTC (rev 5589)
@@ -110,9 +110,4 @@
             errors.error()
             raise HTTPError(MultiStatusResponse([errors.response()]))
 
-    # FIXME: this should really be handled by higher-level machinery.  Even
-    # forgetting the obvious abstraction violation, there's no clear way to
-    # ensure that the rollback will be called at all the appropriate times if
-    # it's the responsibility of each method.  A response-filter, maybe?
-    self._newStoreCalendar._transaction.commit()
     returnValue(responsecode.CREATED)

Modified: CalendarServer/branches/users/wsanchez/transations/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/wsanchez/transations/twistedcaldav/resource.py	2010-05-11 01:34:27 UTC (rev 5588)
+++ CalendarServer/branches/users/wsanchez/transations/twistedcaldav/resource.py	2010-05-11 09:55:35 UTC (rev 5589)
@@ -38,7 +38,7 @@
 from twext.web2.dav.http import ErrorResponse
 
 from twisted.internet import reactor
-from twisted.internet.defer import Deferred, succeed
+from twisted.internet.defer import Deferred, succeed, maybeDeferred
 from twisted.internet.defer import inlineCallbacks, returnValue
 from twext.web2 import responsecode
 from twext.web2.dav import davxml
@@ -153,6 +153,54 @@
         return super(CalDAVResource, self).render(request)
 
 
+    _associatedTransaction = None
+
+    def associateWithTransaction(self, transaction):
+        """
+        Associate this resource with a L{txcaldav.idav.ITransaction}; when this
+        resource (or any of its children) are rendered successfully, commit the
+        transaction.  Otherwise, abort the transaction.
+
+        @param transaction: the transaction to associate this resource and its
+            children with.
+
+        @type transaction: L{txcaldav.idav.ITransaction} 
+        """
+        # FIXME: needs to reject association with transaction if it's already
+        # got one (resources associated with a transaction are not reusable)
+        self._associatedTransaction = transaction
+
+
+    def propagateTransaction(self, otherResource):
+        """
+        Propagate the transaction associated with this resource to another
+        resource (which should ostensibly be a child resource).
+
+        @param otherResource: Another L{CalDAVResource}, usually one being
+            constructed as a child of this one.
+
+        @type otherResource: L{CalDAVResource} (or a subclass thereof)
+        """
+        otherResource.associateWithTransaction(self._associatedTransaction)
+
+
+    def renderHTTP(self, request):
+        """
+        Override C{renderHTTP} to commit the transaction when the resource is
+        successfully rendered.
+
+        @param request: the request to generate a response for.
+        @type request: L{twext.web2.iweb.IRequest}
+        """
+        d = maybeDeferred(super(CalDAVResource, self).renderHTTP, request)
+        def succeeded(result):
+            if self._associatedTransaction is not None:
+                self._associatedTransaction.commit()
+            return result
+        # FIXME: needs a failure handler
+        return d.addCallback(succeeded)
+
+
     ##
     # WebDAV
     ##

Modified: CalendarServer/branches/users/wsanchez/transations/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/users/wsanchez/transations/twistedcaldav/static.py	2010-05-11 01:34:27 UTC (rev 5588)
+++ CalendarServer/branches/users/wsanchez/transations/twistedcaldav/static.py	2010-05-11 09:55:35 UTC (rev 5589)
@@ -110,6 +110,7 @@
     NotificationResource
 
 from txcaldav.calendarstore.file import CalendarStore
+from txdav.propertystore.base import PropertyName
 
 log = Logger()
 
@@ -127,6 +128,70 @@
             (caldav_namespace, "calendar-collection-location-ok")
         )
 
+
+class _NewStorePropertiesWrapper(object):
+    """
+    Wrap a new-style property store (a L{txdav.idav.IPropertyStore}) in the old-
+    style interface for compatibility with existing code.
+    """
+    
+    def __init__(self, newPropertyStore):
+        """
+        Initialize an old-style property store from a new one.
+
+        @param newPropertyStore: the new-style property store.
+        @type newPropertyStore: L{txdav.idav.IPropertyStore}
+        """
+        self._newPropertyStore = newPropertyStore
+
+    @classmethod
+    def _convertKey(cls, qname):
+        namespace, name = qname
+        return PropertyName(namespace, name)
+
+
+    # FIXME 'uid' here should be verifying something.
+    def get(self, qname, uid=None):
+        """
+        
+        """
+        try:
+            return self._newPropertyStore[self._convertKey(qname)]
+        except KeyError:
+            raise HTTPError(StatusResponse(
+                    responsecode.NOT_FOUND,
+                    "No such property: {%s}%s" % qname))
+
+
+    def set(self, property, uid=None):
+        """
+        
+        """
+        self._newPropertyStore[self._convertKey(property.qname())] = property
+
+
+    def delete(self, qname, uid=None):
+        """
+        
+        """
+        del self._newPropertyStore[self._convertKey(qname)]
+
+
+    def contains(self, qname, uid=None, cache=True):
+        """
+        
+        """
+        return (self._convertKey(qname) in self._newPropertyStore)
+
+
+    def list(self, uid=None, filterByUID=True, cache=True):
+        """
+        
+        """
+        return [(pname.namespace, pname.name) for pname in 
+                self._newPropertyStore.keys()]
+
+
 class CalDAVFile (LinkFollowerMixIn, CalDAVResource, DAVFile):
     """
     CalDAV-accessible L{DAVFile} resource.
@@ -189,12 +254,15 @@
 
     def deadProperties(self, caching=True):
         if not hasattr(self, "_dead_properties"):
+            # FIXME: this code should actually be dead, as the property store
+            # should be initialized as part of the traversal process.
+ 
             # Get the property store from super
             deadProperties = super(CalDAVFile, self).deadProperties()
 
             if caching:
                 # Wrap the property store in a memory store
-                deadProperties = CachingPropertyStore(deadProperties)
+                 deadProperties = CachingPropertyStore(deadProperties)
 
             self._dead_properties = deadProperties
 
@@ -256,26 +324,6 @@
         @return: a L{Deferred} which fires when the underlying collection has
             actually been created.
         """
-        #
-        # Create the collection once we know it is safe to do so
-        #
-        def onCalendarCollection(status):
-            if status != responsecode.CREATED:
-                raise HTTPError(status)
-
-            # Initialize CTag on the calendar collection
-            d1 = self.bumpSyncToken()
-
-            # Calendar is initially transparent to freebusy
-            self.writeDeadProperty(
-                caldavxml.ScheduleCalendarTransp(caldavxml.Transparent())
-            )
-
-            # Create the index so its ready when the first PUTs come in
-            d1.addCallback(lambda _: self.index().create())
-            d1.addCallback(lambda _: status)
-            return d1
-
         # d = self.createSpecialCollection(davxml.ResourceType.calendar)
         d = succeed(responsecode.CREATED)
         calendarName = self.fp.basename()
@@ -283,9 +331,19 @@
         self._newStoreCalendar = self._newStoreParentHome.calendarWithName(
             calendarName
         )
-        # d.addCallback(onCalendarCollection)
+        self._dead_properties = _NewStorePropertiesWrapper(
+            self._newStoreCalendar.properties()
+        )
         return d
 
+
+    def isCollection(self):
+        if getattr(self, "_newStoreCalendar", None) is not None:
+            # FIXME: this should really be represented by a separate class
+            return True
+        return super(CalDAVFile, self).isCollection()
+
+
     def createSpecialCollection(self, resourceType=None):
         #
         # Create the collection once we know it is safe to do so
@@ -653,6 +711,13 @@
                 self._newStoreCalendar.calendarObjectWithName(
                     similar.fp.basename()
                 )
+            if similar._newStoreObject is not None:
+                # FIXME: what about creation in http_PUT?
+                similar._dead_properties = _NewStorePropertiesWrapper(
+                    similar._newStoreObject.properties()
+                )
+            # FIXME: tests should fail without this:
+            # self.propagateTransaction(similar)
 
             # Short-circuit stat with information we know to be true at this point
             if isinstance(path, FilePath) and hasattr(self, "knownChildren"):
@@ -1022,12 +1087,13 @@
         self.clientNotifier = ClientNotifier(self)
         CalDAVFile.__init__(self, path)
         DirectoryCalendarHomeResource.__init__(self, parent, record)
+        txn = self.parent.parent._newStore.newTransaction()
         self._newStoreCalendarHome = (
-            self.parent.parent._newStore.newTransaction()
-            .calendarHomeWithUID(self.record.uid,
-                                 create=True)
+            txn.calendarHomeWithUID(self.record.uid, create=True)
         )
+        self.associateWithTransaction(txn)
 
+
     def provision(self):
         result = super(CalendarHomeFile, self).provision()
         if config.Sharing.Enabled:
@@ -1078,6 +1144,11 @@
                     similar.fp.basename()
                 )
             )
+            if similar._newStoreCalendar is not None:
+                similar._dead_properties = _NewStorePropertiesWrapper(
+                    similar._newStoreCalendar.properties()
+                )
+            self.propagateTransaction(similar)
             return similar
 
     def getChild(self, name):

Modified: CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_calendarquery.py
===================================================================
--- CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_calendarquery.py	2010-05-11 01:34:27 UTC (rev 5588)
+++ CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_calendarquery.py	2010-05-11 09:55:35 UTC (rev 5589)
@@ -26,13 +26,13 @@
 from twext.web2.dav.util import davXMLFromStream
 from twext.web2.test.test_server import SimpleRequest
 
-import twistedcaldav.test.util
 from twistedcaldav import caldavxml
 from twistedcaldav import ical
 from twistedcaldav.index import db_basename
 from twistedcaldav.query import queryfilter
+from twistedcaldav.test.util import HomeTestCase
 
-class CalendarQuery (twistedcaldav.test.util.TestCase):
+class CalendarQuery (HomeTestCase):
     """
     calendar-query REPORT
     """

Modified: CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_collectioncontents.py
===================================================================
--- CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_collectioncontents.py	2010-05-11 01:34:27 UTC (rev 5588)
+++ CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_collectioncontents.py	2010-05-11 09:55:35 UTC (rev 5589)
@@ -30,34 +30,29 @@
 from twistedcaldav.method.put_common import StoreCalendarObjectResource
 
 
-import twistedcaldav.test.util
-from twistedcaldav.static import CalendarHomeUIDProvisioningFile,\
-    CalendarHomeProvisioningFile
-from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
-from twext.web2.dav import davxml
+from twistedcaldav.test.util import HomeTestCase
 
-class CollectionContents (twistedcaldav.test.util.TestCase):
+class CollectionContents(HomeTestCase):
     """
     PUT request
     """
     data_dir = FilePath(__file__).sibling("data").path
 
     def setUp(self):
-
         # Need to fake out memcache
         def _getFakeMemcacheProtocol(self):
-
             result = super(MemcacheLock, self)._getMemcacheProtocol()
             if isinstance(result, Memcacher.nullCacher):
                 result = self._memcacheProtocol = Memcacher.memoryCacher()
-
             return result
 
-        MemcacheLock._getMemcacheProtocol = _getFakeMemcacheProtocol
+        self.patch(MemcacheLock, "_getMemcacheProtocol", 
+                   _getFakeMemcacheProtocol)
 
         # Need to not do implicit behavior during these tests
         def _fakeDoImplicitScheduling(self):
             return False, False, False
+
         self.patch(StoreCalendarObjectResource , "doImplicitScheduling",
                    _fakeDoImplicitScheduling)
 
@@ -66,36 +61,7 @@
         # like a calendar home'
         super(CollectionContents, self).setUp()
 
-        fp = FilePath(self.mktemp())
 
-        self.createStockDirectoryService()
-
-        # FIXME: see FIXME in DirectoryPrincipalProvisioningResource.__init__;
-        # this performs a necessary modification to the directory service
-        # object.
-        DirectoryPrincipalProvisioningResource(
-            "/principals/", self.directoryService
-        )
-        provFile = CalendarHomeProvisioningFile(fp, self.directoryService, "/")
-
-        users = provFile.getChild("users")
-        user = users.getChild("wsanchez")
-
-        # Fix the site to point directly at the user's calendar home so that we
-        # can focus on testing just that rather than hierarchy traversal..
-        self.site.resource = user
-
-        # Fix the docroot so that 'mkdtemp' will create directories in the right
-        # place (beneath the calendar).
-        self.docroot = user.fp.path
-
-        # Force the request to succeed regardless of the implementation of
-        # accessControlList.
-        user.accessControlList = lambda request, *a, **k: succeed(
-            self.grantInherit(davxml.All())
-        ) 
-
-
     def test_collection_in_calendar(self):
         """
         Make (regular) collection in calendar

Modified: CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_mkcalendar.py
===================================================================
--- CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_mkcalendar.py	2010-05-11 01:34:27 UTC (rev 5588)
+++ CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_mkcalendar.py	2010-05-11 09:55:35 UTC (rev 5589)
@@ -25,11 +25,11 @@
 from twext.web2.dav.fileop import rmdir
 from twext.web2.test.test_server import SimpleRequest
 
-import twistedcaldav.test.util
 from twistedcaldav import caldavxml
 from twistedcaldav.static import CalDAVFile
+from twistedcaldav.test.util import HomeTestCase
 
-class MKCALENDAR (twistedcaldav.test.util.TestCase):
+class MKCALENDAR (HomeTestCase):
     """
     MKCALENDAR request
     """

Modified: CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_multiget.py
===================================================================
--- CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_multiget.py	2010-05-11 01:34:27 UTC (rev 5588)
+++ CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_multiget.py	2010-05-11 09:55:35 UTC (rev 5589)
@@ -26,12 +26,12 @@
 from twext.web2.dav.util import davXMLFromStream
 from twext.web2.test.test_server import SimpleRequest
 
-import twistedcaldav.test.util
 from twistedcaldav import caldavxml
 from twistedcaldav import ical
 from twistedcaldav.index import db_basename
+from twistedcaldav.test.util import HomeTestCase
 
-class CalendarMultiget (twistedcaldav.test.util.TestCase):
+class CalendarMultiget (HomeTestCase):
     """
     calendar-multiget REPORT
     """

Modified: CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_props.py
===================================================================
--- CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_props.py	2010-05-11 01:34:27 UTC (rev 5588)
+++ CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_props.py	2010-05-11 09:55:35 UTC (rev 5589)
@@ -25,9 +25,9 @@
 from twext.web2.test.test_server import SimpleRequest
 from twistedcaldav import caldavxml
 
-import twistedcaldav.test.util
+from twistedcaldav.test.util import HomeTestCase
 
-class Properties (twistedcaldav.test.util.TestCase):
+class Properties(HomeTestCase):
     """
     CalDAV properties
     """

Modified: CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_wrapping.py
===================================================================
--- CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_wrapping.py	2010-05-11 01:34:27 UTC (rev 5588)
+++ CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/test_wrapping.py	2010-05-11 09:55:35 UTC (rev 5589)
@@ -17,21 +17,22 @@
 Tests for the interaction between model-level and protocol-level logic.
 """
 
+from twisted.internet.defer import inlineCallbacks, returnValue
+
 from twext.python.filepath import CachingFilePath as FilePath
 from twext.web2.dav import davxml
-from twisted.internet.defer import inlineCallbacks, returnValue
-from twistedcaldav.config import config
-from twistedcaldav.directory import augment
+
 from twistedcaldav.directory.calendar import uidsResourceName
 from twistedcaldav.directory.principal import (
     DirectoryPrincipalProvisioningResource)
-from twistedcaldav.directory.test.test_xmlfile import augmentsFile, xmlFile
-from twistedcaldav.directory.xmlfile import XMLDirectoryService
+from twistedcaldav.ical import Component as VComponent
+
 from twistedcaldav.static import CalendarHomeProvisioningFile
+
 from twistedcaldav.test.util import TestCase
+
 from txcaldav.calendarstore.file import CalendarStore, CalendarHome
 from txcaldav.calendarstore.test.test_file import event4_text
-from twistedcaldav.ical import Component as VComponent
 
 
 
@@ -52,11 +53,6 @@
         # Setup the initial directory
         self.createStockDirectoryService()
 
-        # Set up a principals hierarchy for each service we're testing with
-        provisioningResource = DirectoryPrincipalProvisioningResource(
-            "/principals/", self.directoryService
-        )
-        self.site.resource.putChild("principals", provisioningResource)
         calendarsPath = FilePath(self.docroot).child("calendars")
         calendarsPath.makedirs()
         self.calendarCollection = CalendarHomeProvisioningFile(

Modified: CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/util.py	2010-05-11 01:34:27 UTC (rev 5588)
+++ CalendarServer/branches/users/wsanchez/transations/twistedcaldav/test/util.py	2010-05-11 09:55:35 UTC (rev 5589)
@@ -15,9 +15,7 @@
 ##
 
 from __future__ import with_statement
-from twistedcaldav.directory.xmlfile import XMLDirectoryService
-from twistedcaldav.directory import augment
-from twext.python.filepath import CachingFilePath as FilePath
+from twext.web2.dav import davxml
 
 __all__ = [
     "featureUnimplemented",
@@ -42,7 +40,11 @@
 
 from twistedcaldav import memcacher
 from twistedcaldav.config import config
-from twistedcaldav.static import CalDAVFile
+from twistedcaldav.static import CalDAVFile, CalendarHomeProvisioningFile
+from twistedcaldav.directory.xmlfile import XMLDirectoryService
+from twistedcaldav.directory import augment
+from twistedcaldav.directory.principal import (
+    DirectoryPrincipalProvisioningResource)
 
 DelayedCall.debug = True
 
@@ -81,7 +83,14 @@
             {'xmlFile' : "accounts.xml"}
         )
 
+        # FIXME: see FIXME in DirectoryPrincipalProvisioningResource.__init__;
+        # this performs a necessary modification to the directory service
+        # object for it to be fully functional.
+        self.principalsResource = DirectoryPrincipalProvisioningResource(
+            "/principals/", self.directoryService
+        )
 
+
     def setUp(self):
         super(TestCase, self).setUp()
 
@@ -239,6 +248,65 @@
         return verifyChildren(root, structure)
 
 
+
+class HomeTestCase(TestCase):
+    """
+    Utility class for tests which wish to interact with a calendar home rather
+    than a top-level resource hierarchy.
+    """
+
+    def setUp(self):
+        """
+        Replace self.site.resource with an appropriately provisioned
+        CalendarHomeFile, and replace self.docroot with a path pointing at that
+        file.
+        """
+        super(HomeTestCase, self).setUp()
+
+        fp = FilePath(self.mktemp())
+
+        self.createStockDirectoryService()
+
+        self.homeProvisioner = CalendarHomeProvisioningFile(
+            fp, self.directoryService, "/"
+        )
+        self._refreshRoot()
+
+
+    def _refreshRoot(self):
+        """
+        Refresh the user resource positioned at the root of this site, to give
+        it a new transaction.
+        """
+        users = self.homeProvisioner.getChild("users")
+        user = users.getChild("wsanchez")
+
+        # Force the request to succeed regardless of the implementation of
+        # accessControlList.
+        user.accessControlList = lambda request, *a, **k: succeed(
+            self.grantInherit(davxml.All())
+        )
+
+        # Fix the site to point directly at the user's calendar home so that we
+        # can focus on testing just that rather than hierarchy traversal..
+        self.site.resource = user
+
+        # Fix the docroot so that 'mkdtemp' will create directories in the right
+        # place (beneath the calendar).
+        self.docroot = user.fp.path
+
+
+    def send(self, request, callback):
+        """
+        Override C{send} in order to refresh the 'user' resource each time, to
+        get a new transaction to associate with the calendar home.
+        """
+        self._refreshRoot()
+        return super(HomeTestCase, self).send(request, callback)
+
+
+
+
 class InMemoryPropertyStore(object):
     def __init__(self):
         class _FauxPath(object):

Modified: CalendarServer/branches/users/wsanchez/transations/txcaldav/calendarstore/file.py
===================================================================
--- CalendarServer/branches/users/wsanchez/transations/txcaldav/calendarstore/file.py	2010-05-11 01:34:27 UTC (rev 5588)
+++ CalendarServer/branches/users/wsanchez/transations/txcaldav/calendarstore/file.py	2010-05-11 09:55:35 UTC (rev 5589)
@@ -16,6 +16,7 @@
 ##
 from twext.web2.dav.element.rfc2518 import ResourceType
 from txdav.propertystore.base import PropertyName
+from twistedcaldav.caldavxml import ScheduleCalendarTransp, Transparent
 
 """
 File calendar store.
@@ -151,6 +152,7 @@
         """
         self.calendarStore = calendarStore
         self.aborted = False
+        self.committed = False
         self._operations = []
         self._calendarHomes = {}
 
@@ -159,11 +161,19 @@
         self._operations.append(operation)
 
     def abort(self):
+        if self.aborted:
+            raise RuntimeError("already aborted")
+        if self.committed:
+            raise RuntimeError("already committed")
         self.aborted = True
 
     def commit(self):
-        assert not self.aborted
+        if self.aborted:
+            raise RuntimeError("already aborted")
+        if self.committed:
+            raise RuntimeError("already committed")
 
+        self.committed = True
         undos = []
 
         for operation in self._operations:
@@ -235,6 +245,10 @@
 
     def uid(self):
         return self._path.basename()
+    
+    
+    def _updateSyncToken(self, reset=False):
+        "Stub for updating sync token."
 
     def calendars(self):
         return set(self._newCalendars.itervalues()) | set(
@@ -268,9 +282,12 @@
         if name not in self._removedCalendars and childPath.isdir():
             raise CalendarAlreadyExistsError(name)
 
+        c = self._newCalendars[name] = Calendar(childPath, self)
         def do():
             try:
                 childPath.createDirectory()
+                # FIXME: direct tests, undo for index creation
+                Index(c)._oldIndex.create()
 
                 # Return undo
                 return lambda: childPath.remove()
@@ -280,9 +297,14 @@
                 raise
 
         self._transaction.addOperation(do)
-        c = self._newCalendars[name] = Calendar(self._path.child(name), self)
-        c.properties()[PropertyName.fromString(ResourceType.sname())] = \
-            ResourceType.calendar
+        props = c.properties()
+        PN = PropertyName.fromString
+        CalendarType = ResourceType.calendar #@UndefinedVariable
+        props[PN(ResourceType.sname())] = CalendarType
+
+        # Calendars are initially transparent to freebusy.  FIXME: freebusy
+        # needs more structured support than this.
+        props[PN(ScheduleCalendarTransp.sname())] = Transparent()
         # FIXME: there's no need for 'flush' to be a public method of the
         # property store any more.  It should just be transactional like
         # everything else; the API here would better be expressed as
@@ -376,7 +398,7 @@
         return (
             self.calendarObjectWithName(name)
             for name in (
-                set(self._newCalendarObjects.iterkeys()) | 
+                set(self._newCalendarObjects.iterkeys()) |
                 set(name for name in self._path.listdir() if not name.startswith("."))
             )
         )
@@ -603,7 +625,6 @@
         return self.component().getOrganizer()
 
     def properties(self):
-        raise NotImplementedError()
         if not hasattr(self, "_properties"):
             self._properties = PropertyStore(self._path)
         return self._properties
@@ -641,9 +662,15 @@
                 return None
 
         def bumpSyncToken(self, reset=False):
+            # FIXME: needs direct tests
             return self.calendar._updateSyncToken(reset)
 
 
+        def initSyncToken(self):
+            # FIXME: needs direct tests
+            self.bumpSyncToken(True)
+
+
     def __init__(self, calendar):
         self.calendar = calendar
         self._oldIndex = OldIndex(Index.StubResource(calendar))

Modified: CalendarServer/branches/users/wsanchez/transations/txcaldav/icalendarstore.py
===================================================================
--- CalendarServer/branches/users/wsanchez/transations/txcaldav/icalendarstore.py	2010-05-11 01:34:27 UTC (rev 5588)
+++ CalendarServer/branches/users/wsanchez/transations/txcaldav/icalendarstore.py	2010-05-11 09:55:35 UTC (rev 5589)
@@ -156,6 +156,22 @@
         home exists.
         """
 
+
+    def abort():
+        """
+        Mark this transaction as invalid, reversing all of its effects.
+        """
+        # FIXME: probably needs to be deferred.
+
+
+    def commit():
+        """
+        Persist the effects of this transaction.
+        """
+        # FIXME: probably needs to be deferred.
+
+
+
 class ICalendarHome(Interface):
     """
     Calendar home
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100511/ae208e81/attachment-0001.html>


More information about the calendarserver-changes mailing list