[Commits] (vajda) - reworked child collection merging another time
commits at osafoundation.org
commits at osafoundation.org
Fri Sep 17 18:36:18 PDT 2004
Commit by: vajda
Modified files:
chandler/repository/item/Item.py 1.164 1.165
chandler/repository/persistence/RepositoryError.py 1.6 1.7
chandler/repository/persistence/RepositoryView.py 1.11 1.12
chandler/repository/persistence/XMLRefDict.py 1.11 1.12
chandler/repository/persistence/XMLRepositoryView.py 1.57 1.58
chandler/repository/tests/TestMerge.py 1.6 1.7
Log message:
- reworked child collection merging another time
- fixed bug 1974
ViewCVS links:
http://cvs.osafoundation.org/index.cgi/chandler/repository/item/Item.py.diff?r1=text&tr1=1.164&r2=text&tr2=1.165
http://cvs.osafoundation.org/index.cgi/chandler/repository/persistence/RepositoryError.py.diff?r1=text&tr1=1.6&r2=text&tr2=1.7
http://cvs.osafoundation.org/index.cgi/chandler/repository/persistence/RepositoryView.py.diff?r1=text&tr1=1.11&r2=text&tr2=1.12
http://cvs.osafoundation.org/index.cgi/chandler/repository/persistence/XMLRefDict.py.diff?r1=text&tr1=1.11&r2=text&tr2=1.12
http://cvs.osafoundation.org/index.cgi/chandler/repository/persistence/XMLRepositoryView.py.diff?r1=text&tr1=1.57&r2=text&tr2=1.58
http://cvs.osafoundation.org/index.cgi/chandler/repository/tests/TestMerge.py.diff?r1=text&tr1=1.6&r2=text&tr2=1.7
Index: chandler/repository/persistence/XMLRefDict.py
diff -u chandler/repository/persistence/XMLRefDict.py:1.11 chandler/repository/persistence/XMLRefDict.py:1.12
--- chandler/repository/persistence/XMLRefDict.py:1.11 Thu Sep 16 11:03:12 2004
+++ chandler/repository/persistence/XMLRefDict.py Fri Sep 17 18:36:15 2004
@@ -1,6 +1,6 @@
-__revision__ = "$Revision: 1.11 $"
-__date__ = "$Date: 2004/09/16 18:03:12 $"
+__revision__ = "$Revision: 1.12 $"
+__date__ = "$Date: 2004/09/18 01:36:15 $"
__copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
__license__ = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
@@ -358,7 +358,9 @@
def _load(self, key):
- if self.view._loadItem(key) is not None:
+ op, oldAlias = self._changedRefs.get(key, (0, None))
+
+ if op != 1 and self.view._loadItem(key) is not None:
return True
return False
@@ -409,15 +411,11 @@
def _saveValues(self, version):
store = self.view.repository.store
-
- if '_mergeList' in self.__dict__:
- children = self._mergeList
- else:
- children = self
-
- for key, (op, oldAlias) in children._changedRefs.iteritems():
+ unloads = []
+
+ for key, (op, oldAlias) in self._changedRefs.iteritems():
try:
- link = children._get(key, load=False)
+ link = self._get(key, load=False)
except KeyError:
link = None
@@ -433,6 +431,9 @@
if alias is not None:
store.writeName(version, self._uuid, alias, key)
+ if link._value is None:
+ unloads.append((key, link._alias))
+
elif key is None:
self._writeRef(self._uuid, version,
self._firstKey, self._lastKey, None)
@@ -445,194 +446,83 @@
else: # error
raise ValueError, op
+ for key, alias in unloads:
+ self._remove(key)
+ if alias is not None:
+ del self._aliases[alias]
+
def _clearDirties(self):
self._changedRefs.clear()
- try:
- del self._mergeList
- except AttributeError:
- pass
def _mergeChanges(self, oldVersion, toVersion):
- self._mergeList = MergeList(self.view, self._item, oldVersion)
- self._mergeList.collectHistory(toVersion)
- self._mergeList.applyChanges(self, self._changedRefs)
-
- self.view.logger.info('%s merged children of %s with newer versions',
- self.view, self._item.itsPath)
-
-
-class MergeList(LinkedMap):
-
- def __init__(self, view, item, version):
-
- super(MergeList, self).__init__()
-
- self.view = view
- self.item = item
- self.uuid = item._uuid
- self.version = version
-
- self._changedRefs = {}
- self._key = self._getRefs().prepareKey(self.uuid, self.uuid)
- self._aliases = {}
-
- ref = self._getRefs().loadRef(self._key, version, self.uuid)
- if ref is not None:
- self._firstKey, self._lastKey, alias = ref
-
- def _getRefs(self):
-
- return self.view.repository.store._refs
-
- def collectHistory(self, toVersion):
+ moves = {}
- def collect(version, (collection, child), ref):
- if collection == self.uuid: # the children collection
+ def merge(version, (collection, child), ref):
+ if collection == self._uuid: # the children collection
- if child == self.uuid: # the list head
- self._firstKey, self._lastKey, alias = ref
+ if child == self._uuid: # the list head
+ pass
- elif ref is None: # deleted child
- link = self._makeLink(None)
- self._insert(child, link)
+ elif ref is None: # removed child
+ op, oldAlias = self._changedRefs.get(child, (-1, None))
+ if op == 0:
+ self._e_1_remove(child)
+ elif self.has_key(child):
+ del self[child]
else:
- link = self._makeLink(child)
- link._previousKey, link._nextKey, link._alias = ref
- self._insert(child, link)
- if link._alias is not None:
- self._aliases[link._alias] = child
-
- self._getRefs().applyHistory(collect, self.uuid,
- self.version, toVersion)
-
- def applyChanges(self, children, changes):
-
- key = self._insertKey = self._firstKey
- while key in self:
- self._insertKey = key
- key = self._get(key)._nextKey
-
- for child in changes.keys():
- if child in changes:
- if child is not None: # not the list head
- op, oldAlias = changes[child]
- if op == 0: # insert or change
- self.applyChange(children, changes, child, oldAlias)
- elif op == 1: # delete
- raise NotImplementedError
-
- children._firstKey = self._firstKey
- children._lastKey = self._lastKey
-
- def applyChange(self, children, changes, child, oldAlias):
-
- link = children._get(child)
- prev = prevKey = link._previousKey
- exists = child in self
-
- if exists:
- alias = self._get(child)._alias
- if oldAlias is not None:
- if oldAlias != alias and link._alias != alias:
- raise MergeError, ('merging children', self.item, 'child %s renamed to %s and %s' %(oldAlias, link._alias, alias), MergeError.RENAME)
-
- if link._alias in self._aliases:
- alias = link._alias
- if exists and self._aliases[alias] != child or not exists:
- raise MergeError, ('merging children', self.item, 'child %s conflicts with other child %s, both are named %s' %(child, self._aliases[alias], alias), MergeError.RENAME)
-
- if prev is None:
- if exists:
- prevKey = self._firstKey
- else:
- prev = prevKey = self._insertKey
- else:
- key = prevKey
- while key in self:
- prev = prevKey = key
- key = self._get(key)._nextKey
-
- if prevKey is not None and prevKey not in self:
- op, oa = changes.get(prevKey, (0, None))
- if op != 0:
- raise ValueError, op
- self.applyChange(children, changes, prevKey, oa)
-
- current = self.placeChange(child, prev, link._alias)
-
- link._previousKey = current._previousKey
- if exists:
- link._nextKey = current._nextKey
-
- if oldAlias is not None:
- self._changedRefs[child] = (0, oldAlias)
-
- try:
- del changes[child]
- except KeyError:
- pass
+ previousKey, nextKey, alias = ref
+ op, oldAlias = self._changedRefs.get(child, (0, None))
- def placeChange(self, key, afterKey, alias):
+ if op == 1:
+ self._e_2_remove(child)
- if key == afterKey:
- raise ValueError, 'key == afterKey'
+ try:
+ link = self._get(child)
+ if link._alias != alias:
+ if oldAlias is not None:
+ self._e_1_renames(oldAlias, link._alias, alias)
+ else:
+ key = self.resolveAlias(alias)
+ if key is not None:
+ self._e_2_renames(key, alias, child)
+ self.setAlias(child, alias)
+
+ except KeyError:
+ key = self.resolveAlias(alias)
+ if key is not None:
+ self._e_names(child, key, alias)
+ link = self.__setitem__(child, None, alias=alias)
+
+ if previousKey is None or self.has_key(previousKey):
+ self.place(child, previousKey)
+ else:
+ moves[previousKey] = child
+
+ self._getRefs().applyHistory(merge, self._uuid,
+ self._item._version, toVersion)
- try:
- current = self._get(key, False)
- exists = True
- except KeyError:
- current = self._makeLink(key)
- current._alias = alias
- self._insert(key, current)
- exists = False
-
- if exists:
- if current._previousKey == afterKey:
- return current
- if current._previousKey is not None:
- previous = self._get(current._previousKey)
- else:
- previous = None
- if current._nextKey is not None:
- next = self._get(current._nextKey)
- else:
- next = None
-
- if afterKey is None:
- after = None
- afterNextKey = self._firstKey
- else:
- after = self._get(afterKey)
- afterNextKey = after._nextKey
+ for previousKey, child in moves.iteritems():
+ self.place(child, previousKey)
+
+ self.view.logger.info('%s merged children of %s with newer versions',
+ self.view, self._item.itsPath)
- if exists:
- if previous is not None:
- previous._setNext(current._nextKey, current._previousKey, self)
- if next is not None:
- next._setPrevious(current._previousKey, current._nextKey, self)
-
- current._setNext(afterNextKey, key, self)
- if afterNextKey is not None:
- self._get(afterNextKey)._setPrevious(key, afterNextKey, self)
- if after is not None:
- after._setNext(key, afterKey, self)
- current._setPrevious(afterKey, key, self)
+ def _e_1_remove(self, *args):
+ raise MergeError, ('merging children', self._item, 'modified child %s was removed in other view' %(args), MergeError.MOVE)
- return current
-
- def linkChanged(self, link, key):
+ def _e_2_remove(self, *args):
+ raise MergeError, ('merging children', self._item, 'removed child %s was modified in other view' %(args), MergeError.MOVE)
- op, alias = self._changedRefs.get(key, (1, link._alias))
- if op != 0:
- self._changedRefs[key] = (0, alias)
+ def _e_1_renames(self, *args):
+ raise MergeError, ('merging children', self._item, 'child %s renamed to %s and %s' %(args), MergeError.RENAME)
- def _load(self, key):
+ def _e_2_renames(self, *args):
+ raise MergeError, ('merging children', self._item, 'child %s named %s conflicts with child %s of same name' %(args), MergeError.NAME)
- raise MergeError, ('merging children', self.item,
- 'of a bug: _load should not be called.',
- MergeError.BUG)
+ def _e_names(self, *args):
+ raise MergeError, ('merging children', self._item, 'child %s conflicts with other child %s, both are named %s' %(args), MergeError.NAME)
Index: chandler/repository/persistence/RepositoryError.py
diff -u chandler/repository/persistence/RepositoryError.py:1.6 chandler/repository/persistence/RepositoryError.py:1.7
--- chandler/repository/persistence/RepositoryError.py:1.6 Wed Sep 15 15:43:14 2004
+++ chandler/repository/persistence/RepositoryError.py Fri Sep 17 18:36:15 2004
@@ -1,6 +1,6 @@
-__revision__ = "$Revision: 1.6 $"
-__date__ = "$Date: 2004/09/15 22:43:14 $"
+__revision__ = "$Revision: 1.7 $"
+__date__ = "$Date: 2004/09/18 01:36:15 $"
__copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
__license__ = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
@@ -47,5 +47,9 @@
BUG = 0
RENAME = 1
MOVE = 2
+ NAME = 3
- codeNames = { BUG: 'BUG', RENAME: 'RENAME', 'MOVE': MOVE }
+ codeNames = { BUG: 'BUG',
+ RENAME: 'RENAME',
+ MOVE: 'MOVE',
+ NAME: 'NAME' }
Index: chandler/repository/persistence/RepositoryView.py
diff -u chandler/repository/persistence/RepositoryView.py:1.11 chandler/repository/persistence/RepositoryView.py:1.12
--- chandler/repository/persistence/RepositoryView.py:1.11 Tue Sep 14 11:08:16 2004
+++ chandler/repository/persistence/RepositoryView.py Fri Sep 17 18:36:15 2004
@@ -1,6 +1,6 @@
-__revision__ = "$Revision: 1.11 $"
-__date__ = "$Date: 2004/09/14 18:08:16 $"
+__revision__ = "$Revision: 1.12 $"
+__date__ = "$Date: 2004/09/18 01:36:15 $"
__copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
__license__ = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
@@ -461,7 +461,7 @@
self.logger.debug('loading item %s', string[index+6:index+28])
else:
self.logger.debug('loading item %s', string)
-
+
handler = ItemHandler(self, parent or self, afterLoadHooks, instance)
parser.parseDoc(doc, handler)
Index: chandler/repository/item/Item.py
diff -u chandler/repository/item/Item.py:1.164 chandler/repository/item/Item.py:1.165
--- chandler/repository/item/Item.py:1.164 Thu Sep 16 11:03:12 2004
+++ chandler/repository/item/Item.py Fri Sep 17 18:36:15 2004
@@ -1,6 +1,6 @@
-__revision__ = "$Revision: 1.164 $"
-__date__ = "$Date: 2004/09/16 18:03:12 $"
+__revision__ = "$Revision: 1.165 $"
+__date__ = "$Date: 2004/09/18 01:36:15 $"
__copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
__license__ = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
@@ -733,8 +733,8 @@
if not load:
if self._children is not None:
- for child in self._children._itervalues():
- yield child._value
+ for link in self._children._itervalues():
+ yield link._value
elif self._children is not None:
for child in self._children:
@@ -2470,9 +2470,10 @@
def _unloadChild(self, child):
- self._remove(child._uuid)
- if child._name is not None:
- del self._aliases[child._name]
+ if child._uuid in self:
+ self._remove(child._uuid)
+ if child._name is not None:
+ del self._aliases[child._name]
def __repr__(self):
@@ -2498,13 +2499,6 @@
if buffer is not None:
buffer.close()
- def _load(self, key):
-
- if self._item.getRepositoryView()._loadItem(key) is not None:
- return True
-
- return False
-
def _saveValues(self, version):
pass
Index: chandler/repository/persistence/XMLRepositoryView.py
diff -u chandler/repository/persistence/XMLRepositoryView.py:1.57 chandler/repository/persistence/XMLRepositoryView.py:1.58
--- chandler/repository/persistence/XMLRepositoryView.py:1.57 Fri Sep 17 14:42:51 2004
+++ chandler/repository/persistence/XMLRepositoryView.py Fri Sep 17 18:36:15 2004
@@ -1,6 +1,6 @@
-__revision__ = "$Revision: 1.57 $"
-__date__ = "$Date: 2004/09/17 21:42:51 $"
+__revision__ = "$Revision: 1.58 $"
+__date__ = "$Date: 2004/09/18 01:36:15 $"
__copyright__ = "Copyright (c) 2002 Open Source Applications Foundation"
__license__ = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
@@ -362,11 +362,9 @@
self._mergeNDIRTY(item, parentId, oldVersion, toVersion)
oldDirty &= ~Item.NDIRTY
- # @@@ Per Andi, commenting these out to prevent infinite recursion
- # Instead, we'll get a VersionConflictError
- # if newDirty & oldDirty & Item.CDIRTY:
- # # item._children._mergeChanges(oldVersion, toVersion)
- # oldDirty &= ~Item.CDIRTY
+ if newDirty & oldDirty & Item.CDIRTY:
+ item._children._mergeChanges(oldVersion, toVersion)
+ oldDirty &= ~Item.CDIRTY
if newDirty and oldDirty:
raise VersionConflictError, (item, newDirty, oldDirty)
Index: chandler/repository/tests/TestMerge.py
diff -u chandler/repository/tests/TestMerge.py:1.6 chandler/repository/tests/TestMerge.py:1.7
--- chandler/repository/tests/TestMerge.py:1.6 Fri Sep 17 16:05:37 2004
+++ chandler/repository/tests/TestMerge.py Fri Sep 17 18:36:16 2004
@@ -2,8 +2,8 @@
Test merging of items
"""
-__revision__ = "$Revision: 1.6 $"
-__date__ = "$Date: 2004/09/17 23:05:37 $"
+__revision__ = "$Revision: 1.7 $"
+__date__ = "$Date: 2004/09/18 01:36:16 $"
__copyright__ = "Copyright (c) 2003 Open Source Applications Foundation"
__license__ = "http://osafoundation.org/Chandler_0.1_license_terms.htm"
@@ -148,6 +148,7 @@
try:
self.rename('foo', 'bar')
except MergeError, e:
+ #print e
self.assert_(e.getReasonCode() == MergeError.RENAME)
def testMoveSame(self):
@@ -157,6 +158,7 @@
try:
self.move('foo', 'bar')
except MergeError, e:
+ #print e
self.assert_(e.getReasonCode() == MergeError.MOVE)
else:
self.assert_(False)
@@ -177,7 +179,8 @@
try:
main.commit()
except MergeError, e:
- self.assert_(e.getReasonCode() == MergeError.RENAME)
+ #print e
+ self.assert_(e.getReasonCode() == MergeError.NAME)
else:
self.assert_(False)
@@ -201,15 +204,128 @@
try:
main.commit()
except MergeError, e:
- self.assert_(e.getReasonCode() == MergeError.RENAME)
+ #print e
+ self.assert_(e.getReasonCode() == MergeError.NAME)
+ else:
+ self.assert_(False)
+
+ def testMoveFirst(self):
+ pm = self.rep['p']
+ km = self.rep.findPath('//Schema/Core/Item')
+ km.newItem('foo', pm)
+ km.newItem('bar', pm)
+ km.newItem('i1', pm)
+ km.newItem('i2', pm)
+ self.rep.commit()
+
+ view = self.rep.createView('view')
+ main = self.rep.setCurrentView(view)
+ po = self.rep['p']
+ po.placeChild(po['i1'], None)
+ view.commit()
+
+ view = self.rep.setCurrentView(main)
+ pm = self.rep['p']
+ pm.placeChild(pm['i2'], None)
+ main.commit()
+
+ names = [c.itsName for c in pm.iterChildren()]
+ self.assert_(names[0] == 'i1')
+ self.assert_(len(names) == 4)
+
+ def testChange1Remove1(self):
+
+ pm = self.rep['p']
+ km = self.rep.findPath('//Schema/Core/Item')
+ km.newItem('q', self.rep)
+ km.newItem('foo', pm)
+ km.newItem('bar', pm)
+ km.newItem('i1', pm)
+ km.newItem('i2', pm)
+ self.rep.commit()
+
+ view = self.rep.createView('view')
+ main = self.rep.setCurrentView(view)
+ po = self.rep['p']
+ po.placeChild(po['i1'], None)
+ view.commit()
+
+ view = self.rep.setCurrentView(main)
+ pm = self.rep['p']
+ qm = self.rep['q']
+
+ pm['i1'].move(qm)
+
+ try:
+ main.commit()
+ except MergeError, e:
+ #print e
+ self.assert_(e.getReasonCode() == MergeError.MOVE)
else:
self.assert_(False)
+ def testRemove1Change1(self):
+
+ pm = self.rep['p']
+ km = self.rep.findPath('//Schema/Core/Item')
+ km.newItem('q', self.rep)
+ km.newItem('foo', pm)
+ km.newItem('bar', pm)
+ km.newItem('i1', pm)
+ km.newItem('i2', pm)
+ self.rep.commit()
+
+ view = self.rep.createView('view')
+ main = self.rep.setCurrentView(view)
+ po = self.rep['p']
+ qo = self.rep['q']
+ po['i1'].move(qo)
+ view.commit()
+
+ view = self.rep.setCurrentView(main)
+ pm = self.rep['p']
+
+ pm.placeChild(pm['i1'], None)
+
+ try:
+ main.commit()
+ except MergeError, e:
+ #print e
+ self.assert_(e.getReasonCode() == MergeError.MOVE)
+ else:
+ self.assert_(False)
+
+ def testRemove1ChangeOther(self):
+
+ pm = self.rep['p']
+ km = self.rep.findPath('//Schema/Core/Item')
+ km.newItem('q', self.rep)
+ km.newItem('foo', pm)
+ km.newItem('bar', pm)
+ km.newItem('i1', pm)
+ km.newItem('i2', pm)
+ self.rep.commit()
+
+ view = self.rep.createView('view')
+ main = self.rep.setCurrentView(view)
+ po = self.rep['p']
+ qo = self.rep['q']
+ po['i1'].move(qo)
+ view.commit()
+
+ view = self.rep.setCurrentView(main)
+ pm = self.rep['p']
+ pm['foo'].rename('baz')
+ main.commit()
+
+ names = [c.itsName for c in pm.iterChildren()]
+ self.assert_(names[0] == 'baz')
+ self.assert_(len(names) == 3)
+
if __name__ == "__main__":
# import hotshot
# profiler = hotshot.Profile('/tmp/TestItems.hotshot')
# profiler.run('unittest.main()')
# profiler.close()
- # unittest.main()
- pass
+ unittest.main()
More information about the Commits
mailing list