[CalendarServer-changes] [4513] CalendarServer/branches/more-deferreds-3

source_changes at macosforge.org source_changes at macosforge.org
Fri Aug 28 13:49:32 PDT 2009


Revision: 4513
          http://trac.macosforge.org/projects/calendarserver/changeset/4513
Author:   sagen at apple.com
Date:     2009-08-28 13:49:31 -0700 (Fri, 28 Aug 2009)
Log Message:
-----------
Checkpoint -- more methods being deferred

Modified Paths:
--------------
    CalendarServer/branches/more-deferreds-3/calendarserver/webadmin/resource.py
    CalendarServer/branches/more-deferreds-3/calendarserver/webcal/resource.py
    CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.resource.patch
    CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.static.patch
    CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch
    CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_copy.patch
    CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_delete.patch
    CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_mkcol.patch
    CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_move.patch
    CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_prop.patch
    CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_put.patch
    CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.util.patch
    CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.static.patch
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendar.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendaruserproxy.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/principal.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_principal.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/dropbox.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/extensions.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/freebusyurl.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/index.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/mail.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/memcacheprops.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/method/copymove.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/method/delete_common.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/method/put.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_calquery.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_common.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_multiget.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/resource.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/schedule.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/caldav.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/implicit.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/processing.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/scheduler.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/static.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_index.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_resource.py
    CalendarServer/branches/more-deferreds-3/twistedcaldav/timezoneservice.py

Added Paths:
-----------
    CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.test.test_static.patch

Modified: CalendarServer/branches/more-deferreds-3/calendarserver/webadmin/resource.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/calendarserver/webadmin/resource.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/calendarserver/webadmin/resource.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -31,7 +31,7 @@
 from twistedcaldav.config import config
 from twistedcaldav.extensions import DAVFile, ReadOnlyResourceMixIn
 
-from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 from twisted.web2.http import Response
 from twisted.web2.http_headers import MimeType
 from twisted.web2.stream import MemoryStream
@@ -74,7 +74,7 @@
         return None
 
     def createSimilarFile(self, path):
