[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/versioncontrol/ generate interesting events for version control operations

Fred L. Drake, Jr. fdrake at gmail.com
Mon Jun 27 17:52:14 EDT 2005


Log message for revision 30938:
  generate interesting events for version control operations

Changed:
  U   Zope3/trunk/src/zope/app/versioncontrol/README.txt
  A   Zope3/trunk/src/zope/app/versioncontrol/event.py
  U   Zope3/trunk/src/zope/app/versioncontrol/interfaces.py
  U   Zope3/trunk/src/zope/app/versioncontrol/repository.py
  U   Zope3/trunk/src/zope/app/versioncontrol/tests.py

-=-
Modified: Zope3/trunk/src/zope/app/versioncontrol/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/versioncontrol/README.txt	2005-06-27 17:46:06 UTC (rev 30937)
+++ Zope3/trunk/src/zope/app/versioncontrol/README.txt	2005-06-27 21:52:14 UTC (rev 30938)
@@ -64,6 +64,9 @@
     ...     # Method from IPhysicallyLocatable that is actually used:
     ...     def getPath(self):
     ...         return '/' + self.__name__
+    ...
+    ...     def __repr__(self):
+    ...         return "<%s object>" % self.__class__.__name__
 
     >>> component.provideAdapter(
     ...     zope.app.annotation.attribute.AttributeAnnotations)
@@ -127,10 +130,21 @@
     >>> import zope.security.management
     >>> zope.security.management.newInteraction(participation)
 
+Let's register some subscribers so we can check that interesting
+events are being fired for version control actions:
+
+    >>> def showEvent(label, object, event):
+    ...     print label, "for", object
+
+    >>> component.provideHandler(
+    ...     (lambda ob, evt: showEvent("applied version control", ob, evt)),
+    ...     (interface.Interface, interfaces.IVersionControlApplied))
+
 Now, let's put an object under version control and verify that we can
 determine that fact by checking against the interface:
 
     >>> repository.applyVersionControl(samp)
+    applied version control to <Sample object>
     >>> interfaces.IVersioned.providedBy(samp)
     True
     >>> transaction.commit()
@@ -175,6 +189,7 @@
 `IRepository` to return the most recent version on the main branch.
 
     >>> ob = repository.getVersionOfResource(info.history_id, 'mainline')
+    retrieved <Sample object>, version 1
     >>> type(ob)
     <class 'zope.app.versioncontrol.README.Sample'>
     >>> ob is samp
@@ -201,8 +216,10 @@
 Now, let's check out the object and add an attribute:
 
     >>> repository.checkoutResource(ob)
+    checked out <Sample object>, version 1
     >>> ob.value = 42
     >>> repository.checkinResource(ob)
+    checked in <Sample object>, version 2
     >>> transaction.commit()
 
 We can now compare information about the updated version with the
@@ -219,8 +236,10 @@
 
     >>> o1 = repository.getVersionOfResource(orig_history_id,
     ...                                      orig_version_id)
+    retrieved <Sample object>, version 1
     >>> o2 = repository.getVersionOfResource(orig_history_id,
     ...                                      newinfo.version_id)
+    retrieved <Sample object>, version 2
     >>> o1.value
     Traceback (most recent call last):
       ...
@@ -255,7 +274,9 @@
 repository.
 
     >>> repository.updateResource(samp)
+    updated <Sample object> from version 1 to 2
     >>> repository.checkoutResource(samp)
+    checked out <Sample object>, version 2
     >>> transaction.commit()
 
     >>> repository.isResourceChanged(samp)
@@ -275,9 +296,11 @@
 message argument; we'll see later how this can be used.
 
     >>> repository.checkinResource(samp, 'sample checkin')
+    checked in <Sample object>, version 3
     >>> transaction.commit()
 
     >>> repository.checkoutResource(samp)
+    checked out <Sample object>, version 3
     >>> transaction.commit()
 
     >>> repository.isResourceUpToDate(samp)
@@ -301,6 +324,7 @@
     >>> repository.isResourceChanged(samp)
     True
     >>> repository.uncheckoutResource(samp)
+    reverted <Sample object> to version 3
     >>> transaction.commit()
 
     >>> samp.value
@@ -315,12 +339,14 @@
 of an object:
 
     >>> ob = repository.getVersionOfResource(orig_history_id, orig_version_id)
+    retrieved <Sample object>, version 1
     >>> ob.__name__ = "foo"
     >>> repository.isResourceUpToDate(ob)
     False
     >>> repository.getVersionInfo(ob).version_id
     '1'
     >>> repository.updateResource(ob, version_id)
+    updated <Sample object> from version 1 to 3
     >>> repository.getVersionInfo(ob).version_id == version_id
     True
     >>> ob.value
@@ -361,7 +387,9 @@
 repository:
 
     >>> repository.labelResource(samp, 'my-first-label')
+    created label my-first-label from version 3 of <Sample object>
     >>> repository.labelResource(samp, 'my-second-label')
+    created label my-second-label from version 3 of <Sample object>
 
 The list of labels assigned to some version of an object can be
 retrieved using the repository's `getLabelsForResource()` method:
@@ -381,6 +409,7 @@
     >>> repository.getVersionInfo(samp).version_id
     '3'
     >>> ob = repository.getVersionOfResource(orig_history_id, 'my-first-label')
+    retrieved <Sample object>, version 3
     >>> repository.getVersionInfo(ob).version_id
     '3'
 
@@ -388,6 +417,7 @@
 only when this is specifically indicated as allowed:
 
     >>> ob = repository.getVersionOfResource(orig_history_id, orig_version_id)
+    retrieved <Sample object>, version 1
     >>> ob.__name__ = "bar"
     >>> repository.labelResource(ob, 'my-second-label')
     ... # doctest: +NORMALIZE_WHITESPACE
@@ -397,12 +427,14 @@
     with a version.
 
     >>> repository.labelResource(ob, 'my-second-label', force=True)
+    created label my-second-label from version 1 of <Sample object>
 
 Labels can also be used to update an object to a specific version:
 
     >>> repository.getVersionInfo(ob).version_id
     '1'
     >>> repository.updateResource(ob, 'my-first-label')
+    updated <Sample object> from version 1 to 3
     >>> repository.getVersionInfo(ob).version_id
     '3'
     >>> ob.value
@@ -417,6 +449,7 @@
 it is up-to-date or changed is based on the version it was updated to.
 
     >>> repository.updateResource(samp, orig_version_id)
+    updated <Sample object> from version 3 to 1
     >>> transaction.commit()
 
     >>> samp.value
@@ -532,6 +565,7 @@
 for revision 2:
 
     >>> obranch = repository.getVersionOfResource(orig_history_id, '2')
+    retrieved <Sample object>, version 2
     >>> obranch.__name__ = "obranch"
     >>> root["obranch"] = obranch
     >>> repository.getVersionInfo(obranch).version_id
@@ -540,6 +574,7 @@
 Now we can use this object to make a branch:
 
     >>> repository.makeBranch(obranch)
+    created branch 2.1 from version 2 of <Sample object>
     '2.1'
 
 The `makeBranch` method returns the new branch name.  This is needed
@@ -549,7 +584,9 @@
 object on the branch:
 
     >>> repository.updateResource(obranch, '2.1')
+    updated <Sample object> from version 2 to 2
     >>> repository.checkoutResource(obranch)
+    checked out <Sample object>, version 2
 
     >>> repository.getVersionInfo(obranch).version_id
     '2'
@@ -560,6 +597,7 @@
     >>> obranch.value = 100
 
     >>> repository.checkinResource(obranch)
+    checked in <Sample object>, version 2.1.1
     >>> transaction.commit()
 
     >>> repository.getVersionInfo(obranch).version_id
@@ -642,6 +680,7 @@
 Let's apply version control to the container:
 
     >>> repository.applyVersionControl(box)
+    applied version control to <SampleContainer object>
 
 We'll start by showing some basics of how the INonVersionedData
 interface is used.  
@@ -721,12 +760,14 @@
 revisions in the repository:
 
     >>> repository.checkoutResource(box)
+    checked out <SampleContainer object>, version 1
     >>> transaction.commit()
     >>> version_id = repository.getVersionInfo(box).version_id
 
     >>> box.aList.append(4)
     >>> box.bob_list.append(0)
     >>> repository.checkinResource(box)
+    checked in <SampleContainer object>, version 2
     >>> transaction.commit()
 
     >>> box.aList
@@ -735,6 +776,7 @@
     [3, 2, 1, 0]
 
     >>> repository.updateResource(box, version_id)
+    updated <SampleContainer object> from version 2 to 1
     >>> box.aList
     [1, 2, 3]
     >>> box.bob_list

Added: Zope3/trunk/src/zope/app/versioncontrol/event.py
===================================================================
--- Zope3/trunk/src/zope/app/versioncontrol/event.py	2005-06-27 17:46:06 UTC (rev 30937)
+++ Zope3/trunk/src/zope/app/versioncontrol/event.py	2005-06-27 21:52:14 UTC (rev 30938)
@@ -0,0 +1,114 @@
+"""Events for version control.
+
+"""
+__docformat__ = "reStructuredText"
+
+import zope.interface
+
+import zope.app.event.objectevent
+import zope.app.versioncontrol.interfaces
+
+
+class VersionEvent(zope.app.event.objectevent.ObjectEvent):
+
+    def __init__(self, object, info):
+        super(VersionEvent, self).__init__(object)
+        self.info = info
+
+
+class VersionControlApplied(VersionEvent):
+
+    zope.interface.implements(
+        zope.app.versioncontrol.interfaces.IVersionControlApplied)
+
+    def __init__(self, object, info, message):
+        super(VersionControlApplied, self).__init__(object, info)
+        self.message = message
+
+    def __str__(self):
+        s = "applied version control to %s" % self.object
+        if self.message:
+            s = "%s:\n%s" % (s, self.message)
+        return s
+
+
+class VersionCheckedOut(VersionEvent):
+
+    zope.interface.implements(
+        zope.app.versioncontrol.interfaces.IVersionCheckedOut)
+
+    def __str__(self):
+        return "checked out %s, version %s" % (
+            self.object, self.info.version_id)
+
+
+class VersionCheckedIn(VersionEvent):
+
+    zope.interface.implements(
+        zope.app.versioncontrol.interfaces.IVersionCheckedIn)
+
+    def __str__(self):
+        return "checked in %s, version %s" % (
+            self.object, self.info.version_id)
+
+
+class VersionReverted(VersionEvent):
+
+    zope.interface.implements(
+        zope.app.versioncontrol.interfaces.IVersionReverted)
+
+    def __str__(self):
+        return "reverted %s to version %s" % (
+            self.object, self.info.version_id)
+
+
+class VersionUpdated(VersionEvent):
+
+    zope.interface.implements(
+        zope.app.versioncontrol.interfaces.IVersionReverted)
+
+    def __init__(self, object, info, old_version_id):
+        super(VersionUpdated, self).__init__(object, info)
+        self.old_version_id = old_version_id
+
+    def __str__(self):
+        return "updated %s from version %s to %s" % (
+            self.object, self.old_version_id, self.info.version_id)
+
+
+class VersionRetrieved(VersionEvent):
+
+    zope.interface.implements(
+        zope.app.versioncontrol.interfaces.IVersionRetrieved)
+
+    def __str__(self):
+        return "retrieved %s, version %s" % (
+            self.object, self.info.version_id)
+
+
+class VersionLabelled(VersionEvent):
+
+    zope.interface.implements(
+        zope.app.versioncontrol.interfaces.IVersionLabelled)
+
+    def __init__(self, object, info, label):
+        super(VersionLabelled, self).__init__(object, info)
+        self.label = label
+
+    def __str__(self):
+        return "created label %s from version %s of %s" % (
+            self.label, self.info.version_id, self.object)
+
+
+class BranchCreated(VersionEvent):
+
+    zope.interface.implements(
+        zope.app.versioncontrol.interfaces.IVersionReverted)
+
+    def __init__(self, object, info, branch_id):
+        super(BranchCreated, self).__init__(object, info)
+        self.branch_id = branch_id
+
+    def __str__(self):
+        return "created branch %s from version %s of %s" % (
+            self.branch_id, self.info.version_id, self.object)


Property changes on: Zope3/trunk/src/zope/app/versioncontrol/event.py
___________________________________________________________________
Name: svn:mime-type
   + text/x-python
Name: svn:eol-style
   + native

Modified: Zope3/trunk/src/zope/app/versioncontrol/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/app/versioncontrol/interfaces.py	2005-06-27 17:46:06 UTC (rev 30937)
+++ Zope3/trunk/src/zope/app/versioncontrol/interfaces.py	2005-06-27 21:52:14 UTC (rev 30938)
@@ -23,6 +23,7 @@
 from zope.schema.vocabulary import SimpleVocabulary
 
 import zope.app.annotation.interfaces
+import zope.app.event.interfaces
 
 from zope.i18nmessageid import MessageIDFactory
 _ = MessageIDFactory('zope.app.versioncontrol')
@@ -299,3 +300,64 @@
 
 class IVersioned(IVersionable):
     """Version control is in effect for this object."""
+
+
+# Events that are raised for interesting occurances:
+
+class IVersionEvent(zope.app.event.interfaces.IObjectEvent):
+    """Base interface for all version-control events."""
+
+class IVersionControlApplied(IVersionEvent):
+    """Event fired when version control is initially applied to an object."""
+
+    message = zope.schema.Text(
+        title=_("Message"),
+        description=_("Message text passed to applyVersionControl()"
+                      " for the object."),
+        )
+
+    info = zope.interface.Attribute(
+        "VersionInfo object reflecting the action.")
+
+
+class IVersionCheckedIn(IVersionEvent):
+    """Event fired when an object is checked in."""
+
+
+class IVersionCheckedOut(IVersionEvent):
+    """Event fired when an object is checked out."""
+
+
+class IVersionReverted(IVersionEvent):
+    """Event fired when a checked-out object is reverted.
+
+    (Fired by the uncheckoutResource() repository method.)
+    """
+
+
+class IVersionUpdated(IVersionEvent):
+    """Event fired when an object is updated to the latest version."""
+
+
+class IVersionRetrieved(IVersionEvent):
+    """Event fired when a versioned object is retrieved from the repository."""
+
+
+class IVersionLabelled(IVersionEvent):
+    """Event fired when a label is attached to a version."""
+
+    # TODO: should be ASCIILine
+    label = zope.schema.ASCII(
+        title=_("Label"),
+        description=_("Label applied to the version."),
+        )
+
+
+class IBranchCreated(IVersionEvent):
+    """Event fired when a new branch is created."""
+
+    # TODO: should be ASCIILine
+    branch_id = zope.schema.ASCII(
+        title=_("Branch Id"),
+        description=_("Identifier for the new branch."),
+        )

Modified: Zope3/trunk/src/zope/app/versioncontrol/repository.py
===================================================================
--- Zope3/trunk/src/zope/app/versioncontrol/repository.py	2005-06-27 17:46:06 UTC (rev 30937)
+++ Zope3/trunk/src/zope/app/versioncontrol/repository.py	2005-06-27 21:52:14 UTC (rev 30938)
@@ -23,6 +23,7 @@
 from BTrees.OOBTree import OOBTree
 from BTrees.OIBTree import OIBTree
 
+import zope.event
 import zope.interface
 
 from zope.app import datetimeutils
@@ -30,6 +31,7 @@
 
 from zope.app.annotation.interfaces import IAnnotations
 
+from zope.app.versioncontrol import event
 from zope.app.versioncontrol.history import VersionHistory
 from zope.app.versioncontrol.interfaces import VersionControlError
 from zope.app.versioncontrol.interfaces import IVersionable, IVersioned
@@ -195,6 +197,8 @@
                             message is None and 'Initial checkin.' or message
                             )
 
