[CalendarServer-changes] [6278] CalendarServer/trunk/txdav

source_changes at macosforge.org source_changes at macosforge.org
Fri Sep 10 15:49:37 PDT 2010


Revision: 6278
          http://trac.macosforge.org/projects/calendarserver/changeset/6278
Author:   glyph at apple.com
Date:     2010-09-10 15:49:37 -0700 (Fri, 10 Sep 2010)
Log Message:
-----------
attachment upgrading

Modified Paths:
--------------
    CalendarServer/trunk/txdav/caldav/datastore/util.py
    CalendarServer/trunk/txdav/common/datastore/test/test_util.py

Modified: CalendarServer/trunk/txdav/caldav/datastore/util.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/util.py	2010-09-10 22:48:37 UTC (rev 6277)
+++ CalendarServer/trunk/txdav/caldav/datastore/util.py	2010-09-10 22:49:37 UTC (rev 6278)
@@ -13,10 +13,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
+
 """
 Utility logic common to multiple backend implementations.
 """
 
+from twisted.internet.defer import inlineCallbacks, Deferred
+from twisted.internet.protocol import Protocol
+
 from twext.python.vcomponent import InvalidICalendarDataError
 from twext.python.vcomponent import VComponent
 
@@ -90,6 +94,7 @@
     return calendarObject.uid() + ".dropbox"
 
 
+ at inlineCallbacks
 def _migrateCalendar(inCalendar, outCalendar, getComponent):
     """
     Copy all calendar objects and properties in the given input calendar to the
@@ -98,6 +103,8 @@
     @param inCalendar: the L{ICalendar} to retrieve calendar objects from.
     @param outCalendar: the L{ICalendar} to store calendar objects to.
     @param getComponent: a 1-argument callable; see L{migrateHome}.
+
+    @return: a L{Deferred} which fires when the calendar has migrated.
     """
     outCalendar.properties().update(inCalendar.properties())
     for calendarObject in inCalendar.calendarObjects():
@@ -107,12 +114,40 @@
 
         # Only the owner's properties are migrated, since previous releases of
         # calendar server didn't have per-user properties.
-        outCalendar.calendarObjectWithName(
-            calendarObject.name()).properties().update(
-                calendarObject.properties())
-        # XXX attachments
+        outObject = outCalendar.calendarObjectWithName(
+            calendarObject.name())
+        outObject.properties().update(calendarObject.properties())
 
+        # Migrate attachments.
+        for attachment in calendarObject.attachments():
+            name = attachment.name()
+            ctype = attachment.contentType()
+            transport = outObject.createAttachmentWithName(name, ctype)
+            proto =_AttachmentMigrationProto(transport)
+            attachment.retrieve(proto)
+            yield proto.done
 
+
+
+class _AttachmentMigrationProto(Protocol, object):
+    def __init__(self, storeTransport):
+        self.storeTransport = storeTransport
+        self.done = Deferred()
+
+    def dataReceived(self, data):
+        self.storeTransport.write(data)
+
+    def connectionLost(self, reason):
+        try:
+            self.storeTransport.loseConnection()
+        except:
+            self.done.errback()
+        else:
+            self.done.callback(None)
+
+
+
+ at inlineCallbacks
 def migrateHome(inHome, outHome, getComponent=lambda x: x.component()):
     """
     Copy all calendars and properties in the given input calendar to the given
@@ -135,7 +170,7 @@
         name = calendar.name()
         outHome.createCalendarWithName(name)
         outCalendar = outHome.calendarWithName(name)
-        _migrateCalendar(calendar, outCalendar, getComponent)
+        yield _migrateCalendar(calendar, outCalendar, getComponent)
     # No migration for notifications, since they weren't present in earlier
     # released versions of CalendarServer.
 

Modified: CalendarServer/trunk/txdav/common/datastore/test/test_util.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/test/test_util.py	2010-09-10 22:48:37 UTC (rev 6277)
+++ CalendarServer/trunk/txdav/common/datastore/test/test_util.py	2010-09-10 22:49:37 UTC (rev 6278)
@@ -18,8 +18,10 @@
 Tests for L{txdav.common.datastore.util}.
 """
 