-        return DAVFile(path, principalCollections=self.principalCollections())
+        return succeed(DAVFile(path, principalCollections=self.principalCollections()))
 
     def directoryStyleSheet(self):
         return (

Modified: CalendarServer/branches/more-deferreds-3/calendarserver/webcal/resource.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/calendarserver/webcal/resource.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/calendarserver/webcal/resource.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -28,6 +28,7 @@
 from urlparse import urlparse
 from cgi import parse_qs
 
+from twisted.internet.defer import succeed
 from twisted.web2 import responsecode
 from twisted.web2.http import Response
 from twisted.web2.http_headers import MimeType
@@ -53,7 +54,7 @@
 
     def etag(self):
         # Can't be calculated here
-        return None
+        return succeed(None)
 
     def contentLength(self):
         # Can't be calculated here
@@ -75,7 +76,7 @@
         return None
 
     def createSimilarFile(self, path):
-        return DAVFile(path, principalCollections=self.principalCollections())
+        return succeed(DAVFile(path, principalCollections=self.principalCollections()))
 
     _htmlContent_lastCheck      = 0
     _htmlContent_statInfo       = 0

Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.resource.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.resource.patch	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.resource.patch	2009-08-28 20:49:31 UTC (rev 4513)
@@ -330,7 +330,18 @@
  
      def mergeAccessControlList(self, new_acl, request):
          """
-@@ -1089,7 +1142,9 @@
+@@ -926,7 +979,9 @@
+         # FIXME: verify acl is self-consistent
+ 
+         # Step 11
+-        self.writeNewACEs(new_set)
++        d = waitForDeferred(self.writeNewACEs(new_set))
++        yield d
++        d.getResult()
+         yield None
+ 
+     mergeAccessControlList = deferredGenerator(mergeAccessControlList)
+@@ -1089,7 +1144,9 @@
              return url
  
          try:
@@ -341,7 +352,7 @@
          except HTTPError, e:
              assert e.response.code == responsecode.NOT_FOUND, (
                  "Expected %s response from readDeadProperty() exception, not %s"
-@@ -1635,7 +1690,9 @@
+@@ -1635,7 +1692,9 @@
  
          # Check this resource first
          if self.isCollection():
@@ -352,9 +363,17 @@
              if qroot is not None:
                  used = waitForDeferred(self.currentQuotaUse(request))
                  yield used
-@@ -1673,7 +1730,10 @@
+@@ -1666,14 +1725,17 @@
+ 
+     def hasQuota(self, request):
          """
+-        Check whether this resource is undre quota control by checking each parent to see if
++        Check whether this resource is under quota control by checking each parent to see if
+         it has a quota root.
          
+         @return: C{True} if under quota control, C{False} if not.
+         """
+         
          # Check this one first
 -        if self.hasQuotaRoot(request):
 +        hasQuotaRoot = waitForDeferred(self.hasQuotaRoot(request))
@@ -364,7 +383,7 @@
              yield True
              return
          
-@@ -1705,10 +1765,19 @@
+@@ -1705,10 +1767,19 @@
          @return: a C{int} containing the maximum allowed bytes if this collection
              is quota-controlled, or C{None} if not quota controlled.
          """
@@ -387,7 +406,7 @@
      
      def quotaRootParent(self, request):
          """
-@@ -1724,7 +1793,10 @@
+@@ -1724,7 +1795,10 @@
              parent = waitForDeferred(request.locateResource(url))
              yield parent
              parent = parent.getResult()
@@ -399,7 +418,7 @@
                  yield parent
                  return
  
-@@ -1741,11 +1813,19 @@
+@@ -1741,11 +1815,19 @@
          assert maxsize is None or isinstance(maxsize, int), "maxsize must be an int or None"
          
          if maxsize is not None:
@@ -422,7 +441,7 @@
      
      def quotaSize(self, request):
          """
-@@ -1795,7 +1875,10 @@
+@@ -1795,7 +1877,10 @@
          
          # Check this resource first
          if self.isCollection():
@@ -434,7 +453,7 @@
                  d = waitForDeferred(self.updateQuotaUse(request, adjust))
                  yield d
                  d.getResult()
-@@ -1825,20 +1908,34 @@
+@@ -1825,20 +1910,34 @@
              is quota-controlled, or C{None} if not quota controlled.
          """
          assert self.isCollection(), "Only collections can have a quota root"
@@ -478,7 +497,7 @@
      def updateQuotaUse(self, request, adjust):
          """
          Update the quota used value on this resource.
-@@ -1848,25 +1945,32 @@
+@@ -1848,25 +1947,32 @@
          @return: an L{Deferred} with a C{int} result containing the current used byte if this collection
              is quota-controlled, or C{None} if not quota controlled.
          """
@@ -528,7 +547,7 @@
      ##
      # HTTP
      ##
-@@ -1880,7 +1984,7 @@
+@@ -1880,7 +1986,7 @@
          # If this is a collection and the URI doesn't end in "/", redirect.
          #
          if self.isCollection() and request.path[-1:] != "/":

Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.static.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.static.patch	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.static.patch	2009-08-28 20:49:31 UTC (rev 4513)
@@ -48,9 +48,46 @@
      def davComplianceClasses(self):
          return ("1", "access-control") # Add "2" when we have locking
  
-@@ -192,7 +214,7 @@
-         return (self.createSimilarFile(self.fp.child(path).path), segments[1:])
+@@ -169,9 +191,12 @@
+         """
+         # If getChild() finds a child resource, return it
+         try:
+-            child = self.getChild(segments[0])
++            child = waitForDeferred(self.getChild(segments[0]))
++            yield child
++            child = child.getResult()
+             if child is not None:
+-                return (child, segments[1:])
++                yield (child, segments[1:])
++                return
+         except InsecurePath:
+             raise HTTPError(StatusResponse(responsecode.FORBIDDEN, "Invalid URL path"))
+         
+@@ -180,19 +205,26 @@
+         # that the request wants created.
+         self.fp.restat(False)
+         if self.fp.exists() and not self.fp.isdir():
+-            return (None, ())
++            yield (None, ())
++            return
  
+         # OK, we need to return a child corresponding to the first segment
+         path = segments[0]
+         
+         if path == "":
+             # Request is for a directory (collection) resource
+-            return (self, ())
++            yield (self, ())
++            return
+ 
+-        return (self.createSimilarFile(self.fp.child(path).path), segments[1:])
++        result = waitForDeferred(self.createSimilarFile(self.fp.child(path).path))
++        yield result
++        result = result.getResult()
++        yield (result, segments[1:])
+ 
++    locateChild = deferredGenerator(locateChild)
++
      def createSimilarFile(self, path):
 -        return self.__class__(
 +        return self.__class__.fetch(None, 

Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_acl.patch	2009-08-28 20:49:31 UTC (rev 4513)
@@ -22,7 +22,18 @@
  
          principalCollection = TestPrincipalsCollection(
              "/principals/",
-@@ -118,8 +122,9 @@
+@@ -93,7 +97,9 @@
+             loginInterfaces
+         ))
+ 
+-        rootResource.setAccessControlList(self.grant(davxml.All()))
++        d = waitForDeferred(rootResource.setAccessControlList(self.grant(davxml.All())))
++        yield d
++        d.getResult( )
+ 
+         for name, acl in (
+             ("none"       , self.grant()),
+@@ -118,8 +124,9 @@
                  os.mkdir(dirname)
              resource = self.resource_class(dirname)
              resource.setAccessControlList(acl)
@@ -33,26 +44,15 @@
  
      def restore(self):
          # Get rid of whatever messed up state the test has now so that we'll
-@@ -134,24 +139,32 @@
-         Verify source access controls during COPY and MOVE.
-         """
-         def work():
--            dst_path = os.path.join(self.docroot, "copy_dst")
-+            docroot = waitForDeferred(self.docroot)
-+            yield docroot
-+            docroot = docroot.getResult()
-+            dst_path = os.path.join(docroot, "copy_dst")
+@@ -137,6 +144,7 @@
+             dst_path = os.path.join(self.docroot, "copy_dst")
              dst_uri = "/" + os.path.basename(dst_path)
  
 +            results = []
              for src, status in (
                  ("nobind", responsecode.FORBIDDEN),
                  ("bind",   responsecode.FORBIDDEN),
-                 ("unbind", responsecode.CREATED),
-             ):
--                src_path = os.path.join(self.docroot, "src_" + src)
-+                src_path = os.path.join(docroot, "src_" + src)
-                 src_uri = "/" + os.path.basename(src_path)
+@@ -147,11 +155,15 @@
                  if not os.path.isdir(src_path):
                      os.mkdir(src_path)
                  src_resource = self.resource_class(src_path)
@@ -70,7 +70,7 @@
                  for name, acl in (
                      ("none"       , self.grant()),
                      ("read"       , self.grant(davxml.Read())),
-@@ -162,8 +175,11 @@
+@@ -162,8 +174,11 @@
                      filename = os.path.join(src_path, name)
                      if not os.path.isfile(filename):
                          file(filename, "w").close()
@@ -83,20 +83,7 @@
                  for method in ("COPY", "MOVE"):
                      for name, code in (
                          ("none"       , {"COPY": responsecode.FORBIDDEN, "MOVE": status}[method]),
-@@ -175,7 +191,11 @@
-                         path = os.path.join(src_path, name)
-                         uri = src_uri + "/" + name
-     
--                        request = SimpleRequest(self.site, method, uri)
-+                        site = waitForDeferred(self.site)
-+                        yield site
-+                        site = site.getResult()
-+
-+                        request = SimpleRequest(site, method, uri)
-                         request.headers.setHeader("destination", dst_uri)
-                         _add_auth_header(request)
-     
-@@ -184,30 +204,56 @@
+@@ -184,12 +199,30 @@
                                  os.remove(dst_path)
      
                              if response.code != code:
@@ -130,36 +117,15 @@
      def test_COPY_MOVE_dest(self):
          """
          Verify destination access controls during COPY and MOVE.
-         """
-         def work():
--            src_path = os.path.join(self.docroot, "read")
-+            docroot = waitForDeferred(self.docroot)
-+            yield docroot
-+            docroot = docroot.getResult()
-+            src_path = os.path.join(docroot, "read")
+@@ -198,6 +231,7 @@
+             src_path = os.path.join(self.docroot, "read")
              uri = "/" + os.path.basename(src_path)
  
 +            results = []
              for method in ("COPY", "MOVE"):
                  for name, code in (
                      ("nobind" , responsecode.FORBIDDEN),
-                     ("bind"   , responsecode.CREATED),
-                     ("unbind" , responsecode.CREATED),
-                 ):
--                    dst_parent_path = os.path.join(self.docroot, name)
-+                    dst_parent_path = os.path.join(docroot, name)
-                     dst_path = os.path.join(dst_parent_path, "dst")
- 
--                    request = SimpleRequest(self.site, method, uri)
-+                    site = waitForDeferred(self.site)
-+                    yield site
-+                    site = site.getResult()
-+
-+                    request = SimpleRequest(site, method, uri)
-                     request.headers.setHeader("destination", "/" + name + "/dst")
-                     _add_auth_header(request)
- 
-@@ -216,39 +262,80 @@
+@@ -216,18 +250,41 @@
                              os.remove(dst_path)
  
                          if response.code != code:
@@ -173,6 +139,11 @@
 -                    yield (request, test)
 +                    results.append((request, test))
                      self.restore()
++                    # restore( ) blows away _docroot explicitly;
++                    # need to repopulate it
++                    d = waitForDeferred(self._getDocumentRoot())
++                    yield d
++                    d.getResult()
  
 -        return serialize(self.send, work())
 +            yield results
@@ -195,29 +166,12 @@
          Verify access controls during DELETE.
          """
          def work():
-+            docroot = waitForDeferred(self.docroot)
-+            yield docroot
-+            docroot = docroot.getResult()
 +            results = []
              for name, code in (
                  ("nobind" , responsecode.FORBIDDEN),
                  ("bind"   , responsecode.FORBIDDEN),
-                 ("unbind" , responsecode.NO_CONTENT),
-             ):
--                collection_path = os.path.join(self.docroot, name)
-+                collection_path = os.path.join(docroot, name)
-                 path = os.path.join(collection_path, "dst")
+@@ -243,12 +300,28 @@
  
-                 file(path, "w").close()
- 
--                request = SimpleRequest(self.site, "DELETE", "/" + name + "/dst")
-+                site = waitForDeferred(self.site)
-+                yield site
-+                site = site.getResult()
-+
-+                request = SimpleRequest(site, "DELETE", "/" + name + "/dst")
-                 _add_auth_header(request)
- 
                  def test(response, code=code, path=path):
                      if response.code != code:
 -                        return self.oops(request, response, code, "DELETE", name)
@@ -248,40 +202,21 @@
      def test_UNLOCK(self):
          """
          Verify access controls during UNLOCK of unowned lock.
-@@ -261,14 +348,19 @@
+@@ -261,8 +334,10 @@
          """
          Verify access controls during MKCOL.
          """
 -        for method in ("MKCOL", "PUT"):
 -            def work():
 +        def work():
-+            docroot = waitForDeferred(self.docroot)
-+            yield docroot
-+            docroot = docroot.getResult()
 +            results = []
 +
 +            for method in ("MKCOL", "PUT"):
                  for name, code in (
                      ("nobind" , responsecode.FORBIDDEN),
                      ("bind"   , responsecode.CREATED),
-                     ("unbind" , responsecode.CREATED),
-                 ):
--                    collection_path = os.path.join(self.docroot, name)
-+                    collection_path = os.path.join(docroot, name)
-                     path = os.path.join(collection_path, "dst")
+@@ -281,17 +356,34 @@
  
-                     if os.path.isfile(path):
-@@ -276,22 +368,45 @@
-                     elif os.path.isdir(path):
-                         os.rmdir(path)
- 
--                    request = SimpleRequest(self.site, method, "/" + name + "/dst")
-+                    site = waitForDeferred(self.site)
-+                    yield site
-+                    site = site.getResult()
-+                    request = SimpleRequest(site, method, "/" + name + "/dst")
-                     _add_auth_header(request)
- 
                      def test(response, code=code, path=path):
                          if response.code != code:
 -                            return self.oops(request, response, code, method, name)
@@ -314,27 +249,12 @@
          Verify access controls during PUT of existing file.
          """
          def work():
-+            docroot = waitForDeferred(self.docroot)
-+            yield docroot
-+            docroot = docroot.getResult()
 +            results = []
              for name, code in (
                  ("none"       , responsecode.FORBIDDEN),
                  ("read"       , responsecode.FORBIDDEN),
-@@ -299,19 +414,38 @@
-                 ("unlock"     , responsecode.FORBIDDEN),
-                 ("all"        , responsecode.NO_CONTENT),
-             ):
--                path = os.path.join(self.docroot, name)
-+                path = os.path.join(docroot, name)
+@@ -306,12 +398,28 @@
  
--                request = SimpleRequest(self.site, "PUT", "/" + name)
-+                site = waitForDeferred(self.site)
-+                yield site
-+                site = site.getResult()
-+                request = SimpleRequest(site, "PUT", "/" + name)
-                 _add_auth_header(request)
- 
                  def test(response, code=code, path=path):
                      if response.code != code:
 -                        return self.oops(request, response, code, "PUT", name)
@@ -365,34 +285,16 @@
      def test_PROPFIND(self):
          """
          Verify access controls during PROPFIND.
-@@ -325,6 +459,10 @@
+@@ -325,6 +433,7 @@
          Verify access controls during PROPPATCH.
          """
          def work():
-+            docroot = waitForDeferred(self.docroot)
-+            yield docroot
-+            docroot = docroot.getResult()
 +            results = []
              for name, code in (
                  ("none"       , responsecode.FORBIDDEN),
                  ("read"       , responsecode.FORBIDDEN),
-@@ -332,9 +470,12 @@
-                 ("unlock"     , responsecode.FORBIDDEN),
-                 ("all"        , responsecode.MULTI_STATUS),
-             ):
--                path = os.path.join(self.docroot, name)
-+                path = os.path.join(docroot, name)
+@@ -342,17 +451,33 @@
  
--                request = SimpleRequest(self.site, "PROPPATCH", "/" + name)
-+                site = waitForDeferred(self.site)
-+                yield site
-+                site = site.getResult()
-+                request = SimpleRequest(site, "PROPPATCH", "/" + name)
-                 request.stream = MemoryStream(
-                     davxml.WebDAVDocument(davxml.PropertyUpdate()).toxml()
-                 )
-@@ -342,17 +483,36 @@
- 
                  def test(response, code=code, path=path):
                      if response.code != code:
 -                        return self.oops(request, response, code, "PROPPATCH", name)
@@ -424,30 +326,12 @@
          Verify access controls during GET and REPORT.
          """
          def work():
-+            docroot = waitForDeferred(self.docroot)
-+            yield docroot
-+            docroot = docroot.getResult()
 +            results = []
              for method in ("GET", "REPORT"):
                  if method == "GET":
                      ok = responsecode.OK
-@@ -368,9 +528,12 @@
-                     ("unlock"     , responsecode.FORBIDDEN),
-                     ("all"        , ok),
-                 ):
--                    path = os.path.join(self.docroot, name)
-+                    path = os.path.join(docroot, name)
+@@ -378,12 +503,27 @@
  
--                    request = SimpleRequest(self.site, method, "/" + name)
-+                    site = waitForDeferred(self.site)
-+                    yield site
-+                    site = site.getResult()
-+                    request = SimpleRequest(site, method, "/" + name)
-                     if method == "REPORT":
-                         request.stream = MemoryStream(davxml.PrincipalPropertySearch().toxml())
- 
-@@ -378,12 +541,27 @@
- 
                      def test(response, code=code, path=path):
                          if response.code != code:
 -                            return self.oops(request, response, code, method, name)

Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_copy.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_copy.patch	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_copy.patch	2009-08-28 20:49:31 UTC (rev 4513)
@@ -68,19 +68,15 @@
      def test_COPY_no_parent(self):
          """
          COPY to resource with no parent.
-@@ -122,18 +151,35 @@
+@@ -122,9 +151,19 @@
                  # FIXME: Check XML error code (2518bis)
                  pass
  
 -        return serialize(self.send, work(self, test, dst=os.path.join(self.docroot, "elvislives!")))
-+        docroot = waitForDeferred(self.docroot)
-+        yield docroot
-+        docroot = docroot.getResult()
- 
-+        d = waitForDeferred(work(self, test, dst=os.path.join(docroot, "elvislives!")))
++        d = waitForDeferred(work(self, test, dst=os.path.join(self.docroot, "elvislives!")))
 +        yield d
 +        results = d.getResult()
-+
+ 
 +        d = waitForDeferred(serialize(self.send, iter(results)))
 +        yield d
 +        d = d.getResult()
@@ -89,37 +85,11 @@
 +    test_COPY_no_parent = deferredGenerator(test_COPY_no_parent)
 +
  def work(self, test, overwrite=None, dst=None, depths=("0", "infinity", None)):
-+    docroot = waitForDeferred(self.docroot)
-+    yield docroot
-+    docroot = docroot.getResult()
 +    results = []
      if dst is None:
--        dst = os.path.join(self.docroot, "dst")
-+        dst = os.path.join(docroot, "dst")
+         dst = os.path.join(self.docroot, "dst")
          os.mkdir(dst)
- 
--    for basename in os.listdir(self.docroot):
-+    for basename in os.listdir(docroot):
-         if basename == "dst": continue
- 
-         uri = urllib.quote("/" + basename)
--        path = os.path.join(self.docroot, basename)
-+        path = os.path.join(docroot, basename)
-         isfile = os.path.isfile(path)
-         sum = sumFile(path)
-         dst_path = os.path.join(dst, basename)
-@@ -151,15 +197,23 @@
-             def do_test(response, path=path, isfile=isfile, sum=sum, uri=uri, depth=depth, dst_path=dst_path):
-                 test(response, path, isfile, sum, uri, depth, dst_path)
- 
--            request = SimpleRequest(self.site, self.__class__.__name__, uri)
-+            site = waitForDeferred(self.site)
-+            yield site
-+            site = site.getResult()
-+            request = SimpleRequest(site, self.__class__.__name__, uri)
-             request.headers.setHeader("destination", dst_uri)
-             if depth is not None:
-                 request.headers.setHeader("depth", depth)
+@@ -158,8 +197,13 @@
              if overwrite is not None:
                  request.headers.setHeader("overwrite", overwrite)
  

Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_delete.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_delete.patch	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_delete.patch	2009-08-28 20:49:31 UTC (rev 4513)
@@ -10,23 +10,16 @@
  from twisted.web2 import responsecode
  from twisted.web2.iweb import IResponse
  from twisted.web2.test.test_server import SimpleRequest
-@@ -54,8 +55,13 @@
+@@ -54,6 +55,8 @@
                  self.fail("DELETE did not remove path %s" % (path,))
  
          def work():
--            for filename in os.listdir(self.docroot):
--                path = os.path.join(self.docroot, filename)
-+            docroot = waitForDeferred(self.docroot)
-+            yield docroot
-+            docroot = docroot.getResult()
 +            results = []
 +
-+            for filename in os.listdir(docroot):
-+                path = os.path.join(docroot, filename)
+             for filename in os.listdir(self.docroot):
+                 path = os.path.join(self.docroot, filename)
                  uri = urllib.quote("/" + filename)
- 
-                 if os.path.isdir(path): uri = uri + "/"
-@@ -63,12 +69,26 @@
+@@ -63,12 +66,26 @@
                  def do_test(response, path=path):
                      return check_result(response, path)
  

Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_mkcol.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_mkcol.patch	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_mkcol.patch	2009-08-28 20:49:31 UTC (rev 4513)
@@ -18,58 +18,23 @@
      # FIXME:
      # Try in nonexistant parent collection.
      # Try on existing resource.
-@@ -43,7 +45,9 @@
-         """
-         MKCOL request
-         """
--        path, uri = self.mkdtemp("collection")
-+        d = waitForDeferred(self.mkdtemp("collection"))
-+        yield d
-+        path, uri = d.getResult()
+@@ -58,8 +60,13 @@
  
-         rmdir(path)
+         request = SimpleRequest(self.site, "MKCOL", uri)
  
-@@ -56,17 +60,28 @@
-             if not os.path.isdir(path):
-                 self.fail("MKCOL did not create directory %s" % (path,))
- 
--        request = SimpleRequest(self.site, "MKCOL", uri)
-+        site = waitForDeferred(self.site)
-+        yield site
-+        site = site.getResult()
- 
 -        return self.send(request, check_result)
-+        request = SimpleRequest(site, "MKCOL", uri)
- 
 +        d = waitForDeferred(self.send(request, check_result))
 +        yield d
 +        d = d.getResult()
 +        yield d
-+
+ 
 +    test_MKCOL = deferredGenerator(test_MKCOL)
 +
      def test_MKCOL_invalid_body(self):
          """
          MKCOL request with invalid request body
-         (Any body at all is invalid in our implementation; there is no
-         such thing as a valid body.)
-         """
--        path, uri = self.mkdtemp("collection")
-+        d = waitForDeferred(self.mkdtemp("collection"))
-+        yield d
-+        path, uri = d.getResult()
- 
-         rmdir(path)
- 
-@@ -79,7 +94,15 @@
-             if os.path.isdir(path):
-                 self.fail("MKCOL incorrectly created directory %s" % (path,))
- 
--        request = SimpleRequest(self.site, "MKCOL", uri)
-+        site = waitForDeferred(self.site)
-+        yield site
-+        site = site.getResult()
-+        request = SimpleRequest(site, "MKCOL", uri)
+@@ -82,4 +89,9 @@
+         request = SimpleRequest(self.site, "MKCOL", uri)
          request.stream = MemoryStream("This is not a valid MKCOL request body.")
  
 -        return self.send(request, check_result)

Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_move.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_move.patch	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_move.patch	2009-08-28 20:49:31 UTC (rev 4513)
@@ -10,14 +10,11 @@
  import twisted.web2.dav.test.util
  import twisted.web2.dav.test.test_copy
  from twisted.web2 import responsecode
-@@ -60,8 +61,21 @@
+@@ -60,8 +61,18 @@
                  if sum != sumFile(dst_path):
                      self.fail("isdir %s produced different directory" % (uri,))
  
 -        return serialize(self.send, work(self, test))
-+        docroot = waitForDeferred(self.docroot)
-+        yield docroot
-+        docroot = docroot.getResult()
  
 +        d = waitForDeferred(work(self, test))
 +        yield d
@@ -33,19 +30,15 @@
      def test_MOVE_exists(self):
          """
          MOVE to existing resource.
-@@ -74,8 +88,21 @@
+@@ -74,8 +85,17 @@
                  # FIXME: Check XML error code (2518bis)
                  pass
  
 -        return serialize(self.send, work(self, test, overwrite=False))
-+        docroot = waitForDeferred(self.docroot)
-+        yield docroot
-+        docroot = docroot.getResult()
- 
 +        d = waitForDeferred(work(self, test, overwrite=False))
 +        yield d
 +        d = d.getResult()
-+
+ 
 +        d = waitForDeferred(serialize(self.send, iter(d)))
 +        yield d
 +        d = d.getResult( )
@@ -56,19 +49,15 @@
      def test_MOVE_overwrite(self):
          """
          MOVE to existing resource with overwrite header.
-@@ -88,8 +115,21 @@
+@@ -88,8 +108,17 @@
                  # FIXME: Check XML error code (2518bis)
                  pass
  
 -        return serialize(self.send, work(self, test, overwrite=True))
-+        docroot = waitForDeferred(self.docroot)
-+        yield docroot
-+        docroot = docroot.getResult()
- 
 +        d = waitForDeferred(work(self, test, overwrite=True))
 +        yield d
 +        d = d.getResult()
-+
+ 
 +        d = waitForDeferred(serialize(self.send, iter(d)))
 +        yield d
 +        d = d.getResult( )
@@ -79,16 +68,13 @@
      def test_MOVE_no_parent(self):
          """
          MOVE to resource with no parent.
-@@ -102,7 +142,20 @@
+@@ -102,7 +131,17 @@
                  # FIXME: Check XML error code (2518bis)
                  pass
  
 -        return serialize(self.send, work(self, test, dst=os.path.join(self.docroot, "elvislives!")))
-+        docroot = waitForDeferred(self.docroot)
-+        yield docroot
-+        docroot = docroot.getResult()
  
-+        d = waitForDeferred(work(self, test, dst=os.path.join(docroot, "elvislives!")))
++        d = waitForDeferred(work(self, test, dst=os.path.join(self.docroot, "elvislives!")))
 +        yield d
 +        d = d.getResult()
 +

Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_prop.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_prop.patch	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_prop.patch	2009-08-28 20:49:31 UTC (rev 4513)
@@ -10,19 +10,11 @@
  from twisted.trial.unittest import SkipTest
  from twisted.web2 import responsecode
  from twisted.web2.iweb import IResponse
-@@ -57,6 +58,15 @@
+@@ -57,6 +58,7 @@
      PROPFIND, PROPPATCH requests
      """
  
-+    def setUp(self):
-+        # Pre-fetch site, so the rest of the test doesn't have to defer
-+        twisted.web2.dav.test.util.TestCase.setUp(self)
-+        self._getSite()
 +
-+    def _getStoredSite(self):
-+        return self._site
-+    site = property(_getStoredSite)
-+
      def liveProperties(self):
          return [lookupElement(qname)() for qname in self.resource_class.liveProperties if (qname[0] == dav_namespace) and qname not in dynamicLiveProperties]
  

Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_put.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_put.patch	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.test_put.patch	2009-08-28 20:49:31 UTC (rev 4513)
@@ -10,49 +10,41 @@
  from twisted.web2 import responsecode
  from twisted.web2.iweb import IResponse
  from twisted.web2.stream import FileStream
-@@ -42,27 +43,38 @@
+@@ -44,25 +45,31 @@
          """
-         PUT request
-         """
--        dst_path = os.path.join(self.docroot, "dst")
-+        docroot = waitForDeferred(self.docroot)
-+        yield docroot
-+        docroot = docroot.getResult()
+         dst_path = os.path.join(self.docroot, "dst")
  
 -        def checkResult(response, path):
 -            response = IResponse(response)
-+        dst_path = os.path.join(docroot, "dst")
++        def makeClosure(path):
  
 -            if response.code not in (
 -                responsecode.CREATED,
 -                responsecode.NO_CONTENT
 -            ):
 -                self.fail("PUT failed: %s" % (response.code,))
-+        def makeClosure(path):
++            # Return a function with 'path' closed
  
 -            if not os.path.isfile(dst_path):
 -                self.fail("PUT failed to create file %s." % (dst_path,))
-+            # Return a function with 'path' closed
- 
--            if not filecmp.cmp(path, dst_path):
--                self.fail("PUT failed to preserve data for file %s in file %s." % (path, dst_path))
 +            def checkResult(response):
 +                response = IResponse(response)
  
--            etag = response.headers.getHeader("etag")
--            if not etag:
--                self.fail("No etag header in PUT response %r." % (response,))
+-            if not filecmp.cmp(path, dst_path):
+-                self.fail("PUT failed to preserve data for file %s in file %s." % (path, dst_path))
 +                if response.code not in (
 +                    responsecode.CREATED,
 +                    responsecode.NO_CONTENT
 +                ):
 +                    self.fail("PUT failed: %s" % (response.code,))
  
+-            etag = response.headers.getHeader("etag")
+-            if not etag:
+-                self.fail("No etag header in PUT response %r." % (response,))
 +                if not os.path.isfile(dst_path):
 +                    self.fail("PUT failed to create file %s." % (dst_path,))
-+
+ 
 +                if not filecmp.cmp(path, dst_path):
-+                    import pdb; pdb.set_trace()
 +
 +                    self.fail("PUT failed to preserve data for file %s in file %s." % (path, dst_path))
 +
@@ -64,31 +56,23 @@
          #
          # We need to serialize these request & test iterations because they can
          # interfere with each other.
-@@ -70,52 +82,79 @@
+@@ -70,6 +77,7 @@
          def work():
              dst_uri = "/dst"
  
--            for name in os.listdir(self.docroot):
 +            results = []
-+            for name in os.listdir(docroot):
+             for name in os.listdir(self.docroot):
                  if name == "dst":
                      continue
+@@ -78,38 +86,53 @@
  
--                path = os.path.join(self.docroot, name)
-+                path = os.path.join(docroot, name)
- 
                  # Can't really PUT something you can't read
                  if not os.path.isfile(path): continue
 -    
 -                def do_test(response): checkResult(response, path)
 -    
--                request = SimpleRequest(self.site, "PUT", dst_uri)
 +
-+                site = waitForDeferred(self.site)
-+                yield site
-+                site = site.getResult()
-+
-+                request = SimpleRequest(site, "PUT", dst_uri)
+                 request = SimpleRequest(self.site, "PUT", dst_uri)
                  request.stream = FileStream(file(path, "rb"))
 -    
 -                yield (request, do_test)
@@ -116,12 +100,8 @@
          """
          PUT on existing resource with If-None-Match header
          """
--        dst_path = os.path.join(self.docroot, "dst")
-+        docroot = waitForDeferred(self.docroot)
-+        yield docroot
-+        docroot = docroot.getResult()
 +
-+        dst_path = os.path.join(docroot, "dst")
+         dst_path = os.path.join(self.docroot, "dst")
          dst_uri = "/dst"
  
          def work():
@@ -150,18 +130,7 @@
  
                  def onError(f):
                      f.trap(HTTPError)
-                     return checkResult(f.value.response)
- 
--                request = SimpleRequest(self.site, "PUT", dst_uri)
-+                site = waitForDeferred(self.site)
-+                yield site
-+                site = site.getResult()
-+
-+                request = SimpleRequest(site, "PUT", dst_uri)
-                 request.stream = FileStream(file(__file__, "rb"))
-     
-                 if code == responsecode.CREATED:
-@@ -125,10 +164,23 @@
+@@ -125,10 +148,23 @@
                  elif code == responsecode.PRECONDITION_FAILED:
                      request.headers.setHeader("if-none-match", ("*",))
      
@@ -187,16 +156,8 @@
      def test_PUT_no_parent(self):
          """
          PUT with no parent
-@@ -142,7 +194,16 @@
-                 self.fail("Incorrect response code for PUT with no parent (%s != %s)"
-                           % (response.code, responsecode.CONFLICT))
- 
--        request = SimpleRequest(self.site, "PUT", dst_uri)
-+        site = waitForDeferred(self.site)
-+        yield site
-+        site = site.getResult()
-+
-+        request = SimpleRequest(site, "PUT", dst_uri)
+@@ -145,4 +181,9 @@
+         request = SimpleRequest(self.site, "PUT", dst_uri)
          request.stream = FileStream(file(__file__, "rb"))
  
 -        return self.send(request, checkResult)

Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.util.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.util.patch	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.dav.test.util.patch	2009-08-28 20:49:31 UTC (rev 4513)
@@ -50,7 +50,7 @@
  
          dirnames = (
              os.path.join(docroot, "dir1"),                          # 0
-@@ -149,17 +153,23 @@
+@@ -149,37 +153,56 @@
          for dirname in (docroot,) + dirnames[3:8+1]:
              for filename in filenames[:5]:
                  copy(filename, dirname)
@@ -69,45 +69,46 @@
 +            yield d
 +            self._docroot = d.getResult()
  
--        return self._docroot
 +        yield self._docroot
- 
++
 +    _getDocumentRoot = deferredGenerator(_getDocumentRoot)
 +
++    def _getStoredDocumentRoot(self):
+         return self._docroot
+ 
      def _setDocumentRoot(self, value):
          self._docroot = value
  
-@@ -167,10 +177,13 @@
+-    docroot = property(_getDocumentRoot, _setDocumentRoot)
++    docroot = property(_getStoredDocumentRoot, _setDocumentRoot)
  
      def _getSite(self):
          if not hasattr(self, "_site"):
--            rootresource = self.resource_class(self.docroot)
-+            d = waitForDeferred(self.docroot)
+             rootresource = self.resource_class(self.docroot)
+-            rootresource.setAccessControlList(self.grantInherit(davxml.All()))
++            d = waitForDeferred(rootresource.setAccessControlList(self.grantInherit(davxml.All())))
 +            yield d
-+            rootresource = self.resource_class(d.getResult())
-             rootresource.setAccessControlList(self.grantInherit(davxml.All()))
++            d.getResult()
              self._site = Site(rootresource)
--        return self._site
 +        yield self._site
 +    _getSite = deferredGenerator(_getSite)
++
++    def _getStoredSite(self):
+         return self._site
  
      def _setSite(self, site):
          self._site = site
-@@ -191,11 +204,15 @@
-         Creates a new directory in the document root and returns its path and
-         URI.
-         """
--        path = mkdtemp(prefix=prefix + "_", dir=self.docroot)
-+        d = waitForDeferred(self.docroot)
-+        yield d
-+        path = mkdtemp(prefix=prefix + "_", dir=d.getResult())
-         uri  = joinURL("/", url_quote(os.path.basename(path))) + "/"
  
--        return (path, uri)
-+        yield (path, uri)
+-    site = property(_getSite, _setSite)
++    site = property(_getStoredSite, _setSite)
  
-+    mkdtemp = deferredGenerator(mkdtemp)
-+
-     def send(self, request, callback):
-         log.msg("Sending %s request for URI %s" % (request.method, request.uri))
+     def setUp(self):
+         unittest.TestCase.setUp(self)
+         TestFile._cachedPropertyStores = {}
++        d = self._getDocumentRoot()
++        d.addCallback(lambda _: self._getSite())
++        return d
++        # self._getSite()
  
+     def tearDown(self):
+         unittest.TestCase.tearDown(self)

Modified: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.static.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.static.patch	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.static.patch	2009-08-28 20:49:31 UTC (rev 4513)
@@ -49,8 +49,41 @@
      def renderHTTP(self, request):
          """
          See L{resource.RenderMixIn.renderHTTP}.
-@@ -132,8 +140,8 @@
+@@ -100,16 +108,23 @@
  
+             # Don't provide additional resource information to error responses
+             if response.code < 400:
+-                # Content-* headers refer to the response content, not
+-                # (necessarily) to the resource content, so they depend on the
+-                # request method, and therefore can't be set here.
+-                for (header, value) in (
+-                    ("etag", self.etag()),
+-                    ("last-modified", self.lastModified()),
+-                ):
+-                    if value is not None:
+-                        response.headers.setHeader(header, value)
++                d = self.etag()
++                def _gotEtag(etag):
++                    # Content-* headers refer to the response content, not
++                    # (necessarily) to the resource content, so they depend on the
++                    # request method, and therefore can't be set here.
++                    for (header, value) in (
++                        ("etag", etag),
++                        ("last-modified", self.lastModified()),
++                    ):
++                        if value is not None:
++                            response.headers.setHeader(header, value)
+ 
++                    return response
++
++                d.addCallback(_gotEtag)
++                return d
++
+             return response
+ 
+         def onError(f):
+@@ -132,8 +147,8 @@
+ 
      def etag(self):
          lastModified = self.lastModified()
 -        return http_headers.ETag("%X-%X" % (lastModified, hash(self.data)),
@@ -60,7 +93,7 @@
  
      def lastModified(self):
          return self.creationDate()
-@@ -217,7 +225,7 @@
+@@ -217,7 +232,7 @@
          return self.fp.exists()
  
      def etag(self):
@@ -69,7 +102,7 @@
  
          st = self.fp.statinfo
  
-@@ -228,10 +236,10 @@
+@@ -228,10 +243,10 @@
          #
          weak = (time.time() - st.st_mtime <= 1)
  
@@ -82,7 +115,7 @@
  
      def lastModified(self):
          if self.fp.exists():
-@@ -291,12 +299,13 @@
+@@ -291,12 +306,13 @@
          self.ignoredExts.append(ext)
  
      def directoryListing(self):
@@ -102,7 +135,27 @@
      def putChild(self, name, child):
          """
          Register a child with the given name with this resource.
-@@ -329,7 +338,7 @@
+@@ -311,16 +327,16 @@
+         @return: the child of this resource with the given name.
+         """
+         if name == "":
+-            return self
++            return succeed(self)
+ 
+         child = self.putChildren.get(name, None)
+-        if child: return child
++        if child: return succeed(child)
+ 
+         child_fp = self.fp.child(name)
+         if child_fp.exists():
+             return self.createSimilarFile(child_fp.path)
+         else:
+-            return None
++            return succeed(None)
+ 
+     def listChildren(self):
+         """
+@@ -329,21 +345,27 @@
          children = self.putChildren.keys()
          if self.fp.isdir():
              children += [c for c in self.fp.listdir() if c not in children]
@@ -111,11 +164,70 @@
  
      def locateChild(self, req, segments):
          """
-@@ -387,17 +396,17 @@
+         See L{IResource}C{.locateChild}.
+         """
+         # If getChild() finds a child resource, return it
+-        child = self.getChild(segments[0])
+-        if child is not None: return (child, segments[1:])
++        child = waitForDeferred(self.getChild(segments[0]))
++        yield child
++        child = child.getResult()
++        if child is not None:
++            yield (child, segments[1:])
++            return
+ 
+         # If we're not backed by a directory, we have no children.
+         # But check for existance first; we might be a collection resource
+         # that the request wants created.
+         self.fp.restat(False)
+-        if self.fp.exists() and not self.fp.isdir(): return (None, ())
++        if self.fp.exists() and not self.fp.isdir():
++            yield (None, ())
++            return
+ 
+         # OK, we need to return a child corresponding to the first segment
+         path = segments[0]
+@@ -352,24 +374,29 @@
+             fpath = self.fp.child(path)
+         else:
+             # Request is for a directory (collection) resource
+-            return (self, server.StopTraversal)
++            yield (self, server.StopTraversal)
++            return
+ 
+         # Don't run processors on directories - if someone wants their own
+         # customized directory rendering, subclass File instead.
+         if fpath.isfile():
+             processor = self.processors.get(fpath.splitext()[1].lower())
+             if processor:
+-                return (
+-                    processor(fpath.path),
+-                    segments[1:])
++                yield (processor(fpath.path), segments[1:])
++                return
+ 
+         elif not fpath.exists():
+             sibling_fpath = fpath.siblingExtensionSearch(*self.ignoredExts)
+             if sibling_fpath is not None:
+                 fpath = sibling_fpath
+ 
+-        return self.createSimilarFile(fpath.path), segments[1:]
++        result = waitForDeferred(self.createSimilarFile(fpath.path), segments[1:])
++        yield result
++        result = result.getResult()
++        yield result
+ 
++    locateChild = deferredGenerator(locateChild)
++
+     def renderHTTP(self, req):
+         self.fp.restat(False)
+         return super(File, self).renderHTTP(req)
+@@ -387,17 +414,18 @@
                  ifp = self.fp.childSearchPreauth(*self.indexNames)
                  if ifp:
                      # Render from the index file
 -                    standin = self.createSimilarFile(ifp.path)
++                    # MOR: What is going on here?
 +                    standin = self.createSimilarFile(ifp.path).render(req)
                  else:
                      # Render from a DirectoryLister
@@ -138,3 +250,14 @@
  
          try:
              f = self.fp.open()
+@@ -423,8 +451,8 @@
+         return response
+ 
+     def createSimilarFile(self, path):
+-        return self.__class__(path, self.defaultType, self.ignoredExts,
+-                              self.processors, self.indexNames[:])
++        return succeed(self.__class__(path, self.defaultType, self.ignoredExts,
++                              self.processors, self.indexNames[:]))
+ 
+ 
+ class FileSaver(resource.PostableResource):

Added: CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.test.test_static.patch
===================================================================
--- CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.test.test_static.patch	                        (rev 0)
+++ CalendarServer/branches/more-deferreds-3/lib-patches/Twisted/twisted.web2.test.test_static.patch	2009-08-28 20:49:31 UTC (rev 4513)
@@ -0,0 +1,17 @@
+Index: twisted/web2/test/test_static.py
+===================================================================
+--- twisted/web2/test/test_static.py	(revision 26969)
++++ twisted/web2/test/test_static.py	(working copy)
+@@ -34,7 +34,11 @@
+         """
+         Test that we can get an ETag
+         """
+-        self.failUnless(self.data.etag())
++        d = self.data.etag()
++        def _callback(etag):
++            self.failUnless(etag)
++        d.addCallback(_callback)
++        return d
+ 
+ 
+     def test_render(self):

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendar.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendar.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendar.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -151,17 +151,18 @@
     def url(self):
         return joinURL(self._parent.url(), self.recordType)
 
+    @inlineCallbacks
     def getChild(self, name, record=None):
-        self.provision()
+        yield self.provision()
         if name == "":
-            return self
+            returnValue(self)
 
         if record is None:
             record = self.directory.recordWithShortName(self.recordType, name)
             if record is None:
-                return None
+                returnValue(None)
 
-        return self._parent.homeForDirectoryRecord(record)
+        returnValue((yield self._parent.homeForDirectoryRecord(record)))
 
     def listChildren(self):
         if config.EnablePrincipalListings:
@@ -213,17 +214,18 @@
     def url(self):
         return joinURL(self.parent.url(), uidsResourceName)
 
+    @inlineCallbacks
     def getChild(self, name, record=None):
-        self.provision()
+        yield self.provision()
         if name == "":
-            return self
+            returnValue(self)
 
         if record is None:
             record = self.directory.recordWithUID(name)
             if record is None:
-                return None
+                returnValue(None)
 
-        return self.provisionChild(name)
+        returnValue((yield self.provisionChild(name)))
 
     def listChildren(self):
         # Not a listable collection
@@ -311,8 +313,8 @@
 
             # Set calendar-free-busy-set on inbox
             inbox = self.getChild("inbox")
-            inbox.provision()
-            inbox.processFreeBusyCalendar(childURL, True)
+            yield inbox.provision()
+            yield inbox.processFreeBusyCalendar(childURL, True)
 
             # Default calendar is marked as the default for scheduling
             yield inbox.writeDeadProperty(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(childURL)))
@@ -455,7 +457,7 @@
 
         @return: a C{True} if this resource has quota root, C{False} otherwise.
         """
-        return config.UserQuota != 0
+        return succeed(config.UserQuota != 0)
     
     def quotaRoot(self, request):
         """

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendaruserproxy.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/calendaruserproxy.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -131,9 +131,9 @@
 
     def resourceType(self):
         if self.proxyType == "calendar-proxy-read":
-            return davxml.ResourceType.calendarproxyread
+            return succeed(davxml.ResourceType.calendarproxyread)
         elif self.proxyType == "calendar-proxy-write":
-            return davxml.ResourceType.calendarproxywrite
+            return succeed(davxml.ResourceType.calendarproxywrite)
         else:
             return super(CalendarUserProxyPrincipalResource, self).resourceType()
 

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/principal.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/principal.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -837,14 +837,14 @@
             result = (yield CalendarPrincipalResource.readProperty(self, property, request))
         returnValue(result)
 
+    @inlineCallbacks
     def extraDirectoryBodyItems(self, request):
-        d = self.calendarHomeURLs()
-        def _gotURLs(homeURLs):
-            return "".join((
-                    """\nCalendar homes:\n"""          , format_list(format_link(u) for u in homeURLs),
-                    """\nCalendar user addresses:\n""" , format_list(format_link(a) for a in self.calendarUserAddresses()),
-                    ))
-        return d.addCallbacks(_gotURLs)
+        homeURLs = (yield self.calendarHomeURLs())
+        cuas = (yield self.calendarUserAddresses())
+        returnValue( "".join((
+            """\nCalendar homes:\n"""          , format_list(format_link(u) for u in homeURLs),
+            """\nCalendar user addresses:\n""" , format_list(format_link(a) for a in cuas),
+        )))
 
     ##
     # CalDAV
@@ -865,7 +865,7 @@
         # Add a UUID URI based on the record's GUID to the list.
         addresses.add("urn:uuid:%s" % (self.record.guid,))
 
-        return addresses
+        return succeed(addresses)
 
     def enabledAsOrganizer(self):
         if self.record.recordType == DirectoryService.recordType_users:

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_principal.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_principal.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/directory/test/test_principal.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -317,6 +317,7 @@
         for provisioningResource, recordType, recordResource, record in self._allRecords():
             self.assertEquals(record.guid, recordResource.principalUID())
 
+    @inlineCallbacks
     def test_calendarUserAddresses(self):
         """
         DirectoryPrincipalResource.calendarUserAddresses()
@@ -327,7 +328,7 @@
                     (
                         set((recordResource.principalURL(),)) |
                         set(record.calendarUserAddresses)
-                    ).issubset(set(recordResource.calendarUserAddresses()))
+                    ).issubset(set((yield recordResource.calendarUserAddresses())))
                 )
 
     def test_calendarHomeURLs(self):

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/dropbox.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/dropbox.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/dropbox.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -24,6 +24,7 @@
     "DropBoxChildResource",
 ]
 
+from twisted.internet.defer import succeed
 from twext.web2.dav.davxml import ErrorResponse
 from twisted.web2 import responsecode
 from twisted.web2.dav import davxml
@@ -39,7 +40,7 @@
     Drop box collection resource.
     """
     def resourceType(self):
-        return davxml.ResourceType.dropboxhome
+        return succeed(davxml.ResourceType.dropboxhome)
 
     def isCollection(self):
         return True
@@ -52,7 +53,7 @@
     Drop box resource.
     """
     def resourceType(self):
-        return davxml.ResourceType.dropbox
+        return succeed(davxml.ResourceType.dropbox)
 
     def isCollection(self):
         return True

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/extensions.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/extensions.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -700,7 +700,7 @@
 
         if namespace == dav_namespace:
             if name == "resourcetype":
-                returnValue(self.resourceType())
+                returnValue((yield self.resourceType()))
 
         elif namespace == calendarserver_namespace:
             if name == "expanded-group-member-set":
@@ -741,14 +741,15 @@
     def expandedGroupMemberships(self):
         return succeed(())
 
+    @inlineCallbacks
     def resourceType(self):
         # Allow live property to be overridden by dead property
-        if self.deadProperties().contains((dav_namespace, "resourcetype")):
-            return self.deadProperties().get((dav_namespace, "resourcetype"))
+        if (yield self.deadProperties().contains((dav_namespace, "resourcetype"))):
+            returnValue((yield self.deadProperties().get((dav_namespace, "resourcetype"))))
         if self.isCollection():
-            return davxml.ResourceType(davxml.Collection(), davxml.Principal())
+            returnValue(davxml.ResourceType(davxml.Collection(), davxml.Principal()))
         else:
-            return davxml.ResourceType(davxml.Principal())
+            returnValue(davxml.ResourceType(davxml.Principal()))
 
 
 class DAVFile (SudoSACLMixin, SuperDAVFile, LoggingMixIn):
@@ -762,17 +763,18 @@
             qname = property.qname()
 
         if qname == (dav_namespace, "resourcetype"):
-            return succeed(self.resourceType())
+            return self.resourceType()
 
         return super(DAVFile, self).readProperty(property, request)
 
+    @inlineCallbacks
     def resourceType(self):
         # Allow live property to be overridden by dead property
-        if self.deadProperties().contains((dav_namespace, "resourcetype")):
-            return self.deadProperties().get((dav_namespace, "resourcetype"))
+        if (yield self.deadProperties().contains((dav_namespace, "resourcetype"))):
+            returnValue((yield self.deadProperties().get((dav_namespace, "resourcetype"))))
         if self.isCollection():
-            return davxml.ResourceType.collection
-        return davxml.ResourceType.empty
+            returnValue(davxml.ResourceType.collection)
+        returnValue(davxml.ResourceType.empty)
 
     def render(self, request):
         if not self.fp.exists():
@@ -783,6 +785,9 @@
                 # Redirect to include trailing '/' in URI
                 return RedirectResponse(request.unparseURL(path=urllib.quote(urllib.unquote(request.path), safe=':/')+'/'))
             else:
+                # MOR: Not sure what to do here -- it may be that render( )
+                # can't easily be deferred, in which case createSimilarFile( )
+                # will be a problem...
                 ifp = self.fp.childSearchPreauth(*self.indexNames)
                 if ifp:
                     # Render from the index file
@@ -1091,52 +1096,55 @@
         self.propertyStore = propertyStore
         self.resource = propertyStore.resource
 
+    @inlineCallbacks
     def get(self, qname):
         #self.log_debug("Get: %r, %r" % (self.resource.fp.path, qname))
 
-        cache = self._cache()
+        cache = (yield self._cache())
 
         if qname in cache:
             property = cache.get(qname, None)
             if property is None:
                 self.log_debug("Cache miss: %r, %r, %r" % (self, self.resource.fp.path, qname))
                 try:
-                    property = self.propertyStore.get(qname)
+                    property = (yield self.propertyStore.get(qname))
                 except HTTPError:
                     del cache[qname]
                     raise PropertyNotFoundError(qname)
                 cache[qname] = property
 
-            return property
+            returnValue(property)
         else:
             raise PropertyNotFoundError(qname)
 
+    @inlineCallbacks
     def set(self, property):
         #self.log_debug("Set: %r, %r" % (self.resource.fp.path, property))
 
-        cache = self._cache()
+        cache = (yield self._cache())
 
         cache[property.qname()] = None
-        self.propertyStore.set(property)
+        yield self.propertyStore.set(property)
         cache[property.qname()] = property
-        return succeed(None)
+        returnValue(None)
 
+    @inlineCallbacks
     def contains(self, qname):
         #self.log_debug("Contains: %r, %r" % (self.resource.fp.path, qname))
 
         try:
-            cache = self._cache()
+            cache = (yield self._cache())
         except HTTPError, e:
             if e.response.code == responsecode.NOT_FOUND:
-                return False
+                returnValue(False)
             else:
                 raise
 
         if qname in cache:
             #self.log_debug("Contains cache hit: %r, %r, %r" % (self, self.resource.fp.path, qname))
-            return True
+            returnValue(True)
         else:
-            return False
+            returnValue(False)
 
     def delete(self, qname):
         #self.log_debug("Delete: %r, %r" % (self.resource.fp.path, qname))
@@ -1146,18 +1154,21 @@
 
         self.propertyStore.delete(qname)
 
+    @inlineCallbacks
     def list(self):
         #self.log_debug("List: %r" % (self.resource.fp.path,))
-        return self._cache().iterkeys()
+        cache = (yield self._cache())
+        returnValue(cache.iterkeys())
 
+    @inlineCallbacks
     def _cache(self):
         if not hasattr(self, "_data"):
             #self.log_debug("Cache init: %r" % (self.resource.fp.path,))
             self._data = dict(
                 (name, None)
-                for name in self.propertyStore.list()
+                for name in (yield self.propertyStore.list())
             )
-        return self._data
+        returnValue(self._data)
 
 
     def flushCache(self):

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/freebusyurl.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/freebusyurl.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/freebusyurl.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -22,7 +22,7 @@
     "FreeBusyURLResource",
 ]
 
-from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 from twisted.python import log
 from twisted.web2 import responsecode
 from twisted.web2.dav import davxml
@@ -96,16 +96,16 @@
         return davxml.ACL(*aces)
 
     def resourceType(self):
-        return davxml.ResourceType.freebusyurl
+        return succeed(davxml.ResourceType.freebusyurl)
 
     def isCollection(self):
         return False
 
     def isCalendarCollection(self):
-        return False
+        return succeed(False)
 
     def isPseudoCalendarCollection(self):
-        return False
+        return succeed(False)
 
     def render(self, request):
         output = """<html>
@@ -203,7 +203,7 @@
         
         # Pick the first mailto cu address or the first other type
         cuaddr = None
-        for item in principal.calendarUserAddresses():
+        for item in (yield principal.calendarUserAddresses()):
             if cuaddr is None:
                 cuaddr = item
             if item.startswith("mailto"):

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/index.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/index.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/index.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -742,6 +742,7 @@
             index. C{resource} must be a calendar collection (i.e.
             C{resource.isPseudoCalendarCollection()} returns C{True}.)
         """
+        # MOR: isCalendarCollection( ) is now deferred.  What to do here?
         assert resource.isCalendarCollection(), "non-calendar collection resource %s has no index." % (resource,)
         super(Index, self).__init__(resource)
 
@@ -844,6 +845,7 @@
             index. C{resource} must be a calendar collection (i.e.
             C{resource.isPseudoCalendarCollection()} returns C{True}.)
         """
+        # MOR: isCalendarCollection( ) is now deferred.  What to do here?
         assert resource.isPseudoCalendarCollection() and not resource.isCalendarCollection(), "non-calendar collection resource %s has no index." % (resource,)
         super(IndexSchedule, self).__init__(resource)
 

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/mail.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/mail.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/mail.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -225,16 +225,16 @@
         return succeed(self.iMIPACL)
 
     def resourceType(self):
-        return davxml.ResourceType.ischeduleinbox
+        return succeed(davxml.ResourceType.ischeduleinbox)
 
     def isCollection(self):
         return False
 
     def isCalendarCollection(self):
-        return False
+        return succeed(False)
 
     def isPseudoCalendarCollection(self):
-        return False
+        return succeed(False)
 
     def deadProperties(self):
         if not hasattr(self, "_dead_properties"):

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/memcacheprops.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/memcacheprops.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/memcacheprops.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -283,7 +283,7 @@
             path = self.child.fp.path
             key = self.parentPropertyCollection._keyForPath(path)
             parentPropertyCache = (yield self.parentPropertyCollection.propertyCache())
-            returnValue(parentPropertyCache.get(key, ({}, None))[0])
+            returnValue((yield parentPropertyCache.get(key, ({}, None)))[0])
 
         def flushCache(self):
             self.parentPropertyCollection.flushCache(self.child)
@@ -304,21 +304,23 @@
                            % (qname, self.childPropertyStore.resource.fp.path))
             returnValue((yield self.childPropertyStore.get(qname)))
 
+        @inlineCallbacks
         def set(self, property):
             self.log_debug("Write for %s on %s"
                            % (property.qname(), self.childPropertyStore.resource.fp.path))
 
-            self.parentPropertyCollection.setProperty(self.child, property)
-            self.childPropertyStore.set(property)
-            return succeed(None)
+            yield self.parentPropertyCollection.setProperty(self.child, property)
+            yield self.childPropertyStore.set(property)
+            returnValue(None)
 
+        @inlineCallbacks
         def delete(self, qname):
             self.log_debug("Delete for %s on %s"
                            % (qname, self.childPropertyStore.resource.fp.path))
 
-            self.parentPropertyCollection.deleteProperty(self.child, qname)
-            self.childPropertyStore.delete(qname)
-            return succeed(None)
+            yield self.parentPropertyCollection.deleteProperty(self.child, qname)
+            yield self.childPropertyStore.delete(qname)
+            returnValue(None)
 
         @inlineCallbacks
         def contains(self, qname, cache=True):
@@ -328,7 +330,7 @@
 
             self.log_debug("Contains for %s"
                            % (self.childPropertyStore.resource.fp.path,))
-            returnValue(self.childPropertyStore.contains(qname))
+            returnValue((yield self.childPropertyStore.contains(qname)))
 
         @inlineCallbacks
         def list(self, cache=True):
@@ -338,4 +340,4 @@
 
             self.log_debug("List for %s"
                            % (self.childPropertyStore.resource.fp.path,))
-            returnValue(self.childPropertyStore.list())
+            returnValue((yield self.childPropertyStore.list()))

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/method/copymove.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/method/copymove.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/method/copymove.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -48,7 +48,7 @@
     """
 
     # Copy of calendar collections isn't allowed.
-    if isPseudoCalendarCollectionResource(self):
+    if (yield isPseudoCalendarCollectionResource(self)):
         returnValue(responsecode.FORBIDDEN)
 
     result, sourcecal, sourceparent, destination_uri, destination, destinationcal, destinationparent = (yield checkForCalendarAction(self, request))
@@ -79,7 +79,7 @@
         )
 
     # Checks for copying a calendar collection
-    if self.isCalendarCollection():
+    if (yield self.isCalendarCollection()):
         log.err("Attempt to copy a calendar collection into another calendar collection %s" % destination)
         raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "calendar-collection-location-ok")))
 
@@ -118,7 +118,7 @@
     """
     result, sourcecal, sourceparent, destination_uri, destination, destinationcal, destinationparent = (yield checkForCalendarAction(self, request))
     if not result:
-        is_calendar_collection = isPseudoCalendarCollectionResource(self)
+        is_calendar_collection = (yield isPseudoCalendarCollectionResource(self))
         defaultCalendar = (yield self.isDefaultCalendar(request)) if is_calendar_collection else False
 
         # Do default WebDAV action
@@ -154,7 +154,7 @@
 
     if destinationcal:
         # Checks for copying a calendar collection
-        if self.isCalendarCollection():
+        if (yield self.isCalendarCollection()):
             log.err("Attempt to move a calendar collection into another calendar collection %s" % destination)
             raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "calendar-collection-location-ok")))
     