+        zope.event.notify(event.VersionControlApplied(object, info, message))
+
     def checkoutResource(self, object):
         info = self.getVersionInfo(object)
         if info.status != CHECKED_IN:
@@ -227,6 +231,8 @@
         info.status = CHECKED_OUT
         info.touch()
 
+        zope.event.notify(event.VersionCheckedOut(object, info))
+
     def checkinResource(self, object, message=''):
         info = self.getVersionInfo(object)
         if info.status != CHECKED_OUT:
@@ -267,6 +273,8 @@
         info.status = CHECKED_IN
         info.touch()
 
+        zope.event.notify(event.VersionCheckedIn(object, info))
+
     def uncheckoutResource(self, object):
         info = self.getVersionInfo(object)
         if info.status != CHECKED_OUT:
@@ -294,6 +302,8 @@
         annotations = IAnnotations(object)
         annotations[VERSION_INFO_KEY] = info
 
+        zope.event.notify(event.VersionReverted(object, info))
+
     def updateResource(self, object, selector=None):
         info = self.getVersionInfo(object)
         if info.status != CHECKED_IN:
@@ -302,6 +312,7 @@
                 )
 
         history = self.getVersionHistory(info.history_id)
+        oldversion = info.version_id
         version = None
         sticky = info.sticky
 
