[CalendarServer-changes] [3709] CalendarServer/branches/users/sagen/migration-3686/twistedcaldav/ upgrade.py
source_changes at macosforge.org
source_changes at macosforge.org
Mon Feb 23 14:54:01 PST 2009
Revision: 3709
http://trac.macosforge.org/projects/calendarserver/changeset/3709
Author: sagen at apple.com
Date: 2009-02-23 14:54:01 -0800 (Mon, 23 Feb 2009)
Log Message:
-----------
Checkpoint of work in progress on migration branch
Modified Paths:
--------------
CalendarServer/branches/users/sagen/migration-3686/twistedcaldav/upgrade.py
Modified: CalendarServer/branches/users/sagen/migration-3686/twistedcaldav/upgrade.py
===================================================================
--- CalendarServer/branches/users/sagen/migration-3686/twistedcaldav/upgrade.py 2009-02-23 21:35:47 UTC (rev 3708)
+++ CalendarServer/branches/users/sagen/migration-3686/twistedcaldav/upgrade.py 2009-02-23 22:54:01 UTC (rev 3709)
@@ -17,14 +17,19 @@
from __future__ import with_statement
from twisted.web2.dav.fileop import rmdir
+from twisted.web2.dav import davxml
from twistedcaldav.directory.directory import DirectoryService
from twistedcaldav.directory.calendaruserproxy import CalendarUserProxyDatabase
from twistedcaldav.log import Logger
from twistedcaldav.ical import Component
from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
+from twistedcaldav import caldavxml
from calendarserver.tools.util import getDirectory, dummyDirectoryRecord
-import xattr, itertools, os
+import xattr, itertools, os, zlib
+from zlib import compress, decompress
+from cPickle import loads as unpickle, PicklingError, UnpicklingError
+
log = Logger()
@@ -81,19 +86,18 @@
return newData, not newData == data
- def upgradeCalendarCollection(oldCal, newCal, directory):
- os.mkdir(newCal)
+ def upgradeCalendarCollection(calPath, directory):
- for resource in os.listdir(oldCal):
+ for resource in os.listdir(calPath):
if resource.startswith("."):
continue
- oldRes = os.path.join(oldCal, resource)
- newRes = os.path.join(newCal, resource)
+ resPath = os.path.join(calPath, resource)
+ resPathTmp = "%s.tmp" % resPath
- log.info("Processing: %s" % (oldRes,))
- with open(oldRes) as res:
+ log.info("Processing: %s" % (resPath,))
+ with open(resPath) as res:
data = res.read()
try:
@@ -114,60 +118,37 @@
(oldRes, e))
raise
- with open(newRes, "w") as res:
+ # Write to a new file, then rename it over the old one
+ with open(resPathTmp, "w") as res:
res.write(data)
+ os.rename(resPathTmp, resPath)
- for attr, value in xattr.xattr(oldRes).iteritems():
- xattr.setxattr(newRes, attr, value)
- for attr, value in xattr.xattr(oldCal).iteritems():
- xattr.setxattr(newCal, attr, value)
+ # Remove the ctag xattr from the calendar collection
+ for attr, value in xattr.xattr(calPath).iteritems():
+ if attr == "WebDAV:{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag":
+ xattr.removexattr(calPath, attr, value)
- def upgradeCalendarHome(oldHome, newHome, directory):
- try:
- os.makedirs(newHome)
- for attr, value in xattr.xattr(oldHome).iteritems():
- xattr.setxattr(newHome, attr, value)
- except:
- log.info("Skipping upgrade of %s because %s already exists" %
- (oldHome, newHome))
- return
+ def upgradeCalendarHome(homePath, directory):
- log.info("Upgrading calendar home: %s -> %s" % (oldHome, newHome))
+ log.info("Upgrading calendar home: %s" % (homePath,))
- try:
- for cal in os.listdir(oldHome):
- oldCal = os.path.join(oldHome, cal)
- newCal = os.path.join(newHome, cal)
- log.info("Upgrading calendar: %s" % (newCal,))
- upgradeCalendarCollection(oldCal, newCal, directory)
+ for cal in os.listdir(homePath):
+ calPath = os.path.join(homePath, cal)
+ log.info("Upgrading calendar: %s" % (calPath,))
+ upgradeCalendarCollection(calPath, directory)
- # The migration for this calendar home was successful, so now
- # we can remove the original
- for cal in os.listdir(oldHome):
- calPath = os.path.join(oldHome, cal)
- for child in os.listdir(calPath):
- childPath = os.path.join(calPath, child)
- os.remove(childPath)
- os.rmdir(calPath)
- os.rmdir(oldHome)
+ # Change the calendar-free-busy-set xattrs of the inbox to the
+ # __uids__/<guid> form
+ if cal == "inbox":
+ for attr, value in xattr.xattr(calPath).iteritems():
+ if attr == "WebDAV:{urn:ietf:params:xml:ns:caldav}calendar-free-busy-set":
+ value = updateFreeBusySet(value, directory)
+ if value is not None:
+ # Need to write the xattr back to disk
+ xattr.setxattr(calPath, attr, value)
- except Exception, e:
- # A failure means that we are going to throw out everything we
- # did for this calendar home and leave the original intact
- log.error("Error while upgrading %s -> %s: %s. Leaving original intact." % (oldHome, newHome, str(e)))
- for cal in os.listdir(newHome):
- calPath = os.path.join(newHome, cal)
- for child in os.listdir(calPath):
- childPath = os.path.join(calPath, child)
- os.remove(childPath)
- os.rmdir(calPath)
- os.rmdir(newHome)
- raise UpgradeError(
- "Upgrade Error: unable to migrate calendar home %s -> %s: %s" %
- (oldHome, newHome, str(e))
- )
@@ -208,8 +189,17 @@
)
+ def moveCalendarHome(oldHome, newHome):
+ if os.path.exists(newHome):
+ # Both old and new homes exist; stop immediately to let the
+ # administrator fix it
+ raise UpgradeError(
+ "Upgrade Error: calendar home is in two places: %s and %s. Please remove one of them and restart calendar server."
+ % (oldHome, newHome)
+ )
+
directory = getDirectory()
docRoot = config.DocumentRoot
@@ -233,6 +223,8 @@
uidHomes = os.path.join(calRoot, "__uids__")
+ # Move calendar homes to new location:
+
if os.path.exists(uidHomes):
for home in os.listdir(uidHomes):
@@ -242,7 +234,7 @@
oldHome = os.path.join(uidHomes, home)
newHome = os.path.join(uidHomes, home[0:2], home[2:4], home)
- upgradeCalendarHome(oldHome, newHome, directory)
+ moveCalendarHome(oldHome, newHome)
else:
os.mkdir(uidHomes)
@@ -263,10 +255,21 @@
oldHome = os.path.join(dirPath, shortName)
newHome = os.path.join(uidHomes, uid[0:2], uid[2:4],
uid)
- upgradeCalendarHome(oldHome, newHome, directory)
+ moveCalendarHome(oldHome, newHome)
+ # Upgrade calendar homes in the new location:
+ for first in os.listdir(uidHomes):
+ if len(first) == 2:
+ firstPath = os.path.join(uidHomes, first)
+ for second in os.listdir(firstPath):
+ if len(second) == 2:
+ secondPath = os.path.join(firstPath, second)
+ for home in os.listdir(secondPath):
+ homePath = os.path.join(secondPath, home)
+ upgradeCalendarHome(homePath, directory)
+
# Each method in this array will upgrade from one version to the next;
# the index of each method within the array corresponds to the on-disk
# version number that it upgrades from. For example, if the on-disk
@@ -276,6 +279,7 @@
upgradeMethods = [
upgrade_to_1,
]
+# MOR: Change the above to an array of tuples
def upgradeData(config):
@@ -312,3 +316,64 @@
Generic upgrade error.
"""
pass
+
+
+#
+# Utility functions
+#
+def updateFreeBusyHref(href, directory):
+ pieces = href.split("/")
+ if pieces[2] == "__uids__":
+ # Already updated
+ return None
+
+ recordType = pieces[2]
+ shortName = pieces[3]
+ record = directory.recordWithShortName(recordType, shortName)
+ if record is None:
+ msg = "Can't update free-busy href; %s is not in the directory" % shortName
+ log.error(msg)
+ raise UpgradeError(msg)
+
+ uid = record.uid
+ newHref = "/calendars/__uids__/%s/%s/" % (uid, pieces[4])
+ return newHref
+
+
+def updateFreeBusySet(value, directory):
+
+ try:
+ value = zlib.decompress(value)
+ except zlib.error:
+ # Legacy data - not zlib compressed
+ pass
+
+ try:
+ doc = davxml.WebDAVDocument.fromString(value)
+ freeBusySet = doc.root_element
+ except ValueError:
+ try:
+ freeBusySet = unpickle(value)
+ except UnpicklingError:
+ log.err("Invalid xattr property value for: %s" % attr)
+ # MOR: continue on?
+ return
+
+ fbset = set()
+ didUpdate = False
+ for href in freeBusySet.children:
+ href = str(href)
+ newHref = updateFreeBusyHref(href, directory)
+ if newHref is None:
+ fbset.add(href)
+ else:
+ didUpdate = True
+ fbset.add(newHref)
+
+ if didUpdate:
+ property = caldavxml.CalendarFreeBusySet(*[davxml.HRef(href)
+ for href in fbset])
+ value = compress(property.toxml())
+ return value
+
+ return None # no update required
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090223/c8b5bdb9/attachment-0001.html>
More information about the calendarserver-changes
mailing list