@@ -219,7 +219,7 @@
 
     # Check for parent calendar collection
     sourceparent = (yield request.locateResource(parentForURL(request.uri)))
-    if isCalendarCollectionResource(sourceparent):
+    if (yield isCalendarCollectionResource(sourceparent)):
         result = True
         sourcecal = True
     
@@ -238,7 +238,7 @@
     # Check for parent calendar collection
     destination_uri = urlsplit(destination_uri)[2]
     destinationparent = (yield request.locateResource(parentForURL(destination_uri)))
-    if isCalendarCollectionResource(destinationparent):
+    if (yield isCalendarCollectionResource(destinationparent)):
         result = True
         destinationcal = True
 

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/method/delete_common.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/method/delete_common.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/method/delete_common.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -105,7 +105,7 @@
             yield delresource.quotaSizeAdjust(self.request, -old_size)
 
         if response == responsecode.NO_CONTENT:
-            if isPseudoCalendarCollectionResource(parent):
+            if (yield isPseudoCalendarCollectionResource(parent)):
                 index = parent.index()
                 index.deleteResource(delresource.fp.basename())
 
@@ -278,10 +278,10 @@
     @inlineCallbacks
     def run(self):
 
-        if isCalendarCollectionResource(self.parent):
+        if (yield isCalendarCollectionResource(self.parent)):
             response = (yield self.deleteCalendarResource(self.resource, self.resource_uri, self.parent))
             
