[CMF-checkins] SVN: CMF/trunk/C CMFCore.FSPythonScript: Customized
versions now track the "original" source from which they were
customized,
and can present a diff between that version and their current source
text.
Tres Seaver
tseaver at palladion.com
Sun Jan 22 06:58:18 EST 2006
Log message for revision 41404:
CMFCore.FSPythonScript: Customized versions now track the "original" source from which they were customized, and can present a diff between that version and their current source text.
Changed:
U CMF/trunk/CHANGES.txt
U CMF/trunk/CMFCore/FSPythonScript.py
U CMF/trunk/CMFCore/tests/test_FSPythonScript.py
A CMF/trunk/CMFCore/www/cpsDiff.pt
-=-
Modified: CMF/trunk/CHANGES.txt
===================================================================
--- CMF/trunk/CHANGES.txt 2006-01-21 18:34:10 UTC (rev 41403)
+++ CMF/trunk/CHANGES.txt 2006-01-22 11:58:17 UTC (rev 41404)
@@ -2,6 +2,10 @@
New Features
+ - CMFCore.FSPythonScript: Customized versions now track the "original"
+ source from which they were customized, and can present a diff between
+ that version and their current source text.
+
- CMFDefault and CMFCalendar: Added locales directories with .pot files.
A modified i18nextract.py script from Zope 3 is used to extract
translatable strings from .py, .pt, .html and .xml files.
Modified: CMF/trunk/CMFCore/FSPythonScript.py
===================================================================
--- CMF/trunk/CMFCore/FSPythonScript.py 2006-01-21 18:34:10 UTC (rev 41403)
+++ CMF/trunk/CMFCore/FSPythonScript.py 2006-01-22 11:58:17 UTC (rev 41404)
@@ -15,6 +15,7 @@
$Id$
"""
+from difflib import unified_diff
import new
from AccessControl import ClassSecurityInfo
@@ -23,6 +24,7 @@
from Globals import DTMLFile
from Globals import InitializeClass
from OFS.Cache import Cacheable
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Products.PythonScripts.PythonScript import PythonScript
from Shared.DC.Scripts.Script import Script
@@ -43,6 +45,40 @@
co_argcount = 0
+class CustomizedPythonScript(PythonScript):
+ """ Subclass which captures the "source" version's text.
+ """
+ #meta_type = 'Customized Python Script' #(need permissions here)
+ security = ClassSecurityInfo()
+
+ def __init__(self, id, text):
+ self._setId(id)
+ self.write(text)
+ self.original_source = text
+
+ security.declareProtected(ViewManagementScreens, 'getDiff')
+ def getDiff(self):
+ """ Return a diff of the current source with the original source.
+ """
+ return unified_diff( self.original_source.splitlines()
+ , self.read().splitlines()
+ , 'original'
+ , 'modified'
+ , ''
+ , ''
+ , lineterm=""
+ )
+
+ security.declareProtected(ViewManagementScreens, 'manage_showDiff')
+ manage_showDiff = PageTemplateFile('www/cpsDiff.pt', globals())
+
+ manage_options = (PythonScript.manage_options[:1]
+ + ({'label': 'Diff', 'action': 'manage_showDiff'},)
+ + PythonScript.manage_options[1:]
+ )
+
+InitializeClass(CustomizedPythonScript)
+
class FSPythonScript (FSObject, Script):
"""FSPythonScripts act like Python Scripts but are not directly
modifiable from the management interface."""
@@ -77,8 +113,7 @@
def _createZODBClone(self):
"""Create a ZODB (editable) equivalent of this object."""
- obj = PythonScript(self.getId())
- obj.write(self.read())
+ obj = CustomizedPythonScript(self.getId(), self.read())
return obj
def _readFile(self, reparse):
Modified: CMF/trunk/CMFCore/tests/test_FSPythonScript.py
===================================================================
--- CMF/trunk/CMFCore/tests/test_FSPythonScript.py 2006-01-21 18:34:10 UTC (rev 41403)
+++ CMF/trunk/CMFCore/tests/test_FSPythonScript.py 2006-01-22 11:58:17 UTC (rev 41404)
@@ -14,7 +14,8 @@
$Id$
"""
-from unittest import TestSuite, makeSuite, main
+import unittest
+
import Testing
import Zope2
Zope2.startup()
@@ -44,12 +45,12 @@
class FSPythonScriptTests(FSPSMaker):
- def test_GetSize( self ):
+ def test_get_size( self ):
# Test get_size returns correct value
script = self._makeOne('test1', 'test1.py')
self.assertEqual(len(script.read()),script.get_size())
- def testInitializationRaceCondition(self):
+ def test_initialization_race_condition(self):
# Tries to exercise a former race condition where
# FSObject._updateFromFS() set self._parsed before the
# object was really parsed.
@@ -77,64 +78,87 @@
FSPSMaker.setUp(self)
SecurityTest.setUp( self )
- self.root._setObject( 'portal_skins', Folder( 'portal_skins' ) )
- self.skins = self.root.portal_skins
+ def tearDown(self):
+ SecurityTest.tearDown(self)
+ FSPSMaker.tearDown(self)
- self.skins._setObject( 'custom', Folder( 'custom' ) )
- self.custom = self.skins.custom
+ def _makeSkins(self):
- self.skins._setObject( 'fsdir', Folder( 'fsdir' ) )
- self.fsdir = self.skins.fsdir
+ root = self.root
+ root._setObject( 'portal_skins', Folder( 'portal_skins' ) )
+ tool = self.root.portal_skins
- self.fsdir._setObject( 'test6'
- , self._makeOne( 'test6', 'test6.py' ) )
+ tool._setObject( 'custom', Folder( 'custom' ) )
+ custom = tool.custom
- self.fsPS = self.fsdir.test6
+ tool._setObject( 'fsdir', Folder( 'fsdir' ) )
+ fsdir = tool.fsdir
+ fsdir._setObject( 'test6'
+ , self._makeOne( 'test6', 'test6.py' ) )
+
+ fsPS = fsdir.test6
+
+ return root, tool, custom, fsdir, fsPS
+
def test_customize( self ):
- self.fsPS.manage_doCustomize( folder_path='custom' )
+ from Products.CMFCore.FSPythonScript import CustomizedPythonScript
- self.assertEqual( len( self.custom.objectIds() ), 1 )
- self.failUnless( 'test6' in self.custom.objectIds() )
+ root, tool, custom, fsdir, fsPS = self._makeSkins()
+ fsPS.manage_doCustomize( folder_path='custom' )
+
+ self.assertEqual( len( custom.objectIds() ), 1 )
+ self.failUnless( 'test6' in custom.objectIds() )
+
+ test6 = custom._getOb('test6')
+
+ self.failUnless(isinstance(test6, CustomizedPythonScript))
+ self.assertEqual(test6.original_source, fsPS.read())
+
def test_customize_caching(self):
# Test to ensure that cache manager associations survive customizing
+ root, tool, custom, fsdir, fsPS = self._makeSkins()
+
cache_id = 'gofast'
- RAMCacheManager.manage_addRAMCacheManager( self.root
+ RAMCacheManager.manage_addRAMCacheManager( root
, cache_id
, REQUEST=None
)
- self.fsPS.ZCacheable_setManagerId(cache_id, REQUEST=None)
+ fsPS.ZCacheable_setManagerId(cache_id, REQUEST=None)
- self.assertEqual(self.fsPS.ZCacheable_getManagerId(), cache_id)
+ self.assertEqual(fsPS.ZCacheable_getManagerId(), cache_id)
- self.fsPS.manage_doCustomize(folder_path='custom')
- custom_ps = self.custom.test6
+ fsPS.manage_doCustomize(folder_path='custom')
+ custom_ps = custom.test6
self.assertEqual(custom_ps.ZCacheable_getManagerId(), cache_id)
def test_customize_proxyroles(self):
# Test to ensure that proxy roles survive customizing
- self.fsPS._proxy_roles = ('Manager', 'Anonymous')
- self.failUnless(self.fsPS.manage_haveProxy('Anonymous'))
- self.failUnless(self.fsPS.manage_haveProxy('Manager'))
+ root, tool, custom, fsdir, fsPS = self._makeSkins()
- self.fsPS.manage_doCustomize(folder_path='custom')
- custom_ps = self.custom.test6
+ fsPS._proxy_roles = ('Manager', 'Anonymous')
+ self.failUnless(fsPS.manage_haveProxy('Anonymous'))
+ self.failUnless(fsPS.manage_haveProxy('Manager'))
+
+ fsPS.manage_doCustomize(folder_path='custom')
+ custom_ps = custom.test6
self.failUnless(custom_ps.manage_haveProxy('Anonymous'))
self.failUnless(custom_ps.manage_haveProxy('Manager'))
def test_customization_permissions(self):
# Test to ensure that permission settings survive customizing
+ root, tool, custom, fsdir, fsPS = self._makeSkins()
perm = 'View management screens'
# First, set a permission to an odd role and verify
- self.fsPS.manage_permission( perm
- , roles=('Anonymous',)
- , acquire=0
- )
- rop = self.fsPS.rolesOfPermission(perm)
+ fsPS.manage_permission( perm
+ , roles=('Anonymous',)
+ , acquire=0
+ )
+ rop = fsPS.rolesOfPermission(perm)
for rop_info in rop:
if rop_info['name'] == 'Anonymous':
self.failIf(rop_info['selected'] == '')
@@ -142,8 +166,8 @@
self.failUnless(rop_info['selected'] == '')
# Now customize and verify again
- self.fsPS.manage_doCustomize(folder_path='custom')
- custom_ps = self.custom.test6
+ fsPS.manage_doCustomize(folder_path='custom')
+ custom_ps = custom.test6
rop = custom_ps.rolesOfPermission(perm)
for rop_info in rop:
if rop_info['name'] == 'Anonymous':
@@ -151,16 +175,73 @@
else:
self.failUnless(rop_info['selected'] == '')
- def tearDown(self):
- SecurityTest.tearDown(self)
- FSPSMaker.tearDown(self)
+_ORIGINAL_TEXT = """\
+## Script (Python) "cps"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=
+##title=
+##
+return 'cps'
+"""
+_REPLACEMENT_TEXT = """\
+## Script (Python) "cps"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=
+##title=
+##
+return 'cps -- replaced'
+"""
+_DIFF_TEXT = """\
+--- original
++++ modified
+@@ -7,4 +7,4 @@
+ ##parameters=
+ ##title=
+ ##
+-return 'cps'
++return 'cps -- replaced'
+"""
+
+class CustomizedPythonScriptTests(unittest.TestCase):
+
+ def _getTargetClass(self):
+ from Products.CMFCore.FSPythonScript import CustomizedPythonScript
+ return CustomizedPythonScript
+
+ def _makeOne(self, id, text):
+ return self._getTargetClass()(id, text)
+
+ def test_write_leaves_original_source(self):
+ cps = self._makeOne('cps', _ORIGINAL_TEXT)
+ self.assertEqual(cps.read(), _ORIGINAL_TEXT)
+ self.assertEqual(cps.original_source, _ORIGINAL_TEXT)
+ cps.write(_REPLACEMENT_TEXT)
+ self.assertEqual(cps.read(), _REPLACEMENT_TEXT)
+ self.assertEqual(cps.original_source, _ORIGINAL_TEXT)
+
+ def test_getDiff(self):
+ cps = self._makeOne('cps', _ORIGINAL_TEXT)
+ self.assertEqual(len(list(cps.getDiff())), 0)
+
+ cps.write(_REPLACEMENT_TEXT)
+ self.assertEqual(list(cps.getDiff()), _DIFF_TEXT.splitlines())
+
def test_suite():
- return TestSuite((
- makeSuite(FSPythonScriptTests),
- makeSuite(FSPythonScriptCustomizationTests),
+ return unittest.TestSuite((
+ unittest.makeSuite(FSPythonScriptTests),
+ unittest.makeSuite(FSPythonScriptCustomizationTests),
+ unittest.makeSuite(CustomizedPythonScriptTests),
))
if __name__ == '__main__':
- main(defaultTest='test_suite')
+ unittest.main(defaultTest='test_suite')
Added: CMF/trunk/CMFCore/www/cpsDiff.pt
===================================================================
--- CMF/trunk/CMFCore/www/cpsDiff.pt 2006-01-21 18:34:10 UTC (rev 41403)
+++ CMF/trunk/CMFCore/www/cpsDiff.pt 2006-01-22 11:58:17 UTC (rev 41404)
@@ -0,0 +1,19 @@
+<h1 tal:replace="structure context/manage_page_header">Header</h1>
+<h2 tal:define="manage_tabs_message options/manage_tabs_message | nothing"
+ tal:replace="structure context/manage_tabs">Tabs</h2>
+
+<h3>Diff of Customized vs. Original Source</h3>
+
+<div tal:define="diffLines python:list(context.getDiff());
+ ">
+<pre tal:condition="diffLines"
+ tal:content="python: '\n'.join(diffLines)">
+DIFF GOES HERE
+</pre>
+
+<p tal:condition="not: diffLines"><em> No changes. </em></p>
+
+</div>
+
+<h1 tal:replace="structure context/manage_page_footer">Footer</h1>
+
Property changes on: CMF/trunk/CMFCore/www/cpsDiff.pt
___________________________________________________________________
Name: svn:eol-style
+ native
More information about the CMF-checkins
mailing list