Back to index

plone3  3.1.7
Version.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
00004 # 
00005 # This software is subject to the provisions of the Zope Public License,
00006 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
00007 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00008 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00009 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00010 # FOR A PARTICULAR PURPOSE
00011 # 
00012 ##############################################################################
00013 
00014 __version__='$Revision: 1.11 $'[11:-2]
00015 
00016 import tempfile
00017 import time
00018 from cStringIO import StringIO
00019 from cPickle import Pickler, Unpickler
00020 
00021 from Acquisition import Implicit, aq_parent, aq_inner, aq_base
00022 from Globals import InitializeClass, Persistent
00023 from AccessControl import ClassSecurityInfo
00024 from BTrees.OOBTree import OOBTree
00025 from OFS.SimpleItem import SimpleItem
00026 
00027 from Utility import VersionControlError
00028 from nonversioned import listNonVersionedObjects, removeNonVersionedData
00029 
00030 
00031 def cloneByPickle(obj, ignore_list=()):
00032     """Makes a copy of a ZODB object, loading ghosts as needed.
00033 
00034     Ignores specified objects along the way, replacing them with None
00035     in the copy.
00036     """
00037     ignore_dict = {}
00038     for o in ignore_list:
00039         ignore_dict[id(o)] = o
00040 
00041     def persistent_id(ob, ignore_dict=ignore_dict):
00042         if ignore_dict.has_key(id(ob)):
00043             return 'ignored'
00044         if getattr(ob, '_p_changed', 0) is None:
00045             ob._p_changed = 0
00046         return None
00047 
00048     def persistent_load(ref):
00049         assert ref == 'ignored'
00050         # Return a placeholder object that will be replaced by
00051         # removeNonVersionedData().
00052         placeholder = SimpleItem()
00053         placeholder.id = "ignored_subobject"
00054         return placeholder
00055 
00056     stream = StringIO()
00057     p = Pickler(stream, 1)
00058     p.persistent_id = persistent_id
00059     p.dump(obj)
00060     stream.seek(0)
00061     u = Unpickler(stream)
00062     u.persistent_load = persistent_load
00063     return u.load()
00064 
00065 
00066 class Version(Implicit, Persistent):
00067     """A Version is a resource that contains a copy of a particular state
00068        (content and dead properties) of a version-controlled resource.  A
00069        version is created by checking in a checked-out resource. The state
00070        of a version of a version-controlled resource never changes."""
00071 
00072     def __init__(self, version_id, obj):
00073         self.id = version_id
00074         self.date_created = time.time()
00075         self._data = None
00076 
00077     # These attributes are set by the createVersion method of the version
00078     # history at the time the version is created. The branch is the name
00079     # of the branch on which the version was created. The prev attribute
00080     # is the version id of the predecessor to this version. The next attr
00081     # is a sequence of version ids of the successors to this version.
00082     branch = 'mainline'
00083     prev = None
00084     next = ()
00085 
00086     security = ClassSecurityInfo()
00087 
00088     security.declarePublic('getId')
00089     def getId(self):
00090         return self.id
00091 
00092     security.declarePrivate('saveState')
00093     def saveState(self, obj):
00094         """Save the state of object as the state for this version of
00095            a version-controlled resource."""
00096         self._data = self.stateCopy(obj, self)
00097 
00098     security.declarePrivate('copyState')
00099     def copyState(self):
00100         """Return an independent deep copy of the state of the version."""
00101         data = self.__dict__.get('_data')  # Avoid __of__ hooks
00102         return self.stateCopy(data, self)
00103 
00104     security.declarePrivate('stateCopy')
00105     def stateCopy(self, obj, container):
00106         """Get a deep copy of the state of an object.
00107 
00108         Breaks any database identity references.
00109         """
00110         ignore = listNonVersionedObjects(obj)
00111         res = cloneByPickle(aq_base(obj), ignore)
00112         removeNonVersionedData(res)
00113         return res
00114 
00115 
00116 InitializeClass(Version)