-        elif isCalendarCollectionResource(self.resource):
+        elif (yield isCalendarCollectionResource(self.resource)):
             response = (yield self.deleteCalendar(self.resource, self.resource_uri, self.parent))
         
         elif self.resource.isCollection():

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/method/put.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/method/put.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/method/put.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -39,7 +39,7 @@
     parentURL = parentForURL(request.uri)
     parent = (yield request.locateResource(parentURL))
 
-    if isPseudoCalendarCollectionResource(parent):
+    if (yield isPseudoCalendarCollectionResource(parent)):
         self.fp.restat(False)
 
         # Content-type check

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_calquery.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_calquery.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_calquery.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -58,7 +58,7 @@
 
     if not self.isCollection():
         parent = (yield self.locateParent(request, request.uri))
-        if not parent.isPseudoCalendarCollection():
+        if not (yield parent.isPseudoCalendarCollection()):
             log.err("calendar-query report is not allowed on a resource outside of a calendar collection %s" % (self,))
             raise HTTPError(StatusResponse(responsecode.FORBIDDEN, "Must be calendar collection or calendar resource"))
 
@@ -146,12 +146,12 @@
                 else:
                     href = davxml.HRef.fromString(uri)
             
-                returnValue(report_common.responseForHref(request, responses, href, resource, calendar, timezone, propertiesForResource, query, isowner))
+                returnValue((yield report_common.responseForHref(request, responses, href, resource, calendar, timezone, propertiesForResource, query, isowner)))
             else:
                 returnValue(None)
     
         # Check whether supplied resource is a calendar or a calendar object resource
