[Checkins] SVN: z3c.vcsync/trunk/src/z3c/vcsync/ Get rid of IVcLoad
and introduce smarter loading method which only loads
Martijn Faassen
faassen at infrae.com
Wed Jul 4 18:51:59 EDT 2007
Log message for revision 77438:
Get rid of IVcLoad and introduce smarter loading method which only loads
that which has changed.
Changed:
U z3c.vcsync/trunk/src/z3c/vcsync/README.txt
U z3c.vcsync/trunk/src/z3c/vcsync/interfaces.py
U z3c.vcsync/trunk/src/z3c/vcsync/tests.py
U z3c.vcsync/trunk/src/z3c/vcsync/vc.py
-=-
Modified: z3c.vcsync/trunk/src/z3c/vcsync/README.txt
===================================================================
--- z3c.vcsync/trunk/src/z3c/vcsync/README.txt 2007-07-04 21:56:59 UTC (rev 77437)
+++ z3c.vcsync/trunk/src/z3c/vcsync/README.txt 2007-07-04 22:51:59 UTC (rev 77438)
@@ -387,22 +387,28 @@
>>> grok.grok_component('ItemFactory', ItemFactory)
True
-Now for containers. They are registered for an empty extension. They
-are also required to use VcLoad to load their contents::
+Now for containers. They are registered for an empty extension::
- >>> from z3c.vcsync.interfaces import IVcLoad
>>> class ContainerFactory(grok.GlobalUtility):
... grok.provides(IVcFactory)
... def __call__(self, checkout, path):
... container = Container()
- ... IVcLoad(container).load(checkout, path)
... return container
>>> grok.grok_component('ContainerFactory', ContainerFactory)
True
-We have registered enough. Let's load up the contents from the
-filesystem now::
+We need to maintain a list of everything modified, added or deleted by
+the update operation. Normally this information is extracted from the
+version control system, but for the purposes of this test we maintain
+it manually. In this case, everything is added::
+ >>> checkout._added = [root.join('foo.test'), root.join('hoi.test'),
+ ... root.join('sub'), root.join('sub', 'qux.test')]
+ >>> checkout._deleted = []
+ >>> checkout._modified = []
+
+Let's load up the contents from the filesystem now::
+
>>> container2 = Container()
>>> container2.__name__ = 'root'
>>> checkout.load(container2)
@@ -444,8 +450,16 @@
... hoi_path.write('200\n')
>>> checkout.update_function = update_function
+Now let's do an update::
+
>>> checkout.up()
+We maintain the lists of things changed::
+
+ >>> checkout._added = []
+ >>> checkout._deleted = []
+ >>> checkout._modified = [hoi_path]
+
We will reload the checkout into Python objects::
>>> checkout.load(container2)
@@ -468,6 +482,12 @@
>>> checkout.up()
+We maintain the lists of things changed::
+
+ >>> checkout._added = [hallo]
+ >>> checkout._deleted = []
+ >>> checkout._modified = []
+
We will reload the checkout into Python objects again::
>>> checkout.load(container2)
@@ -488,6 +508,12 @@
>>> checkout.up()
+We maintain the lists of things changed::
+
+ >>> checkout._added = []
+ >>> checkout._deleted = [hallo]
+ >>> checkout._modified = []
+
We will reload the checkout into Python objects::
>>> checkout.load(container2)
@@ -512,6 +538,12 @@
>>> checkout.up()
+We maintain the lists of things changed::
+
+ >>> checkout._added = [newdir_path, newdir_path.join('newfile.test')]
+ >>> checkout._deleted = []
+ >>> checkout._modified = []
+
Reloading this will cause a new container to exist::
>>> checkout.load(container2)
@@ -534,6 +566,14 @@
>>> checkout.up()
+We maintain the lists of things changed::
+
+ >>> checkout._added = []
+ >>> checkout._deleted = [newdir_path, newdir_path.join('newfile.test')]
+ >>> checkout._modified = []
+
+And reload the data::
+
>>> checkout.load(container2)
Reloading this will cause the new container to be gone again::
@@ -556,6 +596,12 @@
... some_path.write('1000\n')
>>> checkout.update_function = update_function
+We maintain the lists of things changed::
+
+ >>> checkout._added = [hoi_path2, hoi_path2.join('some.test')]
+ >>> checkout._deleted = [hoi_path]
+ >>> checkout._modified = []
+
>>> checkout.up()
Reloading this will cause a new container to be there instead of the file::
@@ -580,6 +626,12 @@
>>> checkout.up()
+We maintain the lists of things changed::
+
+ >>> checkout._added = [hoi_path]
+ >>> checkout._deleted = [hoi_path2.join('some.test'), hoi_path2]
+ >>> checkout._modified = []
+
Reloading this will cause a new item to be there instead of the
container::
@@ -600,11 +652,17 @@
Next, we willl add a new ``alpha`` file to the checkout when we do an
``up()``, so again we simulate the actions of our version control system::
+ >>> alpha_path = root.join('alpha.test').ensure()
>>> def update_function():
- ... alpha_path = root.join('alpha.test').ensure()
... alpha_path.write('4000\n')
>>> checkout.update_function = update_function
+We maintain the lists of things changed::
+
+ >>> checkout._added = [alpha_path]
+ >>> checkout._deleted = []
+ >>> checkout._modified = []
+
Now we'll synchronize with the memory structure::
>>> state = TestState(container2)
Modified: z3c.vcsync/trunk/src/z3c/vcsync/interfaces.py
===================================================================
--- z3c.vcsync/trunk/src/z3c/vcsync/interfaces.py 2007-07-04 21:56:59 UTC (rev 77437)
+++ z3c.vcsync/trunk/src/z3c/vcsync/interfaces.py 2007-07-04 22:51:59 UTC (rev 77438)
@@ -14,11 +14,6 @@
Returns the path just created.
"""
-class IVcLoad(Interface):
- def load(checkout, path):
- """Load data in checkout's path into context object.
- """
-
class ISerializer(Interface):
def serialize(f):
"""Serialize object to file object.
@@ -37,16 +32,7 @@
def __call__():
"""Create new instance of object.
"""
-
-class IModified(Interface):
- def modified_since(dt):
- """Return True if the object has been modified since dt.
- """
- def update():
- """Update modification datetime.
- """
-
class IState(Interface):
"""Information about Python object state.
"""
@@ -101,15 +87,15 @@
"""Commit checkout to version control system.
"""
- def added_by_up():
+ def added():
"""A list of those files that have been added after 'up'.
"""
- def deleted_by_up():
+ def deleted():
"""A list of those files that have been deleted after 'up'.
"""
- def modified_by_up():
+ def modified():
"""A list of those files that have been modified after 'up'.
"""
Modified: z3c.vcsync/trunk/src/z3c/vcsync/tests.py
===================================================================
--- z3c.vcsync/trunk/src/z3c/vcsync/tests.py 2007-07-04 21:56:59 UTC (rev 77437)
+++ z3c.vcsync/trunk/src/z3c/vcsync/tests.py 2007-07-04 22:51:59 UTC (rev 77438)
@@ -10,14 +10,17 @@
from zope.app.container.interfaces import IContainer
from zope.exceptions.interfaces import DuplicationError
-from z3c.vcsync.interfaces import ISerializer, IVcDump, IVcLoad, IVcFactory, IModified
+from z3c.vcsync.interfaces import ISerializer, IVcDump, IVcFactory
from z3c.vcsync import vc
class TestCheckout(vc.CheckoutBase):
def __init__(self, path):
super(TestCheckout, self).__init__(path)
self.update_function = None
-
+ self._added = []
+ self._deleted = []
+ self._modified = []
+
def up(self):
# call update_function which will modify the checkout as might
# happen in a version control update. Function should be set before
@@ -30,6 +33,15 @@
def commit(self, message):
pass
+ def added(self):
+ return self._added
+
+ def deleted(self):
+ return self._deleted
+
+ def modified(self):
+ return self._modified
+
class TestState(object):
def __init__(self, root):
self.root = root
Modified: z3c.vcsync/trunk/src/z3c/vcsync/vc.py
===================================================================
--- z3c.vcsync/trunk/src/z3c/vcsync/vc.py 2007-07-04 21:56:59 UTC (rev 77437)
+++ z3c.vcsync/trunk/src/z3c/vcsync/vc.py 2007-07-04 22:51:59 UTC (rev 77438)
@@ -2,13 +2,11 @@
from datetime import datetime
from zope.interface import Interface
-from zope.component import queryUtility, queryAdapter
+from zope.component import queryUtility, getUtility, queryAdapter
from zope.app.container.interfaces import IContainer
from zope.traversing.interfaces import IPhysicallyLocatable
-from z3c.vcsync.interfaces import (IVcDump, IVcLoad,
- ISerializer, IVcFactory,
- IModified, ICheckout)
+from z3c.vcsync.interfaces import IVcDump, ISerializer, IVcFactory, ICheckout
import grok
@@ -37,36 +35,33 @@
path = path.join(self.context.__name__)
path.ensure(dir=True)
-class ContainerVcLoad(grok.Adapter):
- grok.provides(IVcLoad)
- grok.context(IContainer)
-
- def load(self, checkout, path):
- loaded = []
- for sub in path.listdir():
- if sub.basename.startswith('.'):
- continue
- if sub.check(dir=True):
- object_name = '' # containers are indicated by empty string
- else:
- object_name = sub.ext
- factory = queryUtility(IVcFactory, name=object_name, default=None)
- # we cannot handle this kind of object, so skip it
- if factory is None:
- continue
- # create instance of object and put it into the container
- # XXX what if object is already there?
- obj = factory(checkout, sub)
- # store the newly created object into the container
- if sub.purebasename in self.context:
- del self.context[sub.purebasename]
- self.context[sub.purebasename] = obj
- loaded.append(sub.purebasename)
- # remove any objects not there anymore
- for name in list(self.context.keys()):
- if name not in loaded:
- del self.context[name]
+def resolve(root, root_path, path):
+ rel_path = path.relto(root_path)
+ steps = rel_path.split('/')
+ steps = [step for step in steps if step != '']
+ steps = steps[1:]
+ obj = root
+ for step in steps:
+ name, ex = os.path.splitext(step)
+ try:
+ obj = obj[name]
+ except KeyError:
+ return None
+ return obj
+def resolve_container(root, root_path, path):
+ rel_path = path.relto(root_path)
+ steps = rel_path.split('/')
+ steps = [step for step in steps if step != '']
+ steps = steps[1:-1]
+ obj = root
+ for step in steps:
+ try:
+ obj = obj[step]
+ except KeyError:
+ return None
+ return obj
+
class CheckoutBase(object):
"""Checkout base class.
@@ -120,12 +115,24 @@
self.get_container_path(root, obj))
def load(self, object):
- # XXX can only load containers here, not items
- names = [path.purebasename for path in self.path.listdir()
- if not path.purebasename.startswith('.')]
- assert len(names) == 1
- IVcLoad(object).load(self, self.path.join(names[0]))
-
+ root = object
+ for deleted_path in self.deleted():
+ obj = resolve(root, self.path, deleted_path)
+ if obj is not None:
+ del obj.__parent__[obj.__name__]
+ added_paths = self.added()
+ # to ensure that containers are created before items we sort them
+ sorted(added_paths)
+ for added_path in added_paths:
+ obj = resolve_container(root, self.path, added_path)
+ factory = getUtility(IVcFactory, name=added_path.ext)
+ obj[added_path.purebasename] = factory(self, added_path)
+ for modified_path in self.modified():
+ obj = resolve(root, self.path, modified_path)
+ factory = getUtility(IVcFactory, name=modified_path.ext)
+ del obj.__parent__[obj.__name__]
+ obj.__parent__[obj.__name__] = factory(self, modified_path)
+
def up(self):
raise NotImplementedError
@@ -135,19 +142,11 @@
def commit(self, message):
raise NotImplementedError
- def added_by_up(self):
+ def added(self):
raise NotImplementedError
- def deleted_by_up(self):
+ def deleted(self):
raise NotImplementedError
- def modified_by_up(self):
+ def modified(self):
raise NotImplementedError
-
-class ContainerModified(grok.Adapter):
- grok.provides(IModified)
- grok.context(IContainer)
-
- def modified_since(self, dt):
- # containers themselves are never modified
- return False
More information about the Checkins
mailing list