[CalendarServer-changes] [5606] CalendarServer/branches/new-store/txcaldav/calendarstore
source_changes at macosforge.org
source_changes at macosforge.org
Fri May 14 21:55:37 PDT 2010
Revision: 5606
http://trac.macosforge.org/projects/calendarserver/changeset/5606
Author: glyph at apple.com
Date: 2010-05-14 21:55:35 -0700 (Fri, 14 May 2010)
Log Message:
-----------
Remove public attributes not present in the interface; add transactionality to calendar object removal.
Modified Paths:
--------------
CalendarServer/branches/new-store/txcaldav/calendarstore/file.py
CalendarServer/branches/new-store/txcaldav/calendarstore/test/test_file.py
Modified: CalendarServer/branches/new-store/txcaldav/calendarstore/file.py
===================================================================
--- CalendarServer/branches/new-store/txcaldav/calendarstore/file.py 2010-05-14 21:23:03 UTC (rev 5605)
+++ CalendarServer/branches/new-store/txcaldav/calendarstore/file.py 2010-05-15 04:55:35 UTC (rev 5606)
@@ -14,10 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##
-from twext.web2.dav.element.rfc2518 import ResourceType
-from txdav.propertystore.base import PropertyName
-from twistedcaldav.caldavxml import ScheduleCalendarTransp, Transparent
-
"""
File calendar store.
"""
@@ -29,7 +25,7 @@
"CalendarObject",
]
-import errno
+from errno import EEXIST, ENOENT
from zope.interface import implements
@@ -38,8 +34,10 @@
from twext.python.log import LoggingMixIn
from twext.python.vcomponent import VComponent
from twext.python.vcomponent import InvalidICalendarDataError
+from twext.web2.dav.element.rfc2518 import ResourceType
from txdav.propertystore.xattr import PropertyStore
+from txdav.propertystore.base import PropertyName
from txcaldav.icalendarstore import ICalendarStoreTransaction
from txcaldav.icalendarstore import ICalendarStore, ICalendarHome
@@ -48,12 +46,13 @@
from txcaldav.icalendarstore import CalendarObjectNameNotAllowedError
from txcaldav.icalendarstore import CalendarAlreadyExistsError
from txcaldav.icalendarstore import CalendarObjectNameAlreadyExistsError
-from txcaldav.icalendarstore import NotFoundError
from txcaldav.icalendarstore import NoSuchCalendarError
from txcaldav.icalendarstore import NoSuchCalendarObjectError
from txcaldav.icalendarstore import InvalidCalendarComponentError
from txcaldav.icalendarstore import InternalDataStoreError
+from twistedcaldav.caldavxml import ScheduleCalendarTransp, Transparent
+
from twistedcaldav.index import Index as OldIndex
from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
@@ -150,9 +149,8 @@
@type calendarStore: L{CalendarStore}
"""
- self.calendarStore = calendarStore
- self.aborted = False
- self.committed = False
+ self._calendarStore = calendarStore
+ self._termination = None
self._operations = []
self._calendarHomes = {}
@@ -160,18 +158,30 @@
def addOperation(self, operation):
self._operations.append(operation)
+
+ def _terminate(self, mode):
+ """
+ Check to see if this transaction has already been terminated somehow,
+ either via committing or aborting, and if not, note that it has been
+ terminated.
+
+ @param mode: The manner of the termination of this transaction.
+
+ @type mode: C{str}
+
+ @raise RuntimeError: This transaction has already been terminated.
+ """
+ if self._termination is not None:
+ raise RuntimeError("already %s" % (self._termination,))
+ self._termination = mode
+
+
def abort(self):
- if self.aborted:
- raise RuntimeError("already aborted")
- if self.committed:
- raise RuntimeError("already committed")
- self.aborted = True
+ self._terminate("aborted")
+
def commit(self):
- if self.aborted:
- raise RuntimeError("already aborted")
- if self.committed:
- raise RuntimeError("already committed")
+ self._terminate("committed")
self.committed = True
undos = []
@@ -189,6 +199,7 @@
self.log_error("Exception while undoing transaction: %s" % (e,))
raise
+
def calendarHomeWithUID(self, uid, create=False):
if (uid, self) in self._calendarHomes:
return self._calendarHomes[(uid, self)]
@@ -198,7 +209,7 @@
assert len(uid) >= 4
- childPath1 = self.calendarStore._path.child(uid[0:2])
+ childPath1 = self._calendarStore._path.child(uid[0:2])
childPath2 = childPath1.child(uid[2:4])
childPath3 = childPath2.child(uid)
@@ -207,7 +218,7 @@
try:
path.createDirectory()
except (IOError, OSError), e:
- if e.errno != errno.EEXIST:
+ if e.errno != EEXIST:
# Ignore, in case someone else created the
# directory while we were trying to as well.
raise
@@ -224,7 +235,7 @@
elif not childPath3.isdir():
return None
- calendarHome = CalendarHome(childPath3, self.calendarStore, self)
+ calendarHome = CalendarHome(childPath3, self._calendarStore, self)
self._calendarHomes[(uid, self)] = calendarHome
return calendarHome
@@ -234,22 +245,26 @@
implements(ICalendarHome)
def __init__(self, path, calendarStore, transaction):
+ self._calendarStore = calendarStore
self._path = path
- self.calendarStore = calendarStore
self._transaction = transaction
self._newCalendars = {}
self._removedCalendars = set()
+
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self._path)
+
def uid(self):
return self._path.basename()
-
-
+
+
def _updateSyncToken(self, reset=False):
"Stub for updating sync token."
+ # FIXME: actually update something
+
def calendars(self):
return set(self._newCalendars.itervalues()) | set(
self.calendarWithName(name)
@@ -292,7 +307,7 @@
# Return undo
return lambda: childPath.remove()
except (IOError, OSError), e:
- if e.errno == errno.EEXIST and childPath.isdir():
+ if e.errno == EEXIST and childPath.isdir():
raise CalendarAlreadyExistsError(name)
raise
@@ -332,7 +347,7 @@
try:
childPath.moveTo(trash)
except (IOError, OSError), e:
- if e.errno == errno.ENOENT:
+ if e.errno == ENOENT:
raise NoSuchCalendarError(name)
raise
@@ -365,7 +380,7 @@
def __init__(self, path, calendarHome):
self._path = path
- self.calendarHome = calendarHome
+ self._calendarHome = calendarHome
self._transaction = calendarHome._transaction
self._newCalendarObjects = {}
self._cachedCalendarObjects = {}
@@ -381,26 +396,19 @@
def ownerCalendarHome(self):
- return self.calendarHome
+ return self._calendarHome
-# def _calendarObjects_index(self):
-# return self.index().calendarObjects()
-#
-# def _calendarObjects_listdir(self):
-# return (
-# self.calendarObjectWithName(name)
-# for name in self.path.listdir()
-# if not name.startswith(".")
-# )
-
def calendarObjects(self):
- return (
+ return sorted((
self.calendarObjectWithName(name)
for name in (
set(self._newCalendarObjects.iterkeys()) |
- set(name for name in self._path.listdir() if not name.startswith("."))
- )
+ set(name for name in self._path.listdir()
+ if not name.startswith(".")) -
+ set(self._removedCalendarObjects)
+ )),
+ key=lambda calObj: calObj.name()
)
@@ -412,7 +420,6 @@
if name in self._cachedCalendarObjects:
return self._cachedCalendarObjects[name]
-
calendarObjectPath = self._path.child(name)
if calendarObjectPath.isfile():
obj = CalendarObject(calendarObjectPath, self)
@@ -430,6 +437,8 @@
continue
obj = CalendarObject(calendarObjectPath, self)
if obj.component().resourceUID() == uid:
+ if obj.name() in self._removedCalendarObjects:
+ return None
return obj
@@ -454,13 +463,18 @@
if calendarObjectPath.isfile():
self._removedCalendarObjects.add(name)
# FIXME: test for undo
- calendarObjectPath.remove()
+ def do():
+ calendarObjectPath.remove()
+ return lambda: None
+ self._transaction.addOperation(do)
else:
raise NoSuchCalendarObjectError(name)
+
def removeCalendarObjectWithUID(self, uid):
self.removeCalendarObjectWithName(self.calendarObjectWithUID(uid)._path.basename())
+
def syncToken(self):
raise NotImplementedError()
@@ -590,7 +604,7 @@
try:
fh = self._path.open()
except IOError, e:
- if e[0] == errno.ENOENT:
+ if e[0] == ENOENT:
raise NoSuchCalendarObjectError(self)
else:
raise
Modified: CalendarServer/branches/new-store/txcaldav/calendarstore/test/test_file.py
===================================================================
--- CalendarServer/branches/new-store/txcaldav/calendarstore/test/test_file.py 2010-05-14 21:23:03 UTC (rev 5605)
+++ CalendarServer/branches/new-store/txcaldav/calendarstore/test/test_file.py 2010-05-15 04:55:35 UTC (rev 5606)
@@ -291,7 +291,7 @@
self.home1._path
)
self.assertEquals(
- self.home1.calendarStore,
+ self.home1._calendarStore,
self.calendarStore
)
@@ -362,7 +362,7 @@
calendarProperties[
PropertyName.fromString(davxml.ResourceType.sname())
],
- davxml.ResourceType.calendar)
+ davxml.ResourceType.calendar) #@UndefinedVariable
checkProperties()
self.txn.commit()
self.home1 = self.calendarStore.newTransaction().calendarHomeWithUID(
@@ -447,21 +447,22 @@
def test_init(self):
"""
- Ivars are correctly initialized.
+ L{Calendar.__init__} sets private attributes to reflect its constructor
+ arguments.
"""
self.failUnless(
isinstance(self.calendar1._path, FilePath),
self.calendar1
)
self.failUnless(
- isinstance(self.calendar1.calendarHome, CalendarHome),
- self.calendar1.calendarHome
+ isinstance(self.calendar1._calendarHome, CalendarHome),
+ self.calendar1._calendarHome
)
def test_name(self):
"""
- Name is correct.
+ L{Calendar.name} reflects the name of the calendar.
"""
self.assertEquals(self.calendar1.name(), "calendar_1")
@@ -477,13 +478,15 @@
)
- def _test_calendarObjects(self, which):
+ def test_calendarObjects(self):
+ """
+ L{Calendar.calendarObjects} will enumerate the calendar objects present
+ in the filesystem, in name order, but skip those with hidden names.
+ """
# Add a dot file to make sure we don't find it
self.home1._path.child(".foo").createDirectory()
- methodName = "_calendarObjects_%s" % (which,)
- method = getattr(self.calendar1, methodName)
- calendarObjects = tuple(method())
+ calendarObjects = tuple(self.calendar1.calendarObjects())
for calendarObject in calendarObjects:
self.failUnless(
@@ -496,22 +499,17 @@
calendar1_objectNames
)
- @featureUnimplemented
- def test_calendarObjects_listdir(self):
- """
- Find all of the calendar objects using the listdir
- implementation.
- """
- return self._test_calendarObjects("listdir")
-
- @featureUnimplemented
- def test_calendarObjects_index(self):
+ def test_calendarObjectsWithRemovedObject(self):
"""
- Find all of the calendar objects using the index
- implementation.
+ L{Calendar.calendarObjects will skip those objects which have been
+ removed by L{Calendar.removeCalendarObjectWithName} in the same
+ transaction, even if it has not yet been committed.
"""
- return self._test_calendarObjects("index")
+ self.calendar1.removeCalendarObjectWithName("2.ics")
+ calendarObjects = list(self.calendar1.calendarObjects())
+ self.assertEquals(set(o.name() for o in calendarObjects),
+ set(calendar1_objectNames) - set(["2.ics"]))
def test_calendarObjectWithName_exists(self):
@@ -657,6 +655,17 @@
)
+ def test_removeCalendarObject_delayedEffect(self):
+ """
+ Removing a calendar object should not immediately remove the underlying
+ file; it should only be removed upon commit() of the transaction.
+ """
+ self.calendar1.removeCalendarObjectWithName("2.ics")
+ self.failUnless(self.calendar1._path.child("2.ics").exists())
+ self.txn.commit()
+ self.failIf(self.calendar1._path.child("2.ics").exists())
+
+
def test_removeCalendarObjectWithName_dot(self):
"""
Filenames starting with "." are reserved by this
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100514/d9e120d6/attachment-0001.html>
More information about the calendarserver-changes
mailing list