-        if calresource.isPseudoCalendarCollection():
+        if (yield calresource.isPseudoCalendarCollection()):
             # Get the timezone property from the collection if one was not set in the query,
             # and store in the query filter for later use
             has_prop = (yield calresource.hasProperty((caldav_namespace, "calendar-timezone"), request))
@@ -174,11 +174,11 @@
                 try:
                     # Get list of children that match the search and have read
                     # access
-                    results = yield calresource.index().indexedSearch(filter)
+                    results = (yield calresource.index().indexedSearch(filter))
                     names = [name for name, ignore_uid, ignore_type
                         in results]
                 except IndexedSearchException:
-                    results = yield calresource.index().bruteForceSearch()
+                    results = (yield calresource.index().bruteForceSearch())
                     names = [name for name, ignore_uid, ignore_type
                         in results]
                     index_query_ok = False
@@ -203,7 +203,7 @@
                     child_path_name = urllib.unquote(child_uri_name)
                     
                     if generate_calendar_data or not index_query_ok:
-                        calendar = yield calresource.iCalendar(child_path_name)
+                        calendar = (yield calresource.iCalendar(child_path_name))
                         assert calendar is not None, "Calendar %s is missing from calendar collection %r" % (child_uri_name, self)
                     else:
                         calendar = None
@@ -216,7 +216,7 @@
             if query_tz is None:
 
                 parent = (yield calresource.locateParent(request, uri))
-                assert parent is not None and parent.isPseudoCalendarCollection()
+                assert parent is not None and (yield parent.isPseudoCalendarCollection())
 
                 has_prop = (yield parent.hasProperty((caldav_namespace, "calendar-timezone"), request))
                 if has_prop:
@@ -227,7 +227,7 @@
             # Check private events access status
             isowner = (yield calresource.isOwner(request, adminprincipals=True, readprincipals=True))
 