+from twisted.internet.protocol import Protocol
 from twisted.trial.unittest import TestCase
 from twext.python.filepath import CachingFilePath
+from twext.web2.http_headers import MimeType
 
 from twisted.application.service import Service, MultiService
 from txdav.common.datastore.util import UpgradeToDatabaseService
@@ -27,7 +29,7 @@
 from txdav.common.datastore.test.util import theStoreBuilder, \
     populateCalendarsFrom
 from txdav.caldav.datastore.test.common import StubNotifierFactory, CommonTests
-from twisted.internet.defer import inlineCallbacks
+from twisted.internet.defer import inlineCallbacks, Deferred
 
 
 class HomeMigrationTests(TestCase):
@@ -43,13 +45,18 @@
         # Add some files to the file store.
         self.filesPath = CachingFilePath(self.mktemp())
         self.filesPath.createDirectory()
-        fileStore = CommonDataStore(
+        fileStore = self.fileStore = CommonDataStore(
             self.filesPath, StubNotifierFactory(), True, True
         )
         self.sqlStore = yield theStoreBuilder.buildStore(
             self, StubNotifierFactory()
         )
-        self.stubService = Service()
+        subStarted = self.subStarted = Deferred()
+        class StubService(Service, object):
+            def startService(self):
+                super(StubService, self).startService()
+                subStarted.callback(None)
+        self.stubService = StubService()
         self.topService = MultiService()
         self.upgrader = UpgradeToDatabaseService(
             fileStore, self.sqlStore, self.stubService
@@ -62,13 +69,14 @@
             ".some-extra-data").setContent("some extra data")
 
 
+    @inlineCallbacks
     def test_upgradeCalendarHomes(self):
         """
         L{UpgradeToDatabaseService.startService} will do the upgrade, then
         start its dependent service by adding it to its service hierarchy.
         """
         self.topService.startService()
-        # XXX asyncify for attachment migration
+        yield self.subStarted
         self.assertEquals(self.stubService.running, True)
         txn = self.sqlStore.newTransaction()
         self.addCleanup(txn.commit)
@@ -82,3 +90,49 @@
                 "some extra data"
         )
 
+
+    @inlineCallbacks
+    def test_upgradeAttachments(self):
+        """
+        L{UpgradeToDatabaseService.startService} upgrades calendar attachments
+        as well.
+        """
+        txn = self.fileStore.newTransaction()
+        committed = []
+        def maybeCommit():
+            if not committed:
+                committed.append(True)
+                txn.commit()
+        self.addCleanup(maybeCommit)
+        def getSampleObj():
+            return txn.calendarHomeWithUID("home1").calendarWithName(
+                "calendar_1").calendarObjectWithName("1.ics")
+        inObject = getSampleObj()
+        someAttachmentName = "some-attachment"
+        someAttachmentType = MimeType.fromString("application/x-custom-type")
+        transport = inObject.createAttachmentWithName(
+            someAttachmentName, someAttachmentType
+        )
+        someAttachmentData = "Here is some data for your attachment, enjoy."
+        transport.write(someAttachmentData)
+        transport.loseConnection()
+        maybeCommit()
+        self.topService.startService()
+        yield self.subStarted
+        committed = []
+        txn = self.sqlStore.newTransaction()
+        outObject = getSampleObj()
+        outAttachment = outObject.attachmentWithName(someAttachmentName)
+        allDone = Deferred()
+        class SimpleProto(Protocol):
+            data = ''
+            def dataReceived(self, data):
+                self.data += data
+            def connectionLost(self, reason):
+                allDone.callback(self.data)
+        self.assertEquals(outAttachment.contentType(), someAttachmentType)
+        outAttachment.retrieve(SimpleProto())
+        allData = yield allDone
+        self.assertEquals(allData, someAttachmentData)
+
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100910/a4c8a34f/attachment-0001.html>


More information about the calendarserver-changes mailing list