@@ -373,6 +384,8 @@
         annotations = IAnnotations(object)
         annotations[VERSION_INFO_KEY] = info
 
+        zope.event.notify(event.VersionUpdated(object, info, oldversion))
+
     def labelResource(self, object, label, force=0):
         info = self.getVersionInfo(object)
         if info.status != CHECKED_IN:
@@ -391,6 +404,8 @@
         history = self.getVersionHistory(info.history_id)
         history.labelVersion(info.version_id, label, force)
 
+        zope.event.notify(event.VersionLabelled(object, info, label))
+
     def makeBranch(self, object, branch_id=None):
         # Note - this is not part of the official version control API yet.
         # It is here to allow unit testing of the architectural aspects
@@ -431,6 +446,8 @@
 
         history.createBranch(branch_id, info.version_id)
 
+        zope.event.notify(event.BranchCreated(object, info, branch_id))
+
         return branch_id
 
     def getVersionOfResource(self, history_id, selector):
@@ -471,6 +488,8 @@
         annotations = IAnnotations(object)
         annotations[VERSION_INFO_KEY] = info
 
+        zope.event.notify(event.VersionRetrieved(object, info))
+
         return object
 
     def getVersionIds(self, object):

Modified: Zope3/trunk/src/zope/app/versioncontrol/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/versioncontrol/tests.py	2005-06-27 17:46:06 UTC (rev 30937)
+++ Zope3/trunk/src/zope/app/versioncontrol/tests.py	2005-06-27 21:52:14 UTC (rev 30938)
@@ -23,6 +23,9 @@
 from zope.component.tests.placelesssetup import PlacelessSetup
 from zope.testing import doctest, module
 from transaction import abort
+
+import zope.event
+
 import zope.app.annotation.interfaces
 import zope.app.annotation.attribute
 import zope.app.location
@@ -37,6 +40,7 @@
 def setUp(test):
     ps.setUp()
     module.setUp(test, name)
+    zope.event.subscribers.append(eventHandler)
 
 def tearDown(test):
     module.tearDown(test, name)
@@ -45,8 +49,13 @@
     if db is not None:
         db.close()
     ps.tearDown()
+    if eventHandler in zope.event.subscribers:
+        zope.event.subscribers.remove(eventHandler)
 
+def eventHandler(event):
+    print event
 
+
 class L(persistent.Persistent, zope.app.location.Location):
     interface.implements(interfaces.IVersionable,
                          zope.app.annotation.interfaces.IAttributeAnnotatable,



More information about the Zope3-Checkins mailing list