-            calendar = yield calresource.iCalendar()
+            calendar = (yield calresource.iCalendar())
             yield queryCalendarObjectResource(calresource, uri, None, calendar, timezone)
 
         returnValue(True)

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_common.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_common.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_common.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -85,7 +85,7 @@
             return
 
     # When scanning we only go down as far as a calendar collection - not into one
-    if resource.isPseudoCalendarCollection():
+    if (yield resource.isPseudoCalendarCollection()):
         resources = [(resource, request_uri)]
     elif not resource.isCollection():
         resources = [(resource, request_uri)]

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_multiget.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_multiget.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/method/report_multiget.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -54,7 +54,7 @@
     # Make sure target resource is of the right type
     if not self.isCollection():
         parent = (yield self.locateParent(request, request.uri))
-        if not parent.isPseudoCalendarCollection():
+        if not (yield parent.isPseudoCalendarCollection()):
             log.err("calendar-multiget report is not allowed on a resource outside of a calendar collection %s" % (self,))
             raise HTTPError(StatusResponse(responsecode.FORBIDDEN, "Must be calendar resource"))
 
@@ -105,7 +105,7 @@
     """
 
     disabled = False
-    if self.isPseudoCalendarCollection():
+    if (yield self.isPseudoCalendarCollection()):
         requestURIis = "calendar"
 
         # Do some optimisation of access control calculation by determining any inherited ACLs outside of
@@ -216,7 +216,7 @@
     
                     parent = (yield child.locateParent(request, resource_uri))
     
-                    if not parent.isCalendarCollection() or not parent.index().resourceExists(name):
+                    if not (yield parent.isCalendarCollection()) or not parent.index().resourceExists(name):
                         responses.append(davxml.StatusResponse(href, davxml.Status.fromResponseCode(responsecode.FORBIDDEN)))
                         continue
                     
@@ -245,7 +245,7 @@
     
                     parent = (yield self.locateParent(request, resource_uri))
     
-                    if not parent.isPseudoCalendarCollection() or not parent.index().resourceExists(name):
+                    if not (yield parent.isPseudoCalendarCollection()) or not parent.index().resourceExists(name):
                         responses.append(davxml.StatusResponse(href, davxml.Status.fromResponseCode(responsecode.FORBIDDEN)))
                         continue
                     child = self

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/resource.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/resource.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -115,6 +115,7 @@
     # HTTP
     ##
 
+    @inlineCallbacks
     def render(self, request):
         if config.EnableMonolithicCalendars:
             #
@@ -139,24 +140,20 @@
         else:
             renderAsHTML = True
 
-        if not renderAsHTML and self.isPseudoCalendarCollection():
+        if not renderAsHTML and (yield self.isPseudoCalendarCollection()):
             # Render a monolithic iCalendar file
             if request.path[-1] != "/":
                 # Redirect to include trailing '/' in URI
-                return RedirectResponse(request.unparseURL(path=urllib.quote(urllib.unquote(request.path), safe=':/')+'/'))
+                returnValue(RedirectResponse(request.unparseURL(path=urllib.quote(urllib.unquote(request.path), safe=':/')+'/')))
 
-            def _defer(data):
-                response = Response()
-                response.stream = MemoryStream(str(data))
-                response.headers.setHeader("content-type", MimeType.fromString("text/calendar"))
-                return response
+            data = (yield self.iCalendarRolledup(request))
+            response = Response()
+            response.stream = MemoryStream(str(data))
+            response.headers.setHeader("content-type", MimeType.fromString("text/calendar"))
+            returnValue(response)
 
-            d = self.iCalendarRolledup(request)
-            d.addCallback(_defer)
-            return d
+        returnValue((yield super(CalDAVResource, self).render(request)))
 
-        return super(CalDAVResource, self).render(request)
-
     def renderHTTP(self, request):
         response = maybeDeferred(super(CalDAVResource, self).renderHTTP, request)
 
@@ -197,6 +194,7 @@
         *[caldavxml.CalendarComponent(name=item) for item in allowedComponents]
     )
 
+    @inlineCallbacks
     def hasProperty(self, property, request):
         """
         Need to special case schedule-calendar-transp for backwards compatability.
@@ -208,10 +206,10 @@
             qname = property.qname()
 
         # Force calendar collections to always appear to have the property
-        if qname == (caldav_namespace, "schedule-calendar-transp") and self.isCalendarCollection():
-            return succeed(True)
+        if qname == (caldav_namespace, "schedule-calendar-transp") and (yield self.isCalendarCollection()):
+            returnValue(True)
         else:
-            return super(CalDAVResource, self).hasProperty(property, request)
+            returnValue((yield super(CalDAVResource, self).hasProperty(property, request)))
 
     @inlineCallbacks
     def readProperty(self, property, request):
@@ -258,7 +256,7 @@
             elif name == "schedule-calendar-transp":
                 # For backwards compatibility, if the property does not exist we need to create
                 # it and default to the old free-busy-set value.
-                if self.isCalendarCollection() and not (yield self.hasDeadProperty(property)):
+                if (yield self.isCalendarCollection()) and not (yield self.hasDeadProperty(property)):
                     # For backwards compatibility we need to sync this up with the calendar-free-busy-set on the inbox
                     principal = (yield self.ownerPrincipal(request))
                     fbset = (yield principal.calendarFreeBusyURIs(request))
@@ -276,7 +274,7 @@
         )
 
         if property.qname() == (caldav_namespace, "supported-calendar-component-set"):
-            if not self.isPseudoCalendarCollection():
+            if not (yield self.isPseudoCalendarCollection()):
                 raise HTTPError(StatusResponse(
                     responsecode.FORBIDDEN,
                     "Property %s may only be set on calendar collection." % (property,)
@@ -306,7 +304,7 @@
                 ))
 
         elif property.qname() == (caldav_namespace, "schedule-calendar-transp"):
