[Checkins] SVN: z3c.vcsync/trunk/ Report more info about a synchronization.

Martijn Faassen faassen at infrae.com
Tue Dec 11 18:32:40 EST 2007


Log message for revision 82258:
  Report more info about a synchronization.
  

Changed:
  U   z3c.vcsync/trunk/CHANGES.txt
  U   z3c.vcsync/trunk/setup.py
  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/CHANGES.txt
===================================================================
--- z3c.vcsync/trunk/CHANGES.txt	2007-12-11 20:47:52 UTC (rev 82257)
+++ z3c.vcsync/trunk/CHANGES.txt	2007-12-11 23:32:40 UTC (rev 82258)
@@ -1,11 +1,17 @@
 z3c.vcsync changes
 ==================
 
-0.9.2 (unreleased)
+0.10 (unreleased)
 ------------------
 
-* ...
+Features added
+~~~~~~~~~~~~~~
 
+* The ``.sync()`` method now does not return the revision number, but
+  an ``ISynchronizationInfo`` object. This has a ``revision_nr``
+  attribute and also contains some information on what happened during
+  the synchronization process.
+
 0.9.1 (2007-11-29)
 ------------------
 

Modified: z3c.vcsync/trunk/setup.py
===================================================================
--- z3c.vcsync/trunk/setup.py	2007-12-11 20:47:52 UTC (rev 82257)
+++ z3c.vcsync/trunk/setup.py	2007-12-11 23:32:40 UTC (rev 82258)
@@ -2,7 +2,7 @@
 import sys, os
 
 setup(name='z3c.vcsync',
-      version='0.9.2dev',
+      version='0.10dev',
       description="Sync ZODB data with version control system, currently SVN",
       package_dir={'': 'src'},
       packages=find_packages('src'),

Modified: z3c.vcsync/trunk/src/z3c/vcsync/README.txt
===================================================================
--- z3c.vcsync/trunk/src/z3c/vcsync/README.txt	2007-12-11 20:47:52 UTC (rev 82257)
+++ z3c.vcsync/trunk/src/z3c/vcsync/README.txt	2007-12-11 23:32:40 UTC (rev 82258)
@@ -676,10 +676,39 @@
   >>> checkout._files = [alpha_path]
   >>> checkout._removed = []
 
+The revision number before full synchronization::
+
+  >>> checkout.revision_nr()
+  7
+
 Now we'll synchronize with the memory structure::
 
-  >>> s.sync(None)
+  >>> info = s.sync(None)
+  >>> info.revision_nr
+  8
 
+We can get a report of what happened. No files were removed::
+
+  >>> info.files_removed()
+  []
+
+One file, alpha, was added to the checkout during our update (by
+someone else)::
+
+  >>> info.files_changed()
+  [local('.../root/alpha.test')]
+
+We removed no objects from our database since the last update::
+
+  >>> info.objects_removed()
+  []
+
+We did change one object, 'hoi', but the test infrastructure always returns
+all objects here (returning more objects is allowed)::
+
+  >>> info.objects_changed()
+  ['/root/foo', '/root/hoi', '/root', '/root/sub/qux', '/root/sub']
+
 We expect the checkout to reflect the changed state of the ``hoi`` object::
 
   >>> root.join('hoi.test').read()

Modified: z3c.vcsync/trunk/src/z3c/vcsync/interfaces.py
===================================================================
--- z3c.vcsync/trunk/src/z3c/vcsync/interfaces.py	2007-12-11 20:47:52 UTC (rev 82257)
+++ z3c.vcsync/trunk/src/z3c/vcsync/interfaces.py	2007-12-11 23:32:40 UTC (rev 82258)
@@ -50,8 +50,9 @@
              control system such as SVN controls these.
         message - message to commit any version control changes.
 
-        Returns the revision number of the version control system that
-        we have now synchronized with.
+        Returns a ISynchronizationInfo object with a report of the
+        synchronization, including the new revision number after 
+        synchronization.
         """
         
     def save(revision_nr):
@@ -128,3 +129,36 @@
         safe to return paths of objects returned by the 'objects'
         method.
         """
+
+class ISynchronizationInfo(Interface):
+    """Information on what happened during a synchronization.
+    """
+
+    revision_nr = Attribute("""
+    The revision number of the version control system that
+    we have synchronized with.
+    """)
+    
+    def objects_removed():
+        """Paths of objects removed in synchronization.
+
+        The paths are state internal paths.
+        """
+        
+    def objects_changed():
+        """Paths of objects added or changed in synchronization.
+
+        The paths are state internal paths.
+        """
+
+    def files_removed():
+        """Paths of files removed in synchronization.
+
+        The paths are filesystem paths (py.path objects)
+        """
+
+    def files_changed():
+        """The paths of files added or changed in synchronization.
+
+        The paths are filesystem paths (py.path objects)
+        """

Modified: z3c.vcsync/trunk/src/z3c/vcsync/tests.py
===================================================================
--- z3c.vcsync/trunk/src/z3c/vcsync/tests.py	2007-12-11 20:47:52 UTC (rev 82257)
+++ z3c.vcsync/trunk/src/z3c/vcsync/tests.py	2007-12-11 23:32:40 UTC (rev 82258)
@@ -22,11 +22,13 @@
         self.update_function = None
         self._files = []
         self._removed = []
+        self._revision_nr = 0
         
     def up(self):
         # call update_function which will modify the checkout as might
         # happen in a version control update. Function should be set before
         # calling this in testing code
+        self._revision_nr += 1
         self.update_function()
 
     def resolve(self):
@@ -42,8 +44,8 @@
         return self._removed
 
     def revision_nr(self):
-        return None
-    
+        return self._revision_nr
+ 
 class TestState(vc.AllState):
     
     def __init__(self, root):

Modified: z3c.vcsync/trunk/src/z3c/vcsync/vc.py
===================================================================
--- z3c.vcsync/trunk/src/z3c/vcsync/vc.py	2007-12-11 20:47:52 UTC (rev 82257)
+++ z3c.vcsync/trunk/src/z3c/vcsync/vc.py	2007-12-11 23:32:40 UTC (rev 82258)
@@ -8,7 +8,8 @@
 from zope.traversing.interfaces import IPhysicallyLocatable
 
 from z3c.vcsync.interfaces import (IVcDump, ISerializer,
-                                   IState, IVcFactory, ISynchronizer)
+                                   IState, IVcFactory, ISynchronizer,
+                                   ISynchronizationInfo)
 
 import grok
 
