[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