-            if not self.isCalendarCollection():
+            if not (yield self.isCalendarCollection()):
                 raise HTTPError(StatusResponse(
                     responsecode.FORBIDDEN,
                     "Property %s may only be set on calendar collection." % (property,)
@@ -320,7 +318,7 @@
             if inboxURL:
                 inbox = (yield request.locateResource(inboxURL))
                 myurl = (yield self.canonicalURL(request))
-                inbox.processFreeBusyCalendar(myurl, property.children[0] == caldavxml.Opaque())
+                yield inbox.processFreeBusyCalendar(myurl, property.children[0] == caldavxml.Opaque())
 
         result = (yield super(CalDAVResource, self).writeProperty(property, request))
         returnValue(result)
@@ -498,6 +496,21 @@
             return ca
 
         def gotChild(child, childpath, children):
+            def isCalCallback(result):
+                if result:
+                    callback(child, childpath)
+                elif child.isCollection():
+                    if depth == "infinity":
+                        fc = child.findCalendarCollections(depth, request, callback, privileges)
+                        fc.addCallback(lambda x: reactor.callLater(0, getChild, children))
+                        return fc
+                reactor.callLater(0, getChild, children)
+
+            d = child.isCalendarCollection()
+            d.addCallback(isCalCallback)
+            return d
+
+            """ MOR: Remove
             if child.isCalendarCollection():
                 callback(child, childpath)
             elif child.isCollection():
@@ -505,8 +518,8 @@
                     fc = child.findCalendarCollections(depth, request, callback, privileges)
                     fc.addCallback(lambda x: reactor.callLater(0, getChild, children))
                     return fc
-
             reactor.callLater(0, getChild, children)
+            """
 
         def getChild(children):
             try:
@@ -552,7 +565,7 @@
         inboxURL = yield principal.scheduleInboxURL()
         if inboxURL:
             inbox = (yield request.locateResource(inboxURL))
-            inbox.processFreeBusyCalendar(request.path, False)
+            yield inbox.processFreeBusyCalendar(request.path, False)
 
     @inlineCallbacks
     def movedCalendar(self, request, defaultCalendar, destination, destination_uri):
@@ -567,8 +580,8 @@
             (_ignore_scheme, _ignore_host, destination_path, _ignore_query, _ignore_fragment) = urlsplit(normalizeURL(destination_uri))
 
             inbox = (yield request.locateResource(inboxURL))
-            inbox.processFreeBusyCalendar(request.path, False)
-            inbox.processFreeBusyCalendar(destination_uri, (yield destination.isCalendarOpaque()))
+            yield inbox.processFreeBusyCalendar(request.path, False)
+            yield inbox.processFreeBusyCalendar(destination_uri, (yield destination.isCalendarOpaque()))
             
             # Adjust the default calendar setting if necessary
             if defaultCalendar:
@@ -577,7 +590,7 @@
     @inlineCallbacks
     def isCalendarOpaque(self):
         
-        assert self.isCalendarCollection()
+        assert (yield self.isCalendarCollection())
         
         if (yield self.hasDeadProperty((caldav_namespace, "schedule-calendar-transp"))):
             property = (yield self.readDeadProperty((caldav_namespace, "schedule-calendar-transp")))
@@ -588,7 +601,7 @@
     @inlineCallbacks
     def isDefaultCalendar(self, request):
         
-        assert self.isCalendarCollection()
+        assert (yield self.isCalendarCollection())
         
         # Not allowed to delete the default calendar
         principal = (yield self.ownerPrincipal(request))
@@ -707,7 +720,7 @@
         """
 
         # Do this only for regular calendar collections and Inbox/Outbox
-        if self.isPseudoCalendarCollection():
+        if (yield self.isPseudoCalendarCollection()):
             edited_aces = []
             for ace in newaces:
                 if TwistedACLInheritable() not in ace.children:
@@ -757,13 +770,13 @@
         """
         Quota root only ever set on calendar homes.
         """
-        return False
+        return succeed(False)
     
     def quotaRoot(self, request):
         """
         Quota root only ever set on calendar homes.
         """
-        return None
+        return succeed(None)
 
 class CalendarPrincipalCollectionResource (DAVPrincipalCollectionResource, CalDAVResource):
     """
@@ -775,10 +788,10 @@
         return True
 
     def isCalendarCollection(self):
-        return False
+        return succeed(False)
 
     def isPseudoCalendarCollection(self):
-        return False
+        return succeed(False)
 
     def principalForCalendarUserAddress(self, address):
         return None
@@ -855,25 +868,25 @@
 
         if namespace == caldav_namespace:
             if name == "calendar-home-set":
-                urls = yield self.calendarHomeURLs()
+                urls = (yield self.calendarHomeURLs())
                 returnValue(caldavxml.CalendarHomeSet(
                     *[davxml.HRef(url) for url in urls]
                 ))
 
             elif name == "calendar-user-address-set":
                 returnValue(caldavxml.CalendarUserAddressSet(
-                    *[davxml.HRef(uri) for uri in self.calendarUserAddresses()]
+                    *[davxml.HRef(uri) for uri in (yield self.calendarUserAddresses())]
                 ))
 
             elif name == "schedule-inbox-URL":
-                url = yield self.scheduleInboxURL()
+                url = (yield self.scheduleInboxURL())
                 if url is None:
                     returnValue(None)
                 else:
                     returnValue(caldavxml.ScheduleInboxURL(davxml.HRef(url)))
 
             elif name == "schedule-outbox-URL":
-                url = yield self.scheduleOutboxURL()
+                url = (yield self.scheduleOutboxURL())
                 if url is None:
                     returnValue(None)
                 else:
@@ -884,7 +897,7 @@
 
         elif namespace == calendarserver_namespace:
             if name == "dropbox-home-URL" and config.EnableDropBox:
-                url = yield self.dropboxURL()
+                url = (yield self.dropboxURL())
                 if url is None:
                     returnValue(None)
                 else:
@@ -1004,7 +1017,7 @@
         """
         Quota root only ever set on calendar homes.
         """
-        return False
+        return succeed(False)
     
     def quotaRoot(self, request):
         """
@@ -1049,7 +1062,7 @@
     try:
         resource = ICalDAVResource(resource)
     except TypeError:
-        return False
+        return succeed(False)
     else:
         return resource.isCalendarCollection()
 
@@ -1057,7 +1070,7 @@
     try:
         resource = ICalDAVResource(resource)
     except TypeError:
-        return False
+        return succeed(False)
     else:
         return resource.isPseudoCalendarCollection()
 

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/schedule.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/schedule.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/schedule.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -26,7 +26,7 @@
 
 from twext.web2.dav.davxml import ErrorResponse
 
-from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 from twisted.web2 import responsecode
 from twisted.web2.dav import davxml
 from twisted.web2.dav.util import joinURL, normalizeURL
@@ -63,10 +63,10 @@
         return True
 
     def isCalendarCollection(self):
-        return False
+        return succeed(False)
 
     def isPseudoCalendarCollection(self):
-        return True
+        return succeed(True)
 
     def supportedReports(self):
         result = super(CalDAVResource, self).supportedReports()
@@ -88,7 +88,7 @@
     )
 
     def resourceType(self):
-        return davxml.ResourceType.scheduleInbox
+        return succeed(davxml.ResourceType.scheduleInbox)
 
     def defaultAccessControlList(self):
         
@@ -115,18 +115,18 @@
 
         if qname == (caldav_namespace, "calendar-free-busy-set"):
             # Always return at least an empty list
-            if not self.hasDeadProperty(property):
+            if not (yield self.hasDeadProperty(property)):
                 returnValue(caldavxml.CalendarFreeBusySet())
         elif qname == (caldav_namespace, "schedule-default-calendar-URL"):
             # Must have a valid default
             try:
-                defaultCalendarProperty = self.readDeadProperty(property)
+                defaultCalendarProperty = (yield self.readDeadProperty(property))
             except HTTPError:
                 defaultCalendarProperty = None
             if defaultCalendarProperty and len(defaultCalendarProperty.children) == 1:
                 defaultCalendar = str(defaultCalendarProperty.children[0])
                 cal = (yield request.locateResource(str(defaultCalendar)))
-                if cal is not None and cal.exists() and isCalendarCollectionResource(cal):
+                if cal is not None and cal.exists() and (yield isCalendarCollectionResource(cal)):
                     returnValue(defaultCalendarProperty) 
             
             # Default is not valid - we have to try to pick one
@@ -157,14 +157,14 @@
             # whether existing items in the property are still valid - only new ones.
             property.children = [davxml.HRef(normalizeURL(str(href))) for href in property.children]
             new_calendars = set([str(href) for href in property.children])
-            if not self.hasDeadProperty(property):
+            if not (yield self.hasDeadProperty(property)):
                 old_calendars = set()
             else:
-                old_calendars = set([str(href) for href in self.readDeadProperty(property).children])
+                old_calendars = set([str(href) for href in (yield self.readDeadProperty(property)).children])
             added_calendars = new_calendars.difference(old_calendars)
             for href in added_calendars:
                 cal = (yield request.locateResource(str(href)))
-                if cal is None or not cal.exists() or not isCalendarCollectionResource(cal):
+                if cal is None or not cal.exists() or not (yield isCalendarCollectionResource(cal)):
                     # Validate that href's point to a valid calendar.
                     raise HTTPError(ErrorResponse(
                         responsecode.CONFLICT,
@@ -180,7 +180,7 @@
                 calURI = str(new_calendar[0])
                 cal = (yield request.locateResource(str(new_calendar[0])))
             # TODO: check that owner of the new calendar is the same as owner of this inbox
-            if cal is None or not cal.exists() or not isCalendarCollectionResource(cal):
+            if cal is None or not cal.exists() or not (yield isCalendarCollectionResource(cal)):
                 # Validate that href's point to a valid calendar.
                 raise HTTPError(ErrorResponse(
                     responsecode.CONFLICT,
@@ -193,21 +193,22 @@
 
         yield super(ScheduleInboxResource, self).writeProperty(property, request)
 
+    @inlineCallbacks
     def processFreeBusyCalendar(self, uri, addit):
         uri = normalizeURL(uri)
 
-        if not self.hasDeadProperty((caldav_namespace, "calendar-free-busy-set")):
+        if not (yield self.hasDeadProperty((caldav_namespace, "calendar-free-busy-set"))):
             fbset = set()
         else:
-            fbset = set([normalizeURL(str(href)) for href in self.readDeadProperty((caldav_namespace, "calendar-free-busy-set")).children])
+            fbset = set([normalizeURL(str(href)) for href in (yield self.readDeadProperty((caldav_namespace, "calendar-free-busy-set"))).children])
         if addit:
             if uri not in fbset:
                 fbset.add(uri)
-                self.writeDeadProperty(caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in fbset]))
+                yield self.writeDeadProperty(caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in fbset]))
         else:
             if uri in fbset:
                 fbset.remove(uri)
-                self.writeDeadProperty(caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in fbset]))
+                yield self.writeDeadProperty(caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in fbset]))
 
     @inlineCallbacks
     def pickNewDefaultCalendar(self, request):
@@ -222,7 +223,7 @@
         if defaultCalendar is None or not defaultCalendar.exists():
             self.parent.provisionDefaultCalendars()
         else:
-            self.writeDeadProperty(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(defaultCalendarURL)))
+            yield self.writeDeadProperty(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(defaultCalendarURL)))
         returnValue(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(defaultCalendarURL)))
 
 class ScheduleOutboxResource (CalendarSchedulingCollectionResource):
@@ -254,7 +255,7 @@
             return super(ScheduleOutboxResource, self).defaultAccessControlList()
 
     def resourceType(self):
-        return davxml.ResourceType.scheduleOutbox
+        return succeed(davxml.ResourceType.scheduleOutbox)
 
     @inlineCallbacks
     def http_POST(self, request):
@@ -311,16 +312,16 @@
         )
 
     def resourceType(self):
-        return davxml.ResourceType.ischeduleinbox
+        return succeed(davxml.ResourceType.ischeduleinbox)
 
     def isCollection(self):
         return False
 
     def isCalendarCollection(self):
-        return False
+        return succeed(False)
 
     def isPseudoCalendarCollection(self):
-        return False
+        return succeed(False)
 
     def render(self, request):
         output = """<html>

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/caldav.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/caldav.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/caldav.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -177,14 +177,14 @@
                 responses.add(recipient.cuaddr, responsecode.OK, reqstatus=iTIPRequestStatus.MESSAGE_DELIVERED)
     
                 # Store CALDAV:originator property
-                child.writeDeadProperty(caldavxml.Originator(davxml.HRef(self.scheduler.originator.cuaddr)))
+                yield child.writeDeadProperty(caldavxml.Originator(davxml.HRef(self.scheduler.originator.cuaddr)))
             
                 # Store CALDAV:recipient property
-                child.writeDeadProperty(caldavxml.Recipient(davxml.HRef(recipient.cuaddr)))
+                yield child.writeDeadProperty(caldavxml.Recipient(davxml.HRef(recipient.cuaddr)))
             
                 # Store CS:schedule-changes property if present
                 if changes:
-                    child.writeDeadProperty(changes)
+                    yield child.writeDeadProperty(changes)
                     
                 returnValue(True)
     
@@ -192,7 +192,7 @@
     def generateFreeBusyResponse(self, recipient, responses, organizerProp, uid):
 
         # Extract the ATTENDEE property matching current recipient from the calendar data
-        cuas = recipient.principal.calendarUserAddresses()
+        cuas = (yield recipient.principal.calendarUserAddresses())
         attendeeProp = self.scheduler.calendar.getAttendeeProperty(cuas)
 
         remote = isinstance(self.scheduler.organizer, RemoteCalendarUser)
@@ -241,7 +241,7 @@
         matchtotal = 0
         for calendarResourceURL in fbset:
             calendarResource = (yield self.scheduler.request.locateResource(calendarResourceURL))
-            if calendarResource is None or not calendarResource.exists() or not isCalendarCollectionResource(calendarResource):
+            if calendarResource is None or not calendarResource.exists() or not (yield isCalendarCollectionResource(calendarResource)):
                 # We will ignore missing calendars. If the recipient has failed to
                 # properly manage the free busy set that should not prevent us from working.
                 continue

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/implicit.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/implicit.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/implicit.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -179,7 +179,7 @@
         
         if resource and resource.exists():
             try:
-                implicit = resource.readDeadProperty(TwistedSchedulingObjectResource)
+                implicit = (yield resource.readDeadProperty(TwistedSchedulingObjectResource))
             except HTTPError:
                 implicit = None
             if implicit is not None:
@@ -193,7 +193,7 @@
                     # We have different ORGANIZERs in the same iCalendar object - this is an error
                     returnValue(False)
                 organizerPrincipal = resource.principalForCalendarUserAddress(organizer) if organizer else None
-                resource.writeDeadProperty(TwistedSchedulingObjectResource("true" if organizerPrincipal != None else "false"))
+                yield resource.writeDeadProperty(TwistedSchedulingObjectResource("true" if organizerPrincipal != None else "false"))
                 log.debug("Implicit - checked scheduling object resource state for UID: '%s', result: %s" % (
                     calendar.resourceUID(),
                     "true" if organizerPrincipal != None else "false",
@@ -335,7 +335,7 @@
                 self.originatorPrincipal = (yield self.request.locateResource(originatorPrincipalURL))
                 if self.originatorPrincipal:
                     # Pick the first mailto cu address or the first other type
-                    for item in self.originatorPrincipal.calendarUserAddresses():
+                    for item in (yield self.originatorPrincipal.calendarUserAddresses()):
                         if not self.originator:
                             self.originator = item
                         if item.startswith("mailto:"):
@@ -667,7 +667,7 @@
         for attendee, rids in aggregated.iteritems():
             
             # Don't send message back to the ORGANIZER
-            if attendee in self.organizerPrincipal.calendarUserAddresses():
+            if attendee in (yield self.organizerPrincipal.calendarUserAddresses()):
                 continue
 
             # Generate an iTIP CANCEL message for this attendee, cancelling
@@ -705,7 +705,7 @@
         for attendee in self.attendees:
 
             # Don't send message back to the ORGANIZER
-            if attendee in self.organizerPrincipal.calendarUserAddresses():
+            if attendee in (yield self.organizerPrincipal.calendarUserAddresses()):
                 continue
 
             # Don't send message to specified attendees

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/processing.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/processing.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/processing.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -508,7 +508,7 @@
         all_declined = not any(instance_states.itervalues())
 
         # Do the simple case of all accepted or decline separately
-        cuas = self.recipient.principal.calendarUserAddresses()
+        cuas = (yield self.recipient.principal.calendarUserAddresses())
         if all_accepted or all_declined:
             # Extract the ATTENDEE property matching current recipient from the calendar data
             attendeeProps = calendar.getAttendeeProperties(cuas)

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/scheduler.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/scheduler.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/scheduling/scheduler.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -164,7 +164,7 @@
                 originatorPrincipal = (yield self.request.locateResource(originatorPrincipalURL))
                 if originatorPrincipal:
                     # Pick the first mailto cu address or the first other type
-                    for item in originatorPrincipal.calendarUserAddresses():
+                    for item in (yield originatorPrincipal.calendarUserAddresses()):
                         if not originator:
                             originator = item
                         if item.startswith("mailto:"):

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/static.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/static.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -97,7 +97,8 @@
         return succeed(cls(path, *args, **kwargs))
 
     def __repr__(self):
-        if self.isCalendarCollection():
+        # MOR: I don't think we can defer __repr__ even though isCalendarCollection( ) now is
+        if False and self.isCalendarCollection():
             return "<%s (calendar collection): %s>" % (self.__class__.__name__, self.fp.path)
         else:
             return super(CalDAVFile, self).__repr__()
@@ -169,11 +170,12 @@
     # CalDAV
     ##
 
+    @inlineCallbacks
     def resourceType(self):
-        if self.isCalendarCollection():
-            return davxml.ResourceType.calendar
+        if (yield self.isCalendarCollection()):
+            returnValue(davxml.ResourceType.calendar)
         else:
-            return super(CalDAVFile, self).resourceType()
+            returnValue((yield super(CalDAVFile, self).resourceType()))
 
     def createCalendar(self, request):
         #
@@ -254,7 +256,7 @@
 
     @inlineCallbacks
     def iCalendarRolledup(self, request):
-        if self.isPseudoCalendarCollection():
+        if (yield self.isPseudoCalendarCollection()):
             # Generate a monolithic calendar
             calendar = iComponent("VCALENDAR")
             calendar.addProperty(iProperty("VERSION", "2.0"))
@@ -319,19 +321,20 @@
                 returnValue(el.calendarData())
         returnValue((yield self.iCalendarText()))
 
+    @inlineCallbacks
     def iCalendarText(self, name=None):
-        if self.isPseudoCalendarCollection():
+        if (yield self.isPseudoCalendarCollection()):
             if name is None:
-                return self.iCalendar().addCallback(str)
+                returnValue(self.iCalendar().addCallback(str))
 
             try:
                 calendar_file = self.fp.child(name).open()
             except IOError, e:
-                if e[0] == errno.ENOENT: return None
+                if e[0] == errno.ENOENT: returnValue(None)
                 raise
 
         elif self.isCollection():
-            return succeed(None)
+            returnValue(None)
 
         else:
             if name is not None:
@@ -345,28 +348,23 @@
         finally:
             calendar_file.close()
 
-        return succeed(calendar_data)
+        returnValue(calendar_data)
 
     def iCalendarXML(self, name=None):
         return self.iCalendarText(name).addCallback(caldavxml.CalendarData.fromCalendar)
 
+    @inlineCallbacks
     def supportedPrivileges(self, request):
         # read-free-busy support on calendar collection and calendar object resources
-        if self.isCollection():
-            return succeed(calendarPrivilegeSet)
+        if (yield self.isCollection()):
+            returnValue(calendarPrivilegeSet)
         else:
-            def gotParent(parent):
-                if parent and isCalendarCollectionResource(parent):
-                    return succeed(calendarPrivilegeSet)
-                else:
-                    return super(CalDAVFile, self).supportedPrivileges(request)
+            parent = (yield self.locateParent(request, request.urlForResource(self)))
+            if parent and (yield isCalendarCollectionResource(parent)):
+                returnValue(calendarPrivilegeSet)
+            else:
+                returnValue((yield super(CalDAVFile, self).supportedPrivileges(request)))
 
-            d = self.locateParent(request, request.urlForResource(self))
-            d.addCallback(gotParent)
-            return d
-
-        return super(CalDAVFile, self).supportedPrivileges(request)
-
     ##
     # Public additions
     ##
@@ -399,34 +397,42 @@
             return succeed(self)
 
         d = maybeDeferred(super(CalDAVFile, self).createSimilarFile, path)
+
         def _gotFile(similar):
-            if isCalendarCollectionResource(self):
-                #
-                # Override DELETE, MOVE
-                #
-                for method in ("DELETE", "MOVE"):
-                    method = "http_" + method
-                    original = getattr(similar, method)
 
-                    @inlineCallbacks
-                    def override(request, original=original):
+            def _isCalCollection(result):
+                if result:
+                    #
+                    # Override DELETE, MOVE
+                    #
+                    for method in ("DELETE", "MOVE"):
+                        method = "http_" + method
+                        original = getattr(similar, method)
 
-                        # Call original method (which is deferred)
-                        response = (yield original(request))
+                        @inlineCallbacks
+                        def override(request, original=original):
 
-                        # Wipe the cache
-                        yield similar.deadProperties().flushCache()
+                            # Call original method (which is deferred)
+                            response = (yield original(request))
 
-                        returnValue(response)
+                            # Wipe the cache
+                            yield similar.deadProperties().flushCache()
 
-                    setattr(similar, method, override)
+                            returnValue(response)
 
-            return similar
+                        setattr(similar, method, override)
+
+                return similar
+
+            d = isCalendarCollectionResource(self)
+            d.addCallback(_isCalCollection)
+            return d
+
         return d.addCallback(_gotFile)
 
     @inlineCallbacks
     def updateCTag(self):
-        assert self.isCollection()
+        assert (yield self.isCollection())
         try:
             yield self.writeDeadProperty(customxml.GETCTag(
                     str(datetime.datetime.now())))
@@ -441,7 +447,7 @@
                       % (self,))
 
         if hasattr(self, 'cacheNotifier'):
-            returnValue(self.cacheNotifier.changed())
+            returnValue((yield self.cacheNotifier.changed()))
         else:
             log.debug("%r does not have a cacheNotifier but the CTag changed"
                       % (self,))
@@ -544,32 +550,35 @@
 
             parent = yield request.locateResource(parent_uri)
 
-            if test(parent):
+            if (yield test(parent)):
                 returnValue(parent)
 
 class AutoProvisioningFileMixIn (AutoProvisioningResourceMixIn):
+
     def provision(self):
+        # MOR: Double check this:
         d = self.provisionFile()
-        super(AutoProvisioningFileMixIn, self).provision()
+        d.addCallback(super(AutoProvisioningFileMixIn, self).provision)
         return d
 
+    @inlineCallbacks
     def provisionFile(self, request=None):
         if hasattr(self, "_provisioned_file"):
-            return succeed(False)
+            returnValue(False)
         else:
             self._provisioned_file = True
 
         fp = self.fp
         fp.restat(False)
         if fp.exists():
-            return succeed(False)
+            returnValue(False)
 
         log.msg("Provisioning file: %s" % (self,))
 
         if hasattr(self, "parent"):
             parent = self.parent
             if not parent.exists() and isinstance(parent, AutoProvisioningFileMixIn):
-                parent.provision()
+                yield parent.provision()
 
             assert parent.exists(), "Parent %s of %s does not exist" % (parent, self)
             assert parent.isCollection(), "Parent %s of %s is not a collection" % (parent, self)
@@ -587,7 +596,7 @@
             fp.open("w").close()
             fp.restat(False)
 
-        return succeed(True)
+        returnValue(True)
 
 class CalendarHomeProvisioningFile (AutoProvisioningFileMixIn, DirectoryCalendarHomeProvisioningResource, DAVFile):
     """
@@ -633,70 +642,53 @@
         else:
             self.homeResourceClass = homeResourceClass
 
+    @inlineCallbacks
     def provisionChild(self, name):
         record = self.directory.recordWithUID(name)
 
         if record is None:
             log.msg("No directory record with GUID %r" % (name,))
-            return None
+            returnValue(None)
 
         if not record.enabledForCalendaring:
             log.msg("Directory record %r is not enabled for calendaring" % (record,))
-            return None
+            returnValue(None)
 
         assert len(name) > 4, "Directory record has an invalid GUID: %r" % (name,)
         
         childPath = self.fp.child(name[0:2]).child(name[2:4]).child(name)
-        d = self.homeResourceClass.fetch(None, childPath.path, self, record)
-        def _gotChild(child):
-            if not child.exists():
-                self.provision()
+        child = (yield self.homeResourceClass.fetch(None, childPath.path, self, record))
+        if not child.exists():
+            yield self.provision()
 
-                if not childPath.parent().isdir():
-                    childPath.parent().makedirs()
+            if not childPath.parent().isdir():
+                childPath.parent().makedirs()
 
-                for oldPath in (
-                    # Pre 2.0: All in one directory
-                    self.fp.child(name),
-                    # Pre 1.2: In types hierarchy instead of the GUID hierarchy
-                    self.parent.getChild(record.recordType).fp.child(record.shortNames[0]),
-                ):
-                    if oldPath.exists():
-                        # The child exists at an old location.  Move to new location.
-                        log.msg("Moving calendar home from old location %r to new location %r." % (oldPath, childPath))
-                        try:
-                            oldPath.moveTo(childPath)
-                        except (OSError, IOError), e:
-                            log.err("Error moving calendar home %r: %s" % (oldPath, e))
-                            raise HTTPError(StatusResponse(
-                                responsecode.INTERNAL_SERVER_ERROR,
-                                "Unable to move calendar home."
-                            ))
-                        child.fp.restat(False)
-                        break
-                else:
-                    #
-                    # NOTE: provisionDefaultCalendars() returns a deferred, which we are ignoring.
-                    # The result being that the default calendars will be present at some point
-                    # in the future, not necessarily right now, and we don't have a way to wait
-                    # on that to finish.
-                    #
-                    child.provisionDefaultCalendars()
-
-                    #
-                    # Try to work around the above a little by telling the client that something
-                    # when wrong temporarily if the child isn't provisioned right away.
-                    #
-                    if not child.exists():
+            for oldPath in (
+                # Pre 2.0: All in one directory
+                self.fp.child(name),
+                # Pre 1.2: In types hierarchy instead of the GUID hierarchy
+                (yield self.parent.getChild(record.recordType).fp.child(record.shortNames[0])),
+            ):
+                if oldPath.exists():
+                    # The child exists at an old location.  Move to new location.
+                    log.msg("Moving calendar home from old location %r to new location %r." % (oldPath, childPath))
+                    try:
+                        oldPath.moveTo(childPath)
+                    except (OSError, IOError), e:
+                        log.err("Error moving calendar home %r: %s" % (oldPath, e))
                         raise HTTPError(StatusResponse(
-                            responsecode.SERVICE_UNAVAILABLE,
-                            "Provisioning calendar home."
+                            responsecode.INTERNAL_SERVER_ERROR,
+                            "Unable to move calendar home."
                         ))
+                    child.fp.restat(False)
+                    break
+            else:
+                yield child.provisionDefaultCalendars()
 
-                assert child.exists()
+            assert child.exists()
 
-            return child
-        return d.addCallback(_gotChild)
+        returnValue(child)
 
     def createSimilarFile(self, path):
         raise HTTPError(responsecode.NOT_FOUND)
@@ -765,7 +757,7 @@
     def getChild(self, name):
         # This avoids finding case variants of put children on case-insensitive filesystems.
         if name not in self.putChildren and name.lower() in (x.lower() for x in self.putChildren):
-            return None
+            returnValue(None)
 
         return super(CalendarHomeFile, self).getChild(name)
 
@@ -832,9 +824,9 @@
 
     def createSimilarFile(self, path):
         if path == self.fp.path:
-            return self
+            return succeed(self)
         else:
-            return CalDAVFile(path, principalCollections=self.principalCollections())
+            return succeed(CalDAVFile(path, principalCollections=self.principalCollections()))
 
     def index(self):
         """
@@ -864,16 +856,17 @@
         ScheduleFile.__init__(self, path, parent)
         ScheduleInboxResource.__init__(self, parent)
 
+    @inlineCallbacks
     def provision(self):
-        if self.provisionFile():
+        if (yield self.provisionFile()):
 
             # Initialize CTag on the calendar collection
-            self.updateCTag()
+            yield self.updateCTag()
 
             # Initialize the index
             self.index().create()
 
-        return super(ScheduleInboxFile, self).provision()
+        returnValue((yield super(ScheduleInboxFile, self).provision()))
 
     def __repr__(self):
         return "<%s (calendar inbox collection): %s>" % (self.__class__.__name__, self.fp.path)
@@ -894,12 +887,13 @@
         ScheduleFile.__init__(self, path, parent)
         ScheduleOutboxResource.__init__(self, parent)
 
+    @inlineCallbacks
     def provision(self):
-        if self.provisionFile():
+        if (yield self.provisionFile()):
             # Initialize CTag on the calendar collection
-            self.updateCTag()
+            yield self.updateCTag()
 
-        return super(ScheduleOutboxFile, self).provision()
+        returnValue((yield super(ScheduleOutboxFile, self).provision()))
 
     def __repr__(self):
         return "<%s (calendar outbox collection): %s>" % (self.__class__.__name__, self.fp.path)
@@ -928,9 +922,9 @@
 
     def createSimilarFile(self, path):
         if path == self.fp.path:
-            return self
+            return succeed(self)
         else:
-            return responsecode.NOT_FOUND
+            return succeed(responsecode.NOT_FOUND)
 
     def http_PUT        (self, request): return responsecode.FORBIDDEN
     def http_COPY       (self, request): return responsecode.FORBIDDEN
@@ -980,9 +974,9 @@
 
     def createSimilarFile(self, path):
         if path == self.fp.path:
-            return self
+            return succeed(self)
         else:
-            return responsecode.NOT_FOUND
+            return succeed(responsecode.NOT_FOUND)
 
     def http_PUT        (self, request): return responsecode.FORBIDDEN
     def http_COPY       (self, request): return responsecode.FORBIDDEN
@@ -1011,9 +1005,9 @@
 
     def createSimilarFile(self, path):
         if path == self.fp.path:
-            return self
+            return succeed(self)
         else:
-            return DropBoxCollectionFile(path, self)
+            return succeed(DropBoxCollectionFile(path, self))
 
     def __repr__(self):
         return "<%s (dropbox home collection): %s>" % (self.__class__.__name__, self.fp.path)
@@ -1025,9 +1019,9 @@
 
     def createSimilarFile(self, path):
         if path == self.fp.path:
-            return self
+            return succeed(self)
         else:
-            return DropBoxChildFile(path, self)
+            return succeed(DropBoxChildFile(path, self))
 
     def __repr__(self):
         return "<%s (dropbox collection): %s>" % (self.__class__.__name__, self.fp.path)
@@ -1040,9 +1034,9 @@
 
     def createSimilarFile(self, path):
         if path == self.fp.path:
-            return self
+            return succeed(self)
         else:
-            return responsecode.NOT_FOUND
+            return succeed(responsecode.NOT_FOUND)
 
 class TimezoneServiceFile (TimezoneServiceResource, CalDAVFile):
     def __init__(self, path, parent):
@@ -1053,9 +1047,9 @@
 
     def createSimilarFile(self, path):
         if path == self.fp.path:
-            return self
+            return succeed(self)
         else:
-            return responsecode.NOT_FOUND
+            return succeed(responsecode.NOT_FOUND)
 
     def http_PUT        (self, request): return responsecode.FORBIDDEN
     def http_COPY       (self, request): return responsecode.FORBIDDEN

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_index.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_index.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_index.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -16,6 +16,7 @@
 
 from twisted.internet import reactor
 from twisted.internet.task import deferLater
+from twisted.internet.defer import succeed
 
 from twistedcaldav.ical import Component
 from twistedcaldav.index import Index, default_future_expansion_duration,\
@@ -40,7 +41,7 @@
 
     def setUp(self):
         super(SQLIndexTests, self).setUp()
-        self.site.resource.isCalendarCollection = lambda: True
+        self.site.resource.isCalendarCollection = lambda: succeed(True)
         self.db = Index(self.site.resource)
 
 

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_resource.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_resource.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/test/test_resource.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -15,6 +15,7 @@
 ##
 
 from twistedcaldav.resource import CalDAVResource
+from twisted.internet.defer import inlineCallbacks
 
 from twistedcaldav.test.util import InMemoryPropertyStore
 from twistedcaldav.test.util import TestCase

Modified: CalendarServer/branches/more-deferreds-3/twistedcaldav/timezoneservice.py
===================================================================
--- CalendarServer/branches/more-deferreds-3/twistedcaldav/timezoneservice.py	2009-08-27 19:42:37 UTC (rev 4512)
+++ CalendarServer/branches/more-deferreds-3/twistedcaldav/timezoneservice.py	2009-08-28 20:49:31 UTC (rev 4513)
@@ -24,6 +24,7 @@
 
 from twext.web2.dav.davxml import ErrorResponse
 
+from twisted.internet.defer import succeed
 from twisted.web2 import responsecode
 from twisted.web2.dav import davxml
 from twisted.web2.http import HTTPError
@@ -73,16 +74,16 @@
         )
 
     def resourceType(self):
-        return davxml.ResourceType.timezones
+        return succeed(davxml.ResourceType.timezones)
 
     def isCollection(self):
         return False
 
     def isCalendarCollection(self):
-        return False
+        return succeed(False)
 
     def isPseudoCalendarCollection(self):
-        return False
+        return succeed(False)
 
     def render(self, request):
         output = """<html>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090828/ccbc31ff/attachment-0001.html>


More information about the calendarserver-changes mailing list