[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