@@ -38,6 +39,14 @@
         path.ensure(dir=True)
 
 def resolve(root, root_path, path):
+    """Resolve checkout path to obj in state.
+
+    root - the root container in the state
+    root_path - a py.path reference to the checkout
+    path - a py.path reference to the file in the checkout
+
+    Returns the object in the state, or None.
+    """
     rel_path = path.relto(root_path)
     steps = rel_path.split(os.path.sep)
     steps = [step for step in steps if step != '']
@@ -52,6 +61,14 @@
     return obj
 
 def resolve_container(root, root_path, path):
+    """Resolve checkout path to container in state.
+
+    root - the root container in the state
+    root_path - a py.path reference to the checkout
+    path - a py.path reference to the directory in the checkout
+
+    Returns the container in the state, or None.
+    """
     rel_path = path.relto(root_path)
     steps = rel_path.split(os.path.sep)
     steps = [step for step in steps if step != '']
@@ -66,6 +83,20 @@
             return None
     return obj
 
+def get_object_path(root, obj):
+    """Return state-specific path for obj.
+
+    Given state root container and obj, return internal path to this obj.
+    """
+    steps = []
+    while True:
+        steps.append(obj.__name__)
+        if obj is root:
+            break
+        obj = obj.__parent__
+    steps.reverse()
+    return '/' + '/'.join(steps)
+
 class Synchronizer(object):
     grok.implements(ISynchronizer)
 
@@ -75,8 +106,16 @@
         self._to_remove = []
 
     def sync(self, revision_nr, message=''):
+        # store these to report in SynchronizationInfo below
+        objects_removed = list(self.state.removed(revision_nr))
+        root = self.state.root
+        objects_changed = [get_object_path(root, obj) for obj in
+                           self.state.objects(revision_nr)]
+        # now save the state to the checkout
         self.save(revision_nr)
+        # update the checkout
         self.checkout.up()
+        # resolve any conflicts
         self.checkout.resolve()
         # now after doing an up, remove dirs that can be removed
         # it is not safe to do this during safe, as an 'svn up' will
@@ -85,10 +124,17 @@
         # the ZODB when we do a load.
         for to_remove in self._to_remove:
             py.path.local(to_remove).remove(rec=True)
+        # store what was removed and modified in checkout now
+        files_removed = self.checkout.removed(revision_nr)
+        files_changed = self.checkout.files(revision_nr)
+        # now load the checkout state back into the ZODB state
         self.load(revision_nr)
+        # and commit the checkout state
         self.checkout.commit(message)
-        return self.checkout.revision_nr()
-    
+        return SynchronizationInfo(self.checkout.revision_nr(),
+                                   objects_removed, objects_changed,
+                                   files_removed, files_changed)
+
     def save(self, revision_nr):
         # remove all files that have been removed in the database
         path = self.checkout.path
@@ -194,3 +240,43 @@
                 continue
             for sub_container in self._containers_helper(obj):
                 yield sub_container
+
+class SynchronizationInfo(object):
+    grok.implements(ISynchronizationInfo)
+
+    def __init__(self, revision_nr,
+                 objects_removed, objects_changed,
+                 files_removed, files_changed):
+        self.revision_nr = revision_nr
+        self._objects_removed = objects_removed
+        self._objects_changed = objects_changed
+        self._files_removed = files_removed
+        self._files_changed = files_changed
+
+    def objects_removed(self):
+        """Paths of objects removed in synchronization.
+
+        The paths are state internal paths.
+        """
+        return self._objects_removed
+    
+    def objects_changed(self):
+        """Paths of objects added or changed in synchronization.
+
+        The paths are state internal paths.
+        """
+        return self._objects_changed
+    
+    def files_removed(self):
+        """Paths of files removed in synchronization.
+
+        The paths are filesystem paths (py.path objects)
+        """
+        return self._files_removed
+    
+    def files_changed(self):
+        """The paths of files added or changed in synchronization.
+
+        The paths are filesystem paths (py.path objects)
+        """
+        return self._files_changed



More information about the Checkins mailing list