provide basic versioning API for resources
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1654 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
53810c1a19
commit
c35d7fab4e
14 changed files with 492 additions and 7 deletions
|
@ -5,6 +5,8 @@
|
||||||
xmlns="http://namespaces.zope.org/browser"
|
xmlns="http://namespaces.zope.org/browser"
|
||||||
i18n_domain="zope">
|
i18n_domain="zope">
|
||||||
|
|
||||||
|
<resource name="loops_logo.jpg" file="loops_logo.jpg" />
|
||||||
|
|
||||||
<!-- Flash user interface -->
|
<!-- Flash user interface -->
|
||||||
|
|
||||||
<page
|
<page
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<html tal:define="dummy view/setHeaders;
|
<html tal:define="dummy view/setHeaders;
|
||||||
hostURL view/loopsUrl;
|
hostURL view/loopsUrl;
|
||||||
movie context/++resource++loops.swf">
|
logoURL context/++resource++loops_logo.jpg;
|
||||||
|
movie context/++resource++loops.swf;
|
||||||
|
">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>loops</title>
|
<title>loops</title>
|
||||||
|
@ -24,7 +26,7 @@
|
||||||
<param name=quality value=high>
|
<param name=quality value=high>
|
||||||
<param name="wmode" value="opaque">
|
<param name="wmode" value="opaque">
|
||||||
<embed src="loops.swf?hostURL=http://z3.loops.cy55.de/loopsdms/cq/"
|
<embed src="loops.swf?hostURL=http://z3.loops.cy55.de/loopsdms/cq/"
|
||||||
tal:attributes="src string:$movie?hostURL=$hostURL/"
|
tal:attributes="src string:$movie?hostURL=$hostURL/&logoURL=$logoURL"
|
||||||
quality=high
|
quality=high
|
||||||
width="960" height="680" name="scorm" align=""
|
width="960" height="680" name="scorm" align=""
|
||||||
wmode="opaque"
|
wmode="opaque"
|
||||||
|
|
BIN
browser/flash/loops_logo.jpg
Normal file
BIN
browser/flash/loops_logo.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
|
@ -431,6 +431,7 @@
|
||||||
<include package=".knowledge" />
|
<include package=".knowledge" />
|
||||||
<include package=".organize" />
|
<include package=".organize" />
|
||||||
<include package=".process" />
|
<include package=".process" />
|
||||||
|
<include package=".versioning" />
|
||||||
<include package=".search" />
|
<include package=".search" />
|
||||||
<include package=".browser" />
|
<include package=".browser" />
|
||||||
<include package=".xmlrpc" />
|
<include package=".xmlrpc" />
|
||||||
|
|
|
@ -147,6 +147,7 @@ class Resource(Image, Contained):
|
||||||
def getClients(self, relationships=None):
|
def getClients(self, relationships=None):
|
||||||
if relationships is None:
|
if relationships is None:
|
||||||
relationships = [TargetRelation]
|
relationships = [TargetRelation]
|
||||||
|
# Versioning: obj = IVersionable(self).master
|
||||||
rels = getRelations(second=self, relationships=relationships)
|
rels = getRelations(second=self, relationships=relationships)
|
||||||
return [r.first for r in rels]
|
return [r.first for r in rels]
|
||||||
|
|
||||||
|
|
68
versioning/README.txt
Normal file
68
versioning/README.txt
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
===============================================================
|
||||||
|
loops - Linked Objects for Organization and Processing Services
|
||||||
|
===============================================================
|
||||||
|
|
||||||
|
Managing versions of resources.
|
||||||
|
|
||||||
|
($Id$)
|
||||||
|
|
||||||
|
|
||||||
|
Setting up a loops Site and Utilities
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
Let's do some basic set up
|
||||||
|
|
||||||
|
>>> from zope import component, interface
|
||||||
|
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
|
||||||
|
>>> site = placefulSetUp(True)
|
||||||
|
|
||||||
|
and build a simple loops site with a concept manager and some concepts
|
||||||
|
(with a relation registry, a catalog, and all the type machinery - what
|
||||||
|
in real life is done via standard ZCML setup or via local utility
|
||||||
|
configuration):
|
||||||
|
|
||||||
|
>>> from loops.versioning.testsetup import TestSite
|
||||||
|
>>> t = TestSite(site)
|
||||||
|
>>> concepts, resources, views = t.setup()
|
||||||
|
|
||||||
|
>>> #sorted(concepts)
|
||||||
|
>>> #sorted(resources)
|
||||||
|
>>> len(concepts) + len(resources)
|
||||||
|
24
|
||||||
|
|
||||||
|
|
||||||
|
Version Information
|
||||||
|
===================
|
||||||
|
|
||||||
|
>>> from loops.versioning.interfaces import IVersionable
|
||||||
|
>>> from loops.versioning.versionable import VersionableResource
|
||||||
|
>>> component.provideAdapter(VersionableResource)
|
||||||
|
|
||||||
|
We can access versioning information for an object by using an IVersionable
|
||||||
|
adapter on the object.
|
||||||
|
|
||||||
|
>>> d001 = resources['d001.txt']
|
||||||
|
>>> vD001 = IVersionable(d001)
|
||||||
|
|
||||||
|
If there aren't any versions associated with the object we get the default
|
||||||
|
values:
|
||||||
|
|
||||||
|
>>> vD001.master is d001
|
||||||
|
True
|
||||||
|
>>> vD001.versionId
|
||||||
|
'1.1'
|
||||||
|
>>> vD001.versions
|
||||||
|
{}
|
||||||
|
>>> vD001.currentVersion is d001
|
||||||
|
True
|
||||||
|
>>> vD001.releasedVersion is d001
|
||||||
|
True
|
||||||
|
|
||||||
|
Now we can create a new version for our document:
|
||||||
|
|
||||||
|
>>> d001v1_1 = vD001.createVersion()
|
||||||
|
>>> sorted(resources)
|
||||||
|
|
||||||
|
>>> vD001v1_1 = IVersionable(d001v1_1)
|
||||||
|
>>> vD001v1_1.versionId
|
||||||
|
'1.2'
|
4
versioning/__init__.py
Normal file
4
versioning/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
"""
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
19
versioning/configure.zcml
Normal file
19
versioning/configure.zcml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<!-- $Id$ -->
|
||||||
|
|
||||||
|
<configure
|
||||||
|
xmlns:zope="http://namespaces.zope.org/zope"
|
||||||
|
xmlns:browser="http://namespaces.zope.org/browser"
|
||||||
|
i18n_domain="zope"
|
||||||
|
>
|
||||||
|
|
||||||
|
<zope:adapter factory="loops.versioning.versionable.VersionableResource"
|
||||||
|
trusted="True" />
|
||||||
|
|
||||||
|
<zope:class class="loops.versioning.versionable.VersionableResource">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="loops.versioning.interfaces.IVersionable" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="loops.versioning.interfaces.IVersionable" />
|
||||||
|
</zope:class>
|
||||||
|
|
||||||
|
</configure>
|
70
versioning/interfaces.py
Normal file
70
versioning/interfaces.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Versioning interfaces.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.interface import Interface, Attribute
|
||||||
|
from zope import interface, component, schema
|
||||||
|
|
||||||
|
|
||||||
|
class IVersionable(Interface):
|
||||||
|
""" An object that may exist in different versions.
|
||||||
|
"""
|
||||||
|
|
||||||
|
versionNumbers = Attribute(u'A tuple of version numbers for the context '
|
||||||
|
'object, with a number for each level')
|
||||||
|
|
||||||
|
variantIds = Attribute(u'A tuple of variant IDs (e.g. for language '
|
||||||
|
'varuants) for the context object')
|
||||||
|
|
||||||
|
versionId = Attribute(u'A string identifying this version, e.g. 1.1_de, '
|
||||||
|
'derived from versionNumbers and variantIds')
|
||||||
|
|
||||||
|
master = Attribute(u'The object (master version) that should be used for access to '
|
||||||
|
'version-independent attributes and central '
|
||||||
|
'versioning metadata')
|
||||||
|
|
||||||
|
# attributes taken from the master version:
|
||||||
|
|
||||||
|
versions = Attribute(u'A dictionary of all versions of this object')
|
||||||
|
|
||||||
|
currentVersion = Attribute(u'The default version to be used for editing')
|
||||||
|
|
||||||
|
releasedVersion = Attribute(u'The default version to be used for viewing')
|
||||||
|
|
||||||
|
def createVersion(level=1):
|
||||||
|
""" Create a copy of the context object as a new version and return it.
|
||||||
|
|
||||||
|
The level of the version says if it is a minor (1) or major (0)
|
||||||
|
version. (It would even be possible to have more than two levels.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def createVariant(id, level=0):
|
||||||
|
""" Create a copy of the context object as a new variant and return it.
|
||||||
|
|
||||||
|
The level provides the position in the variantIds tuple.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class IVersionInfo(Interface):
|
||||||
|
""" Versioning metadata, e.g. criteria for version selection.
|
||||||
|
"""
|
23
versioning/tests.py
Executable file
23
versioning/tests.py
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
# $Id$
|
||||||
|
|
||||||
|
import unittest, doctest
|
||||||
|
from zope.testing.doctestunit import DocFileSuite
|
||||||
|
from zope.interface.verify import verifyClass
|
||||||
|
from loops.versioning import versioninfo
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
"Basic tests for the expert sub-package."
|
||||||
|
|
||||||
|
def testSomething(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_suite():
|
||||||
|
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
|
||||||
|
return unittest.TestSuite((
|
||||||
|
unittest.makeSuite(Test),
|
||||||
|
DocFileSuite('README.txt', optionflags=flags),
|
||||||
|
))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main(defaultTest='test_suite')
|
98
versioning/testsetup.py
Normal file
98
versioning/testsetup.py
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
"""
|
||||||
|
Set up a loops site for testing.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope import component
|
||||||
|
from zope.app.catalog.catalog import Catalog
|
||||||
|
from zope.app.catalog.interfaces import ICatalog
|
||||||
|
from zope.app.catalog.field import FieldIndex
|
||||||
|
from zope.app.catalog.text import TextIndex
|
||||||
|
|
||||||
|
from cybertools.relation.tests import IntIdsStub
|
||||||
|
from cybertools.relation.registry import RelationRegistry
|
||||||
|
from cybertools.relation.interfaces import IRelationRegistry
|
||||||
|
from cybertools.relation.registry import IndexableRelationAdapter
|
||||||
|
from cybertools.typology.interfaces import IType
|
||||||
|
|
||||||
|
from loops import Loops
|
||||||
|
from loops import util
|
||||||
|
from loops.interfaces import IIndexAttributes
|
||||||
|
from loops.concept import Concept
|
||||||
|
from loops.concept import IndexAttributes as ConceptIndexAttributes
|
||||||
|
from loops.resource import Resource
|
||||||
|
from loops.resource import IndexAttributes as ResourceIndexAttributes
|
||||||
|
from loops.knowledge.setup import SetupManager as KnowledgeSetupManager
|
||||||
|
from loops.setup import SetupManager, addObject
|
||||||
|
from loops.type import ConceptType, ResourceType, TypeConcept
|
||||||
|
|
||||||
|
|
||||||
|
class TestSite(object):
|
||||||
|
|
||||||
|
def __init__(self, site):
|
||||||
|
self.site = site
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
site = self.site
|
||||||
|
|
||||||
|
component.provideUtility(IntIdsStub())
|
||||||
|
relations = RelationRegistry()
|
||||||
|
relations.setupIndexes()
|
||||||
|
component.provideUtility(relations, IRelationRegistry)
|
||||||
|
component.provideAdapter(IndexableRelationAdapter)
|
||||||
|
|
||||||
|
component.provideAdapter(ConceptType)
|
||||||
|
component.provideAdapter(ResourceType)
|
||||||
|
component.provideAdapter(TypeConcept)
|
||||||
|
|
||||||
|
catalog = Catalog()
|
||||||
|
component.provideUtility(catalog, ICatalog)
|
||||||
|
|
||||||
|
catalog['loops_title'] = TextIndex('title', IIndexAttributes, True)
|
||||||
|
catalog['loops_text'] = TextIndex('text', IIndexAttributes, True)
|
||||||
|
catalog['loops_type'] = FieldIndex('tokenForSearch', IType, False)
|
||||||
|
|
||||||
|
loopsRoot = site['loops'] = Loops()
|
||||||
|
|
||||||
|
component.provideAdapter(KnowledgeSetupManager, name='knowledge')
|
||||||
|
setup = SetupManager(loopsRoot)
|
||||||
|
concepts, resources, views = setup.setup()
|
||||||
|
|
||||||
|
component.provideAdapter(ConceptIndexAttributes)
|
||||||
|
component.provideAdapter(ResourceIndexAttributes)
|
||||||
|
|
||||||
|
tType = concepts.getTypeConcept()
|
||||||
|
tDomain = concepts['domain']
|
||||||
|
tTextDocument = concepts['textdocument']
|
||||||
|
|
||||||
|
tCustomer = addObject(concepts, Concept, 'customer', title=u'Customer',
|
||||||
|
type=tType)
|
||||||
|
dProjects = addObject(concepts, Concept, 'projects',
|
||||||
|
title=u'Project Domain', type=tDomain)
|
||||||
|
tCustomer.assignParent(dProjects)
|
||||||
|
|
||||||
|
cust1 = addObject(concepts, Concept, 'cust1',
|
||||||
|
title=u'Customer 1', type=tCustomer)
|
||||||
|
cust2 = addObject(concepts, Concept, 'cust2',
|
||||||
|
title=u'Customer 2', type=tCustomer)
|
||||||
|
cust3 = addObject(concepts, Concept, 'cust3',
|
||||||
|
title=u'Customer 3', type=tCustomer)
|
||||||
|
d001 = addObject(resources, Resource, 'd001.txt',
|
||||||
|
title=u'Doc 001', type=tTextDocument)
|
||||||
|
d001.assignConcept(cust1)
|
||||||
|
d002 = addObject(resources, Resource, 'd002.txt',
|
||||||
|
title=u'Doc 002', type=tTextDocument)
|
||||||
|
d002.assignConcept(cust3)
|
||||||
|
d003 = addObject(resources, Resource, 'd003.txt',
|
||||||
|
title=u'Doc 003', type=tTextDocument)
|
||||||
|
d003.assignConcept(cust1)
|
||||||
|
|
||||||
|
for c in concepts.values():
|
||||||
|
catalog.index_doc(int(util.getUidForObject(c)), c)
|
||||||
|
for r in resources.values():
|
||||||
|
catalog.index_doc(int(util.getUidForObject(r)), r)
|
||||||
|
|
||||||
|
return concepts, resources, views
|
||||||
|
|
||||||
|
|
149
versioning/versionable.py
Normal file
149
versioning/versionable.py
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2007 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Utilities for managing version informations.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from BTrees.OOBTree import OOBTree
|
||||||
|
from zope.component import adapts
|
||||||
|
from zope.interface import implements
|
||||||
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
from zope.traversing.api import getName, getParent
|
||||||
|
|
||||||
|
from cybertools.text.mimetypes import extensions
|
||||||
|
from cybertools.typology.interfaces import IType
|
||||||
|
from loops.interfaces import IResource
|
||||||
|
from loops.versioning.interfaces import IVersionable
|
||||||
|
|
||||||
|
|
||||||
|
_not_found = object()
|
||||||
|
attrPattern = '__version_%s__'
|
||||||
|
|
||||||
|
|
||||||
|
class VersionableResource(object):
|
||||||
|
""" An adapter that enables a resource to store version information.
|
||||||
|
"""
|
||||||
|
|
||||||
|
implements(IVersionable)
|
||||||
|
adapts(IResource)
|
||||||
|
|
||||||
|
def __init__(self, context):
|
||||||
|
self.context = context
|
||||||
|
|
||||||
|
def getVersioningAttribute(self, attr, default):
|
||||||
|
attrName = attrPattern % attr
|
||||||
|
value = getattr(self.context, attrName, _not_found)
|
||||||
|
if value is _not_found:
|
||||||
|
return default
|
||||||
|
return value
|
||||||
|
|
||||||
|
def initVersioningAttribute(self, attr, value):
|
||||||
|
attrName = attrPattern % attr
|
||||||
|
value = getattr(self.context, attrName, _not_found)
|
||||||
|
if value is _not_found:
|
||||||
|
setattr(self.context, attrName, value)
|
||||||
|
|
||||||
|
def setVersioningAttribute(self, attr, value):
|
||||||
|
attrName = attrPattern % attr
|
||||||
|
setattr(self.context, attrName, value)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def versionNumbers(self):
|
||||||
|
return self.getVersioningAttribute('versionNumbers', (1, 1))
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def variantIds(self):
|
||||||
|
return self.getVersioningAttribute('variantIds', ())
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def versionId(self):
|
||||||
|
versionPart = '.'.join(str(n) for n in self.versionNumbers)
|
||||||
|
return '_'.join([versionPart] + list(self.variantIds))
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def master(self):
|
||||||
|
return self.getVersioningAttribute('master', self.context)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def versionableMaster(self):
|
||||||
|
""" The adapted master... """
|
||||||
|
return IVersionable(self.master)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def versions(self):
|
||||||
|
return self.versionableMaster.getVersioningAttribute('versions', {})
|
||||||
|
|
||||||
|
@property
|
||||||
|
def currentVersion(self):
|
||||||
|
return self.versionableMaster.getVersioningAttribute('currentVersion', self.master)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def releasedVersion(self):
|
||||||
|
m = self.versionableMaster
|
||||||
|
return self.versionableMaster.getVersioningAttribute('releasedVersion', self.master)
|
||||||
|
|
||||||
|
def createVersion(self, level=1):
|
||||||
|
context = self.context
|
||||||
|
versionableMaster = self.versionableMaster
|
||||||
|
# get the new version numbers
|
||||||
|
vn = list(IVersionable(self.currentVersion).versionNumbers)
|
||||||
|
while len(vn) <= level:
|
||||||
|
vn.append(1)
|
||||||
|
vn[level] += 1
|
||||||
|
# create new object
|
||||||
|
cls = context.__class__
|
||||||
|
obj = cls()
|
||||||
|
# set versioning attributes of new object
|
||||||
|
versionableObj = IVersionable(obj)
|
||||||
|
versionableObj.setVersioningAttribute('versionNumbers', tuple(vn))
|
||||||
|
versionableObj.setVersioningAttribute('variantIds', self.variantIds)
|
||||||
|
versionableObj.setVersioningAttribute('master', self.master)
|
||||||
|
# generate name for new object, register in parent
|
||||||
|
versionId = versionableObj.versionId
|
||||||
|
name = self.generateName(getName(context),
|
||||||
|
extensions.get(context.contentType, ''),
|
||||||
|
versionId)
|
||||||
|
getParent(context)[name] = obj
|
||||||
|
# set resource attributes
|
||||||
|
obj.resourceType = context.resourceType
|
||||||
|
ti = IType(context).typeInterface
|
||||||
|
if ti is not None:
|
||||||
|
adaptedContext = ti(context)
|
||||||
|
adaptedObj = ti(obj)
|
||||||
|
for attr in ti:
|
||||||
|
if attr not in ('resourceType',):
|
||||||
|
setattr(adaptedObj, attr, getattr(adaptedContext, attr))
|
||||||
|
# set attributes of the master version
|
||||||
|
versionableMaster.initVersioningAttribute('versions', OOBTree())
|
||||||
|
self.versions[versionId] = obj
|
||||||
|
versionableMaster.setVersioningAttribute('currentVersion', obj)
|
||||||
|
return obj
|
||||||
|
|
||||||
|
def generateName(self, name, ext, versionId):
|
||||||
|
if ext:
|
||||||
|
ext = '.' + ext
|
||||||
|
if ext and name.endswith(ext):
|
||||||
|
name = name[:-len(ext)]
|
||||||
|
elif len(name) > 3 and name[-4] == '.':
|
||||||
|
ext = name[-4:]
|
||||||
|
name = name[:-4]
|
||||||
|
return name + '_' + versionId + ext
|
||||||
|
|
44
versioning/versioninfo.py
Normal file
44
versioning/versioninfo.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2007 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Utilities for managing version informations.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.interface import implements
|
||||||
|
|
||||||
|
from loops.versioning.interfaces import IVersionInfo
|
||||||
|
|
||||||
|
|
||||||
|
class VersionInfo(object):
|
||||||
|
""" Collects and provides informations related to object versions.
|
||||||
|
"""
|
||||||
|
|
||||||
|
implements(IVersionInfo)
|
||||||
|
|
||||||
|
|
||||||
|
def getVersionInfo(obj, request):
|
||||||
|
""" Check if a special version should be used for the object
|
||||||
|
provided.
|
||||||
|
|
||||||
|
In addition return meta information about the object versions
|
||||||
|
so that this will not have to be retrieved later.
|
||||||
|
"""
|
||||||
|
return obj, VersionInfo()
|
14
view.py
14
view.py
|
@ -40,11 +40,12 @@ from cybertools.relation import DyadicRelation
|
||||||
from cybertools.relation.registry import getRelations
|
from cybertools.relation.registry import getRelations
|
||||||
from cybertools.relation.interfaces import IRelationRegistry, IRelatable
|
from cybertools.relation.interfaces import IRelationRegistry, IRelatable
|
||||||
|
|
||||||
from interfaces import IView, INode
|
from loops.interfaces import IView, INode
|
||||||
from interfaces import IViewManager, INodeContained
|
from loops.interfaces import IViewManager, INodeContained
|
||||||
from interfaces import ILoopsContained
|
from loops.interfaces import ILoopsContained
|
||||||
from interfaces import ITargetRelation
|
from loops.interfaces import ITargetRelation
|
||||||
from interfaces import IConcept
|
from loops.interfaces import IConcept
|
||||||
|
from loops.versioning.versioninfo import getVersionInfo
|
||||||
|
|
||||||
|
|
||||||
class View(object):
|
class View(object):
|
||||||
|
@ -202,6 +203,8 @@ class NodeTraverser(ItemTraverser):
|
||||||
else:
|
else:
|
||||||
target = self.context.target
|
target = self.context.target
|
||||||
if target is not None:
|
if target is not None:
|
||||||
|
# provide versioning info and switch to correct version if appropriate
|
||||||
|
target, versionInfo = getVersionInfo(target, request)
|
||||||
# remember self.context in request
|
# remember self.context in request
|
||||||
viewAnnotations = request.annotations.setdefault('loops.view', {})
|
viewAnnotations = request.annotations.setdefault('loops.view', {})
|
||||||
viewAnnotations['node'] = self.context
|
viewAnnotations['node'] = self.context
|
||||||
|
@ -211,6 +214,7 @@ class NodeTraverser(ItemTraverser):
|
||||||
else:
|
else:
|
||||||
# we'll use the target object in the node's context
|
# we'll use the target object in the node's context
|
||||||
viewAnnotations['target'] = target
|
viewAnnotations['target'] = target
|
||||||
|
viewAnnotations['versionInfo'] = versionInfo
|
||||||
return self.context
|
return self.context
|
||||||
return super(NodeTraverser, self).publishTraverse(request, name)
|
return super(NodeTraverser, self).publishTraverse(request, name)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue