[CMF-checkins] SVN: CMF/branches/goldegg-phase-1/ Merge
GenericSetup 1.0, stripping out redundant activity in CMFSetup.
Tres Seaver
tseaver at palladion.com
Fri Sep 23 17:33:02 EDT 2005
Log message for revision 38573:
Merge GenericSetup 1.0, stripping out redundant activity in CMFSetup.
Changed:
U CMF/branches/goldegg-phase-1/CMFSetup/context.py
U CMF/branches/goldegg-phase-1/CMFSetup/differ.py
U CMF/branches/goldegg-phase-1/CMFSetup/interfaces.py
U CMF/branches/goldegg-phase-1/CMFSetup/registry.py
U CMF/branches/goldegg-phase-1/CMFSetup/rolemap.py
D CMF/branches/goldegg-phase-1/CMFSetup/tests/test_context.py
D CMF/branches/goldegg-phase-1/CMFSetup/tests/test_differ.py
D CMF/branches/goldegg-phase-1/CMFSetup/tests/test_registry.py
D CMF/branches/goldegg-phase-1/CMFSetup/tests/test_rolemap.py
D CMF/branches/goldegg-phase-1/CMFSetup/tests/test_tool.py
U CMF/branches/goldegg-phase-1/CMFSetup/tool.py
A CMF/branches/goldegg-phase-1/GenericSetup/
A CMF/branches/goldegg-phase-1/GenericSetup/CHANGES.txt
A CMF/branches/goldegg-phase-1/GenericSetup/CREDITS.txt
A CMF/branches/goldegg-phase-1/GenericSetup/DEPENDENCIES.txt
A CMF/branches/goldegg-phase-1/GenericSetup/PROFILES.txt
A CMF/branches/goldegg-phase-1/GenericSetup/README.txt
A CMF/branches/goldegg-phase-1/GenericSetup/__init__.py
A CMF/branches/goldegg-phase-1/GenericSetup/context.py
A CMF/branches/goldegg-phase-1/GenericSetup/differ.py
A CMF/branches/goldegg-phase-1/GenericSetup/exceptions.py
A CMF/branches/goldegg-phase-1/GenericSetup/factory.py
A CMF/branches/goldegg-phase-1/GenericSetup/interfaces.py
A CMF/branches/goldegg-phase-1/GenericSetup/permissions.py
A CMF/branches/goldegg-phase-1/GenericSetup/properties.py
A CMF/branches/goldegg-phase-1/GenericSetup/registry.py
A CMF/branches/goldegg-phase-1/GenericSetup/rolemap.py
A CMF/branches/goldegg-phase-1/GenericSetup/tests/
A CMF/branches/goldegg-phase-1/GenericSetup/tests/__init__.py
A CMF/branches/goldegg-phase-1/GenericSetup/tests/common.py
A CMF/branches/goldegg-phase-1/GenericSetup/tests/conformance.py
A CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/
A CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/export_steps.xml
A CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/import_steps.xml
A CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/profile.ini
A CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/toolset.xml
A CMF/branches/goldegg-phase-1/GenericSetup/tests/four/
A CMF/branches/goldegg-phase-1/GenericSetup/tests/four/placeholder.txt
A CMF/branches/goldegg-phase-1/GenericSetup/tests/one/
A CMF/branches/goldegg-phase-1/GenericSetup/tests/one/placeholder.txt
A CMF/branches/goldegg-phase-1/GenericSetup/tests/simple.png
A CMF/branches/goldegg-phase-1/GenericSetup/tests/test_context.py
A CMF/branches/goldegg-phase-1/GenericSetup/tests/test_differ.py
A CMF/branches/goldegg-phase-1/GenericSetup/tests/test_properties.py
A CMF/branches/goldegg-phase-1/GenericSetup/tests/test_registry.py
A CMF/branches/goldegg-phase-1/GenericSetup/tests/test_rolemap.py
A CMF/branches/goldegg-phase-1/GenericSetup/tests/test_tool.py
A CMF/branches/goldegg-phase-1/GenericSetup/tests/test_utils.py
A CMF/branches/goldegg-phase-1/GenericSetup/tests/three/
A CMF/branches/goldegg-phase-1/GenericSetup/tests/three/placeholder.txt
A CMF/branches/goldegg-phase-1/GenericSetup/tests/two/
A CMF/branches/goldegg-phase-1/GenericSetup/tests/two/placeholder.txt
A CMF/branches/goldegg-phase-1/GenericSetup/tool.py
A CMF/branches/goldegg-phase-1/GenericSetup/utils.py
A CMF/branches/goldegg-phase-1/GenericSetup/version.txt
A CMF/branches/goldegg-phase-1/GenericSetup/www/
A CMF/branches/goldegg-phase-1/GenericSetup/www/siteAddForm.zpt
A CMF/branches/goldegg-phase-1/GenericSetup/www/sutCompare.zpt
A CMF/branches/goldegg-phase-1/GenericSetup/www/sutExportSteps.zpt
A CMF/branches/goldegg-phase-1/GenericSetup/www/sutImportSteps.zpt
A CMF/branches/goldegg-phase-1/GenericSetup/www/sutProperties.zpt
A CMF/branches/goldegg-phase-1/GenericSetup/www/sutSnapshots.zpt
A CMF/branches/goldegg-phase-1/GenericSetup/www/tool.png
A CMF/branches/goldegg-phase-1/GenericSetup/www/toolAdd.zpt
A CMF/branches/goldegg-phase-1/GenericSetup/xml/
A CMF/branches/goldegg-phase-1/GenericSetup/xml/esrExport.xml
A CMF/branches/goldegg-phase-1/GenericSetup/xml/isrExport.xml
A CMF/branches/goldegg-phase-1/GenericSetup/xml/object_nodes.xml
A CMF/branches/goldegg-phase-1/GenericSetup/xml/property_nodes.xml
A CMF/branches/goldegg-phase-1/GenericSetup/xml/rmeExport.xml
A CMF/branches/goldegg-phase-1/GenericSetup/xml/spcExport.xml
A CMF/branches/goldegg-phase-1/GenericSetup/xml/tscExport.xml
-=-
Modified: CMF/branches/goldegg-phase-1/CMFSetup/context.py
===================================================================
--- CMF/branches/goldegg-phase-1/CMFSetup/context.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/CMFSetup/context.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -17,446 +17,9 @@
$Id$
"""
-import os
-import time
-from StringIO import StringIO
-from tarfile import TarFile
-from tarfile import TarInfo
-
-from AccessControl import ClassSecurityInfo
-from Acquisition import aq_inner
-from Acquisition import aq_parent
-from Acquisition import aq_self
-from Acquisition import Implicit
-from DateTime.DateTime import DateTime
-from Globals import InitializeClass
-from OFS.DTMLDocument import DTMLDocument
-from OFS.Folder import Folder
-from OFS.Image import File
-from OFS.Image import Image
-from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
-from Products.PythonScripts.PythonScript import PythonScript
-
-from interfaces import IExportContext
-from interfaces import IImportContext
-from permissions import ManagePortal
-
-
-class DirectoryImportContext( Implicit ):
-
- __implements__ = ( IImportContext, )
-
- security = ClassSecurityInfo()
-
- def __init__( self
- , tool
- , profile_path
- , should_purge=False
- , encoding=None
- ):
-
- self._site = aq_parent( aq_inner( tool ) )
- self._profile_path = profile_path
- self._should_purge = bool( should_purge )
- self._encoding = encoding
-
- security.declareProtected( ManagePortal, 'getSite' )
- def getSite( self ):
-
- """ See ISetupContext.
- """
- return aq_self(self._site)
-
- security.declareProtected( ManagePortal, 'getEncoding' )
- def getEncoding( self ):
-
- """ See IImportContext.
- """
- return self._encoding
-
- security.declareProtected( ManagePortal, 'readDataFile' )
- def readDataFile( self, filename, subdir=None ):
-
- """ See IImportContext.
- """
- if subdir is None:
- full_path = os.path.join( self._profile_path, filename )
- else:
- full_path = os.path.join( self._profile_path, subdir, filename )
-
- if not os.path.exists( full_path ):
- return None
-
- file = open( full_path, 'rb' )
- result = file.read()
- file.close()
-
- return result
-
- security.declareProtected( ManagePortal, 'getLastModified' )
- def getLastModified( self, path ):
-
- """ See IImportContext.
- """
- full_path = os.path.join( self._profile_path, path )
-
- if not os.path.exists( full_path ):
- return None
-
- return DateTime( os.path.getmtime( full_path ) )
-
- security.declareProtected( ManagePortal, 'isDirectory' )
- def isDirectory( self, path ):
-
- """ See IImportContext.
- """
- full_path = os.path.join( self._profile_path, path )
-
- if not os.path.exists( full_path ):
- return None
-
- return os.path.isdir( full_path )
-
- security.declareProtected( ManagePortal, 'listDirectory' )
- def listDirectory( self, path, skip=('CVS', '.svn') ):
-
- """ See IImportContext.
- """
- if path is None:
- path = ''
-
- full_path = os.path.join( self._profile_path, path )
-
- if not os.path.exists( full_path ) or not os.path.isdir( full_path ):
- return None
-
- names = os.listdir( full_path )
-
- return [ name for name in names if name not in skip ]
-
- security.declareProtected( ManagePortal, 'shouldPurge' )
- def shouldPurge( self ):
-
- """ See IImportContext.
- """
- return self._should_purge
-
-InitializeClass( DirectoryImportContext )
-
-
-class DirectoryExportContext( Implicit ):
-
- __implements__ = ( IExportContext, )
-
- security = ClassSecurityInfo()
-
- def __init__( self, tool, profile_path ):
-
- self._site = aq_parent( aq_inner( tool ) )
- self._profile_path = profile_path
-
- security.declareProtected( ManagePortal, 'getSite' )
- def getSite( self ):
-
- """ See ISetupContext.
- """
- return aq_self(self._site)
-
- security.declareProtected( ManagePortal, 'writeDataFile' )
- def writeDataFile( self, filename, text, content_type, subdir=None ):
-
- """ See IExportContext.
- """
- if subdir is None:
- prefix = self._profile_path
- else:
- prefix = os.path.join( self._profile_path, subdir )
-
- full_path = os.path.join( prefix, filename )
-
- if not os.path.exists( prefix ):
- os.makedirs( prefix )
-
- mode = content_type.startswith( 'text/' ) and 'w' or 'wb'
-
- file = open( full_path, mode )
- file.write( text )
- file.close()
-
-InitializeClass( DirectoryExportContext )
-
-
-class TarballExportContext( Implicit ):
-
- __implements__ = ( IExportContext, )
-
- security = ClassSecurityInfo()
-
- def __init__( self, tool ):
-
- self._site = aq_parent( aq_inner( tool ) )
- timestamp = time.gmtime()
- archive_name = ( 'portal_setup-%4d%02d%02d%02d%02d%02d.tar.gz'
- % timestamp[:6] )
-
- self._archive_stream = StringIO()
- self._archive_filename = archive_name
- self._archive = TarFile.open( archive_name, 'w:gz'
- , self._archive_stream )
-
- security.declareProtected( ManagePortal, 'getSite' )
- def getSite( self ):
-
- """ See ISetupContext.
- """
- return aq_self(self._site)
-
- security.declareProtected( ManagePortal, 'writeDataFile' )
- def writeDataFile( self, filename, text, content_type, subdir=None ):
-
- """ See IExportContext.
- """
- if subdir is not None:
- filename = os.path.join( subdir, filename )
-
- stream = StringIO( text )
- info = TarInfo( filename )
- info.size = len( text )
- info.mtime = time.time()
- self._archive.addfile( info, stream )
-
- security.declareProtected( ManagePortal, 'getArchive' )
- def getArchive( self ):
-
- """ Close the archive, and return it as a big string.
- """
- self._archive.close()
- return self._archive_stream.getvalue()
-
- security.declareProtected( ManagePortal, 'getArchiveFilename' )
- def getArchiveFilename( self ):
-
- """ Close the archive, and return it as a big string.
- """
- return self._archive_filename
-
-InitializeClass( TarballExportContext )
-
-
-class SnapshotExportContext( Implicit ):
-
- __implements__ = ( IExportContext, )
-
- security = ClassSecurityInfo()
-
- def __init__( self, tool, snapshot_id ):
-
- self._tool = tool = aq_inner( tool )
- self._site = aq_parent( tool )
- self._snapshot_id = snapshot_id
-
- security.declareProtected( ManagePortal, 'getSite' )
- def getSite( self ):
-
- """ See ISetupContext.
- """
- return aq_self(self._site)
-
- security.declareProtected( ManagePortal, 'writeDataFile' )
- def writeDataFile( self, filename, text, content_type, subdir=None ):
-
- """ See IExportContext.
- """
- folder = self._ensureSnapshotsFolder( subdir )
-
- # TODO: switch on content_type
- ob = self._createObjectByType( filename, text, content_type )
- folder._setObject( str( filename ), ob ) # No Unicode IDs!
-
- security.declareProtected( ManagePortal, 'getSnapshotURL' )
- def getSnapshotURL( self ):
-
- """ See IExportContext.
- """
- return '%s/%s' % ( self._tool.absolute_url(), self._snapshot_id )
-
- security.declareProtected( ManagePortal, 'getSnapshotFolder' )
- def getSnapshotFolder( self ):
-
- """ See IExportContext.
- """
- return self._ensureSnapshotsFolder()
-
- #
- # Helper methods
- #
- security.declarePrivate( '_createObjectByType' )
- def _createObjectByType( self, name, body, content_type ):
-
- if name.endswith('.py'):
-
- ob = PythonScript( name )
- ob.write( body )
-
- elif name.endswith('.dtml'):
-
- ob = DTMLDocument( '', __name__=name )
- ob.munge( body )
-
- elif content_type in ('text/html', 'text/xml' ):
-
- ob = ZopePageTemplate( name, str( body )
- , content_type=content_type )
-
- elif content_type[:6]=='image/':
-
- ob=Image( name, '', body, content_type=content_type )
-
- else:
- ob=File( name, '', body, content_type=content_type )
-
- return ob
-
- security.declarePrivate( '_ensureSnapshotsFolder' )
- def _ensureSnapshotsFolder( self, subdir=None ):
-
- """ Ensure that the appropriate snapshot folder exists.
- """
- path = [ 'snapshots', self._snapshot_id ]
-
- if subdir is not None:
- path.extend( subdir.split( '/' ) )
-
- current = self._tool
-
- for element in path:
-
- if element not in current.objectIds():
- # No Unicode IDs!
- current._setObject( str( element ), Folder( element ) )
-
- current = current._getOb( element )
-
- return current
-
-InitializeClass( SnapshotExportContext )
-
-
-class SnapshotImportContext( Implicit ):
-
- __implements__ = ( IImportContext, )
-
- security = ClassSecurityInfo()
-
- def __init__( self
- , tool
- , snapshot_id
- , should_purge=False
- , encoding=None
- ):
-
- self._tool = tool = aq_inner( tool )
- self._site = aq_parent( tool )
- self._snapshot_id = snapshot_id
- self._encoding = encoding
- self._should_purge = bool( should_purge )
-
- security.declareProtected( ManagePortal, 'getSite' )
- def getSite( self ):
-
- """ See ISetupContext.
- """
- return aq_self(self._site)
-
- security.declareProtected( ManagePortal, 'getEncoding' )
- def getEncoding( self ):
-
- """ Return the encoding used in data files.
-
- o Return None if the data should not be encoded.
- """
- return self._encoding
-
- security.declareProtected( ManagePortal, 'readDataFile' )
- def readDataFile( self, filename, subdir=None ):
-
- """ See IImportContext.
- """
- try:
- snapshot = self._getSnapshotFolder( subdir )
- object = snapshot._getOb( filename )
- except ( AttributeError, KeyError ):
- return None
-
- try:
- return object.read()
- except AttributeError:
- return object.manage_FTPget()
-
- security.declareProtected( ManagePortal, 'getLastModified' )
- def getLastModified( self, path ):
-
- """ See IImportContext.
- """
- try:
- snapshot = self._getSnapshotFolder()
- object = snapshot.restrictedTraverse( path )
- except ( AttributeError, KeyError ):
- return None
- else:
- return object.bobobase_modification_time()
-
- security.declareProtected( ManagePortal, 'isDirectory' )
- def isDirectory( self, path ):
-
- """ See IImportContext.
- """
- try:
- snapshot = self._getSnapshotFolder()
- object = snapshot.restrictedTraverse( path )
- except ( AttributeError, KeyError ):
- return None
- else:
- folderish = getattr( object, 'isPrincipiaFolderish', False )
- return bool( folderish )
-
- security.declareProtected( ManagePortal, 'listDirectory' )
- def listDirectory( self, path, skip=() ):
-
- """ See IImportContext.
- """
- try:
- snapshot = self._getSnapshotFolder()
- subdir = snapshot.restrictedTraverse( path )
- except ( AttributeError, KeyError ):
- return None
- else:
- if not getattr( subdir, 'isPrincipiaFolderish', False ):
- return None
-
- object_ids = subdir.objectIds()
- return [ x for x in object_ids if x not in skip ]
-
- security.declareProtected( ManagePortal, 'shouldPurge' )
- def shouldPurge( self ):
-
- """ See IImportContext.
- """
- return self._should_purge
-
- #
- # Helper methods
- #
- security.declarePrivate( '_getSnapshotFolder' )
- def _getSnapshotFolder( self, subdir=None ):
-
- """ Return the appropriate snapshot (sub)folder.
- """
- path = [ 'snapshots', self._snapshot_id ]
-
- if subdir is not None:
- path.extend( subdir.split( '/' ) )
-
- return self._tool.restrictedTraverse( path )
-
-InitializeClass( SnapshotImportContext )
+# BBB
+from Products.GenericSetup.context import DirectoryImportContext
+from Products.GenericSetup.context import DirectoryExportContext
+from Products.GenericSetup.context import TarballExportContext
+from Products.GenericSetup.context import SnapshotExportContext
+from Products.GenericSetup.context import SnapshotImportContext
Modified: CMF/branches/goldegg-phase-1/CMFSetup/differ.py
===================================================================
--- CMF/branches/goldegg-phase-1/CMFSetup/differ.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/CMFSetup/differ.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -15,215 +15,6 @@
$Id$
"""
-from difflib import unified_diff
-import re
-
-from Globals import InitializeClass
-from AccessControl import ClassSecurityInfo
-
-BLANKS_REGEX = re.compile( r'^\s*$' )
-
-def unidiff( a
- , b
- , filename_a='original'
- , timestamp_a=None
- , filename_b='modified'
- , timestamp_b=None
- , ignore_blanks=False
- ):
- r"""Compare two sequences of lines; generate the resulting delta.
-
- Each sequence must contain individual single-line strings
- ending with newlines. Such sequences can be obtained from the
- `readlines()` method of file-like objects. The delta
- generated also consists of newline-terminated strings, ready
- to be printed as-is via the writeline() method of a file-like
- object.
-
- Note that the last line of a file may *not* have a newline;
- this is reported in the same way that GNU diff reports this.
- *This method only supports UNIX line ending conventions.*
-
- filename_a and filename_b are used to generate the header,
- allowing other tools to determine what 'files' were used
- to generate this output.
-
- timestamp_a and timestamp_b, when supplied, are expected
- to be last-modified timestamps to be inserted in the
- header, as floating point values since the epoch.
-
- Example:
-
- >>> print ''.join(UniDiffer().compare(
- ... 'one\ntwo\nthree\n'.splitlines(1),
- ... 'ore\ntree\nemu\n'.splitlines(1))),
- +++ original
- --- modified
- @@ -1,3 +1,3 @@
- -one
- +ore
- -two
- -three
- +tree
- +emu
- """
- if isinstance( a, basestring ):
- a = a.splitlines()
-
- if isinstance( b, basestring ):
- b = b.splitlines()
-
- if ignore_blanks:
- a = [ x for x in a if not BLANKS_REGEX.match( x ) ]
- b = [ x for x in b if not BLANKS_REGEX.match( x ) ]
-
- return unified_diff( a
- , b
- , filename_a
- , filename_b
- , timestamp_a
- , timestamp_b
- , lineterm=""
- )
-
-class ConfigDiff:
-
- security = ClassSecurityInfo()
-
- def __init__( self
- , lhs
- , rhs
- , missing_as_empty=False
- , ignore_blanks=False
- , skip=('CVS','.svn')
- ):
- self._lhs = lhs
- self._rhs = rhs
- self._missing_as_empty = missing_as_empty
- self._ignore_blanks=ignore_blanks
- self._skip = skip
-
- security.declarePrivate( 'compareDirectories' )
- def compareDirectories( self, subdir=None ):
-
- lhs_files = self._lhs.listDirectory( subdir, self._skip )
- if lhs_files is None:
- lhs_files = []
-
- rhs_files = self._rhs.listDirectory( subdir, self._skip )
- if rhs_files is None:
- rhs_files = []
-
- added = [ f for f in rhs_files if f not in lhs_files ]
- removed = [ f for f in lhs_files if f not in rhs_files ]
- all_files = lhs_files + added
- all_files.sort()
-
- result = []
-
- for filename in all_files:
-
- if subdir is None:
- pathname = filename
- else:
- pathname = '%s/%s' % ( subdir, filename )
-
- if filename not in added:
- isDirectory = self._lhs.isDirectory( pathname )
- else:
- isDirectory = self._rhs.isDirectory( pathname )
-
- if not self._missing_as_empty and filename in removed:
-
- if isDirectory:
- result.append( '** Directory %s removed\n' % pathname )
- result.extend( self.compareDirectories( pathname ) )
- else:
- result.append( '** File %s removed\n' % pathname )
-
- elif not self._missing_as_empty and filename in added:
-
- if isDirectory:
- result.append( '** Directory %s added\n' % pathname )
- result.extend( self.compareDirectories( pathname ) )
- else:
- result.append( '** File %s added\n' % pathname )
-
- elif isDirectory:
-
- result.extend( self.compareDirectories( pathname ) )
-
- if ( filename not in added + removed and
- not self._rhs.isDirectory( pathname ) ):
-
- result.append( '** Directory %s replaced with a file of '
- 'the same name\n' % pathname )
-
- if self._missing_as_empty:
- result.extend( self.compareFiles( filename, subdir ) )
- else:
- if ( filename not in added + removed and
- self._rhs.isDirectory( pathname ) ):
-
- result.append( '** File %s replaced with a directory of '
- 'the same name\n' % pathname )
-
- if self._missing_as_empty:
- result.extend( self.compareFiles( filename, subdir ) )
-
- result.extend( self.compareDirectories( pathname ) )
- else:
- result.extend( self.compareFiles( filename, subdir ) )
-
- return result
-
- security.declarePrivate( 'compareFiles' )
- def compareFiles( self, filename, subdir=None ):
-
- if subdir is None:
- path = filename
- else:
- path = '%s/%s' % ( subdir, filename )
-
- lhs_file = self._lhs.readDataFile( filename, subdir )
- lhs_time = self._lhs.getLastModified( path )
-
- if lhs_file is None:
- assert self._missing_as_empty
- lhs_file = ''
- lhs_time = 0
-
- rhs_file = self._rhs.readDataFile( filename, subdir )
- rhs_time = self._rhs.getLastModified( path )
-
- if rhs_file is None:
- assert self._missing_as_empty
- rhs_file = ''
- rhs_time = 0
-
- if lhs_file == rhs_file:
- diff_lines = []
- else:
- diff_lines = unidiff( lhs_file
- , rhs_file
- , filename_a=path
- , timestamp_a=lhs_time
- , filename_b=path
- , timestamp_b=rhs_time
- , ignore_blanks=self._ignore_blanks
- )
- diff_lines = list( diff_lines ) # generator
-
- if len( diff_lines ) == 0: # No *real* difference found
- return []
-
- diff_lines.insert( 0, 'Index: %s' % path )
- diff_lines.insert( 1, '=' * 67 )
-
- return diff_lines
-
- security.declarePrivate( 'compare' )
- def compare( self ):
- return '\n'.join( self.compareDirectories() )
-
-InitializeClass( ConfigDiff )
+# BBB
+from Products.GenericSetup.context import unidiff
+from Products.GenericSetup.context import ConfigDiff
Modified: CMF/branches/goldegg-phase-1/CMFSetup/interfaces.py
===================================================================
--- CMF/branches/goldegg-phase-1/CMFSetup/interfaces.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/CMFSetup/interfaces.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -15,494 +15,18 @@
$Id$
"""
-from Interface import Interface
-
-
-BASE, EXTENSION = range(2)
-
-
-class IPseudoInterface( Interface ):
-
- """ API documentation; not testable / enforceable.
- """
-
-class ISetupContext( Interface ):
-
- """ Context used for export / import plugins.
- """
- def getSite():
-
- """ Return the site object being configured / dumped.
- """
-
-class IImportContext( ISetupContext ):
-
- def getEncoding():
-
- """ Get the encoding used for configuration data within the site.
-
- o Return None if the data should not be encoded.
- """
-
- def readDataFile( filename, subdir=None ):
-
- """ Search the current configuration for the requested file.
-
- o 'filename' is the name (without path elements) of the file.
-
- o 'subdir' is an optional subdirectory; if not supplied, search
- only the "root" directory.
-
- o Return the file contents as a string, or None if the
- file cannot be found.
- """
-
- def getLastModified( path ):
-
- """ Return the modification timestamp of the item at 'path'.
-
- o Result will be a DateTime instance.
-
- o Search profiles in the configuration in order.
-
- o If the context is filesystem based, return the 'stat' timestamp
- of the file / directory to which 'path' points.
-
- o If the context is ZODB-based, return the Zope modification time
- of the object to which 'path' points.
-
- o Return None if 'path' does not point to any object.
- """
-
- def isDirectory( path ):
-
- """ Test whether path points to a directory / folder.
-
- o If the context is filesystem based, check that 'path' points to
- a subdirectory within the "root" directory.
-
- o If the context is ZODB-based, check that 'path' points to a
- "container" under the context's tool.
-
- o Return None if 'path' does not resolve; otherwise, return a
- bool.
- """
-
- def listDirectory( path, skip=('CVS', '.svn') ):
-
- """ List IDs of the contents of a directory / folder.
-
- o Omit names in 'skip'.
-
- o If 'path' does not point to a directory / folder, return None.
- """
-
- def shouldPurge():
-
- """ When installing, should the existing setup be purged?
- """
-
-class IImportPlugin( IPseudoInterface ):
-
- """ Signature for callables used to import portions of site configuration.
- """
- def __call__( context ):
-
- """ Perform the setup step.
-
- o Return a message describing the work done.
-
- o 'context' must implement IImportContext.
- """
-
-class IExportContext( ISetupContext ):
-
- def writeDataFile( filename, text, content_type, subdir=None ):
-
- """ Write data into the specified location.
-
- o 'filename' is the unqualified name of the file.
-
- o 'text' is the content of the file.
-
- o 'content_type' is the MIMEtype of the file.
-
- o 'subdir', if passed, is a path to a subdirectory / folder in
- which to write the file; if not passed, write the file to the
- "root" of the target.
- """
-
-class IExportPlugin( IPseudoInterface ):
-
- """ Signature for callables used to export portions of site configuration.
- """
- def __call__( context ):
-
- """ Write export data for the site wrapped by context.
-
- o Return a message describing the work done.
-
- o 'context' must implement IExportContext. The plugin will use
- its 'writeDataFile' method for each file to be exported.
- """
-
-class IStepRegistry( Interface ):
-
- """ Base interface for step registries.
- """
- def listSteps():
-
- """ Return a sequence of IDs of registered steps.
-
- o Order is not significant.
- """
-
- def listStepMetadata():
-
- """ Return a sequence of mappings describing registered steps.
-
- o Mappings will be ordered alphabetically.
- """
-
- def getStepMetadata( key, default=None ):
-
- """ Return a mapping of metadata for the step identified by 'key'.
-
- o Return 'default' if no such step is registered.
-
- o The 'handler' metadata is available via 'getStep'.
- """
-
- def generateXML():
-
- """ Return a round-trippable XML representation of the registry.
-
- o 'handler' values are serialized using their dotted names.
- """
-
- def parseXML( text ):
-
- """ Parse 'text'.
- """
-
-class IImportStepRegistry( IStepRegistry ):
-
- """ API for import step registry.
- """
- def sortSteps():
-
- """ Return a sequence of registered step IDs
-
- o Sequence is sorted topologically by dependency, with the dependent
- steps *after* the steps they depend on.
- """
-
- def checkComplete():
-
- """ Return a sequence of ( node, edge ) tuples for unsatisifed deps.
- """
-
- def getStep( key, default=None ):
-
- """ Return the IImportPlugin registered for 'key'.
-
- o Return 'default' if no such step is registered.
- """
-
- def registerStep( id
- , version
- , handler
- , dependencies=()
- , title=None
- , description=None
- ):
- """ Register a setup step.
-
- o 'id' is a unique name for this step,
-
- o 'version' is a string for comparing versions, it is preferred to
- be a yyyy/mm/dd-ii formatted string (date plus two-digit
- ordinal). when comparing two version strings, the version with
- the lower sort order is considered the older version.
-
- - Newer versions of a step supplant older ones.
-
- - Attempting to register an older one after a newer one results
- in a KeyError.
-
- o 'handler' should implement IImportPlugin.
-
- o 'dependencies' is a tuple of step ids which have to run before
- this step in order to be able to run at all. Registration of
- steps that have unmet dependencies are deferred until the
- dependencies have been registered.
-
- o 'title' is a one-line UI description for this step.
- If None, the first line of the documentation string of the handler
- is used, or the id if no docstring can be found.
-
- o 'description' is a one-line UI description for this step.
- If None, the remaining line of the documentation string of
- the handler is used, or default to ''.
- """
-
-class IExportStepRegistry( IStepRegistry ):
-
- """ API for export step registry.
- """
- def getStep( key, default=None ):
-
- """ Return the IExportPlugin registered for 'key'.
-
- o Return 'default' if no such step is registered.
- """
-
- def registerStep( id, handler, title=None, description=None ):
-
- """ Register an export step.
-
- o 'id' is the unique identifier for this step
-
- o 'handler' should implement IExportPlugin.
-
- o 'title' is a one-line UI description for this step.
- If None, the first line of the documentation string of the step
- is used, or the id if no docstring can be found.
-
- o 'description' is a one-line UI description for this step.
- If None, the remaining line of the documentation string of
- the step is used, or default to ''.
- """
-
-class IToolsetRegistry( Interface ):
-
- """ API for toolset registry.
- """
- def listForbiddenTools():
-
- """ Return a list of IDs of tools which must be removed, if present.
- """
-
- def addForbiddenTool(tool_id ):
-
- """ Add 'tool_id' to the list of forbidden tools.
-
- o Raise KeyError if 'tool_id' is already in the list.
-
- o Raise ValueError if 'tool_id' is in the "required" list.
- """
-
- def listRequiredTools():
-
- """ Return a list of IDs of tools which must be present.
- """
-
- def getRequiredToolInfo( tool_id ):
-
- """ Return a mapping describing a partiuclar required tool.
-
- o Keys include:
-
- 'id' -- the ID of the tool
-
- 'class' -- a dotted path to its class
-
- o Raise KeyError if 'tool_id' id not a known tool.
- """
-
- def listRequiredToolInfo():
-
- """ Return a list of IDs of tools which must be present.
- """
-
- def addRequiredTool( tool_id, dotted_name ):
-
- """ Add a tool to our "required" list.
-
- o 'tool_id' is the tool's ID.
-
- o 'dotted_name' is a dotted (importable) name of the tool's class.
-
- o Raise KeyError if we have already registered a class for 'tool_id'.
-
- o Raise ValueError if 'tool_id' is in the "forbidden" list.
- """
-
-class IProfileRegistry( Interface ):
-
- """ API for profile registry.
- """
- def getProfileInfo( profile_id ):
-
- """ Return a mapping describing a registered filesystem profile.
-
- o Keys include:
-
- 'id' -- the ID of the profile
-
- 'title' -- its title
-
- 'description' -- a textual description of the profile
-
- 'path' -- a path to the profile on the filesystem.
-
- 'product' -- the name of the product to which 'path' is
- relative (None for absolute paths).
-
- 'type' -- either BASE or EXTENSION
- """
-
- def listProfiles():
-
- """ Return a list of IDs for registered profiles.
- """
-
- def listProfileInfo():
-
- """ Return a list of mappings describing registered profiles.
-
- o See 'getProfileInfo' for a description of the mappings' keys.
- """
-
- def registerProfile( name
- , title
- , description
- , path
- , product=None
- , profile_type=BASE
- ):
- """ Add a new profile to the registry.
-
- o If an existing profile is already registered for 'product:name',
- raise KeyError.
-
- o If 'product' is passed, then 'path' should be interpreted as
- relative to the corresponding product directory.
- """
-
-class ISetupTool( Interface ):
-
- """ API for SetupTool.
- """
-
- def getEncoding():
-
- """ Get the encoding used for configuration data within the site.
-
- o Return None if the data should not be encoded.
- """
-
- def getImportContextID():
-
- """ Get the ID of the active import context.
- """
-
- def setImportContext( context_id ):
-
- """ Set the ID of the active import context and update the registries.
- """
-
- def getImportStepRegistry():
-
- """ Return the IImportStepRegistry for the tool.
- """
-
- def getExportStepRegistry():
-
- """ Return the IExportStepRegistry for the tool.
- """
-
- def getToolsetRegistry():
-
- """ Return the IToolsetRegistry for the tool.
- """
-
- def runImportStep( step_id, run_dependencies=True, purge_old=None ):
-
- """ Execute a given setup step
-
- o 'step_id' is the ID of the step to run.
-
- o If 'purge_old' is True, then run the step after purging any
- "old" setup first (this is the responsibility of the step,
- which must check the context we supply).
-
- o If 'run_dependencies' is True, then run any out-of-date
- dependency steps first.
-
- o Return a mapping, with keys:
-
- 'steps' -- a sequence of IDs of the steps run.
-
- 'messages' -- a dictionary holding messages returned from each
- step
- """
-
- def runAllImportSteps( purge_old=None ):
-
- """ Run all setup steps in dependency order.
-
- o If 'purge_old' is True, then run each step after purging any
- "old" setup first (this is the responsibility of the step,
- which must check the context we supply).
-
- o Return a mapping, with keys:
-
- 'steps' -- a sequence of IDs of the steps run.
-
- 'messages' -- a dictionary holding messages returned from each
- step
- """
-
- def runExportStep( step_id ):
-
- """ Generate a tarball containing artifacts from one export step.
-
- o 'step_id' identifies the export step.
-
- o Return a mapping, with keys:
-
- 'steps' -- a sequence of IDs of the steps run.
-
- 'messages' -- a dictionary holding messages returned from each
- step
-
- 'tarball' -- the stringified tar-gz data.
- """
-
- def runAllExportSteps():
-
- """ Generate a tarball containing artifacts from all export steps.
-
- o Return a mapping, with keys:
-
- 'steps' -- a sequence of IDs of the steps run.
-
- 'messages' -- a dictionary holding messages returned from each
- step
-
- 'tarball' -- the stringified tar-gz data.
- """
-
- def createSnapshot( snapshot_id ):
-
- """ Create a snapshot folder using all steps.
-
- o 'snapshot_id' is the ID of the new folder.
- """
-
- def compareConfigurations( lhs_context
- , rhs_context
- , missing_as_empty=False
- , ignore_whitespace=False
- ):
- """ Compare two configurations.
-
- o 'lhs_context' and 'rhs_context' must implement IImportContext.
-
- o If 'missing_as_empty', then compare files not present as though
- they were zero-length; otherwise, omit such files.
-
- o If 'ignore_whitespace', then suppress diffs due only to whitespace
- (c.f: 'diff -wbB')
- """
+# BBB
+from Products.GenericSetup.interfaces import BASE
+from Products.GenericSetup.interfaces import EXTENSION
+from Products.GenericSetup.interfaces import IPseudoInterface
+from Products.GenericSetup.interfaces import ISetupContext
+from Products.GenericSetup.interfaces import IImportContext
+from Products.GenericSetup.interfaces import IImportPlugin
+from Products.GenericSetup.interfaces import IExportContext
+from Products.GenericSetup.interfaces import IExportPlugin
+from Products.GenericSetup.interfaces import IStepRegistry
+from Products.GenericSetup.interfaces import IImportStepRegistry
+from Products.GenericSetup.interfaces import IExportStepRegistry
+from Products.GenericSetup.interfaces import IToolsetRegistry
+from Products.GenericSetup.interfaces import IProfileRegistry
+from Products.GenericSetup.interfaces import ISetupTool
Modified: CMF/branches/goldegg-phase-1/CMFSetup/registry.py
===================================================================
--- CMF/branches/goldegg-phase-1/CMFSetup/registry.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/CMFSetup/registry.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -15,739 +15,9 @@
$Id$
"""
-from xml.sax import parseString
-
-from AccessControl import ClassSecurityInfo
-from Acquisition import Implicit
-from Globals import InitializeClass
-from Products.PageTemplates.PageTemplateFile import PageTemplateFile
-
-from interfaces import BASE
-from interfaces import IImportStepRegistry
-from interfaces import IExportStepRegistry
-from interfaces import IToolsetRegistry
-from interfaces import IProfileRegistry
-from permissions import ManagePortal
-from utils import HandlerBase
-from utils import _xmldir
-from utils import _getDottedName
-from utils import _resolveDottedName
-from utils import _extractDocstring
-
-
-class ImportStepRegistry( Implicit ):
-
- """ Manage knowledge about steps to create / configure site.
-
- o Steps are composed together to define a site profile.
- """
- __implements__ = ( IImportStepRegistry, )
-
- security = ClassSecurityInfo()
-
- def __init__( self ):
-
- self.clear()
-
- security.declareProtected( ManagePortal, 'listSteps' )
- def listSteps( self ):
-
- """ Return a sequence of IDs of registered steps.
-
- o Order is not significant.
- """
- return self._registered.keys()
-
- security.declareProtected( ManagePortal, 'sortSteps' )
- def sortSteps( self ):
-
- """ Return a sequence of registered step IDs
-
- o Sequence is sorted topologically by dependency, with the dependent
- steps *after* the steps they depend on.
- """
- return self._computeTopologicalSort()
-
- security.declareProtected( ManagePortal, 'checkComplete' )
- def checkComplete( self ):
-
- """ Return a sequence of ( node, edge ) tuples for unsatisifed deps.
- """
- result = []
- seen = {}
-
- graph = self._computeTopologicalSort()
-
- for node in graph:
-
- dependencies = self.getStepMetadata( node )[ 'dependencies' ]
-
- for dependency in dependencies:
-
- if seen.get( dependency ) is None:
- result.append( ( node, dependency ) )
-
- seen[ node ] = 1
-
- return result
-
- security.declareProtected( ManagePortal, 'getStepMetadata' )
- def getStepMetadata( self, key, default=None ):
-
- """ Return a mapping of metadata for the step identified by 'key'.
-
- o Return 'default' if no such step is registered.
-
- o The 'handler' metadata is available via 'getStep'.
- """
- result = {}
-
- info = self._registered.get( key )
-
- if info is None:
- return default
-
- return info.copy()
-
- security.declareProtected( ManagePortal, 'listStepMetadata' )
- def listStepMetadata( self ):
-
- """ Return a sequence of mappings describing registered steps.
-
- o Mappings will be ordered alphabetically.
- """
- step_ids = self.listSteps()
- step_ids.sort()
- return [ self.getStepMetadata( x ) for x in step_ids ]
-
- security.declareProtected( ManagePortal, 'generateXML' )
- def generateXML( self ):
-
- """ Return a round-trippable XML representation of the registry.
-
- o 'handler' values are serialized using their dotted names.
- """
- return self._exportTemplate()
-
- security.declarePrivate( 'getStep' )
- def getStep( self, key, default=None ):
-
- """ Return the IImportPlugin registered for 'key'.
-
- o Return 'default' if no such step is registered.
- """
- marker = object()
- info = self._registered.get( key, marker )
-
- if info is marker:
- return default
-
- return _resolveDottedName( info[ 'handler' ] )
-
- security.declarePrivate( 'registerStep' )
- def registerStep( self
- , id
- , version
- , handler
- , dependencies=()
- , title=None
- , description=None
- ):
- """ Register a setup step.
-
- o 'id' is a unique name for this step,
-
- o 'version' is a string for comparing versions, it is preferred to
- be a yyyy/mm/dd-ii formatted string (date plus two-digit
- ordinal). when comparing two version strings, the version with
- the lower sort order is considered the older version.
-
- - Newer versions of a step supplant older ones.
-
- - Attempting to register an older one after a newer one results
- in a KeyError.
-
- o 'handler' should implement IImportPlugin.
-
- o 'dependencies' is a tuple of step ids which have to run before
- this step in order to be able to run at all. Registration of
- steps that have unmet dependencies are deferred until the
- dependencies have been registered.
-
- o 'title' is a one-line UI description for this step.
- If None, the first line of the documentation string of the handler
- is used, or the id if no docstring can be found.
-
- o 'description' is a one-line UI description for this step.
- If None, the remaining line of the documentation string of
- the handler is used, or default to ''.
- """
- already = self.getStepMetadata( id )
-
- if already and already[ 'version' ] > version:
- raise KeyError( 'Existing registration for step %s, version %s'
- % ( id, already[ 'version' ] ) )
-
- if title is None or description is None:
-
- t, d = _extractDocstring( handler, id, '' )
-
- title = title or t
- description = description or d
-
- info = { 'id' : id
- , 'version' : version
- , 'handler' : _getDottedName( handler )
- , 'dependencies' : dependencies
- , 'title' : title
- , 'description' : description
- }
-
- self._registered[ id ] = info
-
- security.declarePrivate( 'parseXML' )
- def parseXML( self, text, encoding=None ):
-
- """ Parse 'text'.
- """
- reader = getattr( text, 'read', None )
-
- if reader is not None:
- text = reader()
-
- parser = _ImportStepRegistryParser( encoding )
- parseString( text, parser )
-
- return parser._parsed
-
- security.declarePrivate( 'clear' )
- def clear( self ):
-
- self._registered = {}
-
- #
- # Helper methods
- #
- security.declarePrivate( '_computeTopologicalSort' )
- def _computeTopologicalSort( self ):
-
- result = []
-
- graph = [ ( x[ 'id' ], x[ 'dependencies' ] )
- for x in self._registered.values() ]
-
- for node, edges in graph:
-
- after = -1
-
- for edge in edges:
-
- if edge in result:
- after = max( after, result.index( edge ) )
-
- result.insert( after + 1, node )
-
- return result
-
- security.declarePrivate( '_exportTemplate' )
- _exportTemplate = PageTemplateFile( 'isrExport.xml', _xmldir )
-
-InitializeClass( ImportStepRegistry )
-
-
-class ExportStepRegistry( Implicit ):
-
- """ Registry of known site-configuration export steps.
-
- o Each step is registered with a unique id.
-
- o When called, with the portal object passed in as an argument,
- the step must return a sequence of three-tuples,
- ( 'data', 'content_type', 'filename' ), one for each file exported
- by the step.
-
- - 'data' is a string containing the file data;
-
- - 'content_type' is the MIME type of the data;
-
- - 'filename' is a suggested filename for use when downloading.
-
- """
- __implements__ = ( IExportStepRegistry, )
-
- security = ClassSecurityInfo()
-
- def __init__( self ):
-
- self.clear()
-
- security.declareProtected( ManagePortal, 'listSteps' )
- def listSteps( self ):
-
- """ Return a list of registered step IDs.
- """
- return self._registered.keys()
-
- security.declareProtected( ManagePortal, 'getStepMetadata' )
- def getStepMetadata( self, key, default=None ):
-
- """ Return a mapping of metadata for the step identified by 'key'.
-
- o Return 'default' if no such step is registered.
-
- o The 'handler' metadata is available via 'getStep'.
- """
- info = self._registered.get( key )
-
- if info is None:
- return default
-
- return info.copy()
-
- security.declareProtected( ManagePortal, 'listStepMetadata' )
- def listStepMetadata( self ):
-
- """ Return a sequence of mappings describing registered steps.
-
- o Steps will be alphabetical by ID.
- """
- step_ids = self.listSteps()
- step_ids.sort()
- return [ self.getStepMetadata( x ) for x in step_ids ]
-
- security.declareProtected( ManagePortal, 'generateXML' )
- def generateXML( self ):
-
- """ Return a round-trippable XML representation of the registry.
-
- o 'handler' values are serialized using their dotted names.
- """
- return self._exportTemplate()
-
- security.declarePrivate( 'getStep' )
- def getStep( self, key, default=None ):
-
- """ Return the IExportPlugin registered for 'key'.
-
- o Return 'default' if no such step is registered.
- """
- marker = object()
- info = self._registered.get( key, marker )
-
- if info is marker:
- return default
-
- return _resolveDottedName( info[ 'handler' ] )
-
- security.declarePrivate( 'registerStep' )
- def registerStep( self, id, handler, title=None, description=None ):
-
- """ Register an export step.
-
- o 'id' is the unique identifier for this step
-
- o 'step' should implement IExportPlugin.
-
- o 'title' is a one-line UI description for this step.
- If None, the first line of the documentation string of the step
- is used, or the id if no docstring can be found.
-
- o 'description' is a one-line UI description for this step.
- If None, the remaining line of the documentation string of
- the step is used, or default to ''.
- """
- if title is None or description is None:
-
- t, d = _extractDocstring( handler, id, '' )
-
- title = title or t
- description = description or d
-
- info = { 'id' : id
- , 'handler' : _getDottedName( handler )
- , 'title' : title
- , 'description' : description
- }
-
- self._registered[ id ] = info
-
- security.declarePrivate( 'parseXML' )
- def parseXML( self, text, encoding=None ):
-
- """ Parse 'text'.
- """
- reader = getattr( text, 'read', None )
-
- if reader is not None:
- text = reader()
-
- parser = _ExportStepRegistryParser( encoding )
- parseString( text, parser )
-
- return parser._parsed
-
- security.declarePrivate( 'clear' )
- def clear( self ):
-
- self._registered = {}
-
- #
- # Helper methods
- #
- security.declarePrivate( '_exportTemplate' )
- _exportTemplate = PageTemplateFile( 'esrExport.xml', _xmldir )
-
-InitializeClass( ExportStepRegistry )
-
-class ToolsetRegistry( Implicit ):
-
- """ Track required / forbidden tools.
- """
- __implements__ = ( IToolsetRegistry, )
-
- security = ClassSecurityInfo()
- security.setDefaultAccess( 'allow' )
-
- def __init__( self ):
-
- self.clear()
-
- #
- # Toolset API
- #
- security.declareProtected( ManagePortal, 'listForbiddenTools' )
- def listForbiddenTools( self ):
-
- """ See IToolsetRegistry.
- """
- result = list( self._forbidden )
- result.sort()
- return result
-
- security.declareProtected( ManagePortal, 'addForbiddenTool' )
- def addForbiddenTool( self, tool_id ):
-
- """ See IToolsetRegistry.
- """
- if tool_id in self._forbidden:
- return
-
- if self._required.get( tool_id ) is not None:
- raise ValueError, 'Tool %s is required!' % tool_id
-
- self._forbidden.append( tool_id )
-
- security.declareProtected( ManagePortal, 'listRequiredTools' )
- def listRequiredTools( self ):
-
- """ See IToolsetRegistry.
- """
- result = list( self._required.keys() )
- result.sort()
- return result
-
- security.declareProtected( ManagePortal, 'getRequiredToolInfo' )
- def getRequiredToolInfo( self, tool_id ):
-
- """ See IToolsetRegistry.
- """
- return self._required[ tool_id ]
-
- security.declareProtected( ManagePortal, 'listRequiredToolInfo' )
- def listRequiredToolInfo( self ):
-
- """ See IToolsetRegistry.
- """
- return [ self.getRequiredToolInfo( x )
- for x in self.listRequiredTools() ]
-
- security.declareProtected( ManagePortal, 'addRequiredTool' )
- def addRequiredTool( self, tool_id, dotted_name ):
-
- """ See IToolsetRegistry.
- """
- if tool_id in self._forbidden:
- raise ValueError, "Forbidden tool ID: %s" % tool_id
-
- self._required[ tool_id ] = { 'id' : tool_id
- , 'class' : dotted_name
- }
-
- security.declareProtected( ManagePortal, 'generateXML' )
- def generateXML( self ):
-
- """ Pseudo API.
- """
- return self._toolsetConfig()
-
- security.declareProtected( ManagePortal, 'parseXML' )
- def parseXML( self, text, encoding=None ):
-
- """ Pseudo-API
- """
- reader = getattr( text, 'read', None )
-
- if reader is not None:
- text = reader()
-
- parser = _ToolsetParser( encoding )
- parseString( text, parser )
-
- for tool_id in parser._forbidden:
- self.addForbiddenTool( tool_id )
-
- for tool_id, dotted_name in parser._required.items():
- self.addRequiredTool( tool_id, dotted_name )
-
- security.declarePrivate( 'clear' )
- def clear( self ):
-
- self._forbidden = []
- self._required = {}
-
- #
- # Helper methods.
- #
- security.declarePrivate( '_toolsetConfig' )
- _toolsetConfig = PageTemplateFile( 'tscExport.xml'
- , _xmldir
- , __name__='toolsetConfig'
- )
-
-InitializeClass( ToolsetRegistry )
-
-class ProfileRegistry( Implicit ):
-
- """ Track registered profiles.
- """
- __implements__ = ( IProfileRegistry, )
-
- security = ClassSecurityInfo()
- security.setDefaultAccess( 'allow' )
-
- def __init__( self ):
-
- self.clear()
-
- security.declareProtected( ManagePortal, '' )
- def getProfileInfo( self, profile_id ):
-
- """ See IProfileRegistry.
- """
- result = self._profile_info[ profile_id ]
- return result.copy()
-
- security.declareProtected( ManagePortal, 'listProfiles' )
- def listProfiles( self ):
-
- """ See IProfileRegistry.
- """
- return tuple( self._profile_ids )
-
- security.declareProtected( ManagePortal, 'listProfileInfo' )
- def listProfileInfo( self ):
-
- """ See IProfileRegistry.
- """
- return [ self.getProfileInfo( id ) for id in self.listProfiles() ]
-
- security.declareProtected( ManagePortal, 'registerProfile' )
- def registerProfile( self
- , name
- , title
- , description
- , path
- , product=None
- , profile_type=BASE
- ):
- """ See IProfileRegistry.
- """
- profile_id = '%s:%s' % (product or 'other', name)
- if self._profile_info.get( profile_id ) is not None:
- raise KeyError, 'Duplicate profile ID: %s' % profile_id
-
- self._profile_ids.append( profile_id )
-
- info = { 'id' : profile_id
- , 'title' : title
- , 'description' : description
- , 'path' : path
- , 'product' : product
- , 'type': profile_type
- }
-
- self._profile_info[ profile_id ] = info
-
- security.declarePrivate( 'clear' )
- def clear( self ):
-
- self._profile_info = {}
- self._profile_ids = []
-
-InitializeClass( ProfileRegistry )
-
-_profile_registry = ProfileRegistry()
-
-class _ImportStepRegistryParser( HandlerBase ):
-
- security = ClassSecurityInfo()
- security.declareObjectPrivate()
- security.setDefaultAccess( 'deny' )
-
- def __init__( self, encoding ):
-
- self._encoding = encoding
- self._started = False
- self._pending = None
- self._parsed = []
-
- def startElement( self, name, attrs ):
-
- if name == 'import-steps':
-
- if self._started:
- raise ValueError, 'Duplicated setup-steps element: %s' % name
-
- self._started = True
-
- elif name == 'import-step':
-
- if self._pending is not None:
- raise ValueError, 'Cannot nest setup-step elements'
-
- self._pending = dict( [ ( k, self._extract( attrs, k ) )
- for k in attrs.keys() ] )
-
- self._pending[ 'dependencies' ] = []
-
- elif name == 'dependency':
-
- if not self._pending:
- raise ValueError, 'Dependency outside of step'
-
- depended = self._extract( attrs, 'step' )
- self._pending[ 'dependencies' ].append( depended )
-
- else:
- raise ValueError, 'Unknown element %s' % name
-
- def characters( self, content ):
-
- if self._pending is not None:
- content = self._encode( content )
- self._pending.setdefault( 'description', [] ).append( content )
-
- def endElement(self, name):
-
- if name == 'import-steps':
- pass
-
- elif name == 'import-step':
-
- if self._pending is None:
- raise ValueError, 'No pending step!'
-
- deps = tuple( self._pending[ 'dependencies' ] )
- self._pending[ 'dependencies' ] = deps
-
- desc = ''.join( self._pending[ 'description' ] )
- self._pending[ 'description' ] = desc
-
- self._parsed.append( self._pending )
- self._pending = None
-
-InitializeClass( _ImportStepRegistryParser )
-
-class _ExportStepRegistryParser( HandlerBase ):
-
- security = ClassSecurityInfo()
- security.declareObjectPrivate()
- security.setDefaultAccess( 'deny' )
-
- def __init__( self, encoding ):
-
- self._encoding = encoding
- self._started = False
- self._pending = None
- self._parsed = []
-
- def startElement( self, name, attrs ):
-
- if name == 'export-steps':
-
- if self._started:
- raise ValueError, 'Duplicated export-steps element: %s' % name
-
- self._started = True
-
- elif name == 'export-step':
-
- if self._pending is not None:
- raise ValueError, 'Cannot nest export-step elements'
-
- self._pending = dict( [ ( k, self._extract( attrs, k ) )
- for k in attrs.keys() ] )
-
- else:
- raise ValueError, 'Unknown element %s' % name
-
- def characters( self, content ):
-
- if self._pending is not None:
- content = self._encode( content )
- self._pending.setdefault( 'description', [] ).append( content )
-
- def endElement(self, name):
-
- if name == 'export-steps':
- pass
-
- elif name == 'export-step':
-
- if self._pending is None:
- raise ValueError, 'No pending step!'
-
- desc = ''.join( self._pending[ 'description' ] )
- self._pending[ 'description' ] = desc
-
- self._parsed.append( self._pending )
- self._pending = None
-
-InitializeClass( _ExportStepRegistryParser )
-
-
-class _ToolsetParser( HandlerBase ):
-
- security = ClassSecurityInfo()
- security.declareObjectPrivate()
- security.setDefaultAccess( 'deny' )
-
- def __init__( self, encoding ):
-
- self._encoding = encoding
- self._required = {}
- self._forbidden = []
-
- def startElement( self, name, attrs ):
-
- if name == 'tool-setup':
- pass
-
- elif name == 'forbidden':
-
- tool_id = self._extract( attrs, 'tool_id' )
-
- if tool_id not in self._forbidden:
- self._forbidden.append( tool_id )
-
- elif name == 'required':
-
- tool_id = self._extract( attrs, 'tool_id' )
- dotted_name = self._extract( attrs, 'class' )
- self._required[ tool_id ] = dotted_name
-
- else:
- raise ValueError, 'Unknown element %s' % name
-
-
-InitializeClass( _ToolsetParser )
+# BBB
+from Products.GenericSetup.registry import ImportStepRegistry
+from Products.GenericSetup.registry import ExportStepRegistry
+from Products.GenericSetup.registry import ToolsetRegistry
+from Products.GenericSetup.registry import ProfileRegistry
+from Products.GenericSetup.registry import _profile_registry
Modified: CMF/branches/goldegg-phase-1/CMFSetup/rolemap.py
===================================================================
--- CMF/branches/goldegg-phase-1/CMFSetup/rolemap.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/CMFSetup/rolemap.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -15,198 +15,6 @@
$Id$
"""
-from AccessControl import ClassSecurityInfo
-from AccessControl.Permission import Permission
-from Globals import InitializeClass
-from Products.PageTemplates.PageTemplateFile import PageTemplateFile
-
-from permissions import ManagePortal
-from utils import _xmldir
-from utils import ConfiguratorBase
-from utils import CONVERTER, DEFAULT, KEY
-
-
-#
-# Configurator entry points
-#
-_FILENAME = 'rolemap.xml'
-
-def importRolemap( context ):
-
- """ Import roles / permission map from an XML file.
-
- o 'context' must implement IImportContext.
-
- o Register via Python:
-
- registry = site.portal_setup.setup_steps
- registry.registerStep( 'importRolemap'
- , '20040518-01'
- , Products.CMFSetup.rolemap.importRolemap
- , ()
- , 'Role / Permission import'
- , 'Import additional roles, and map '
- 'roles to permissions'
- )
-
- o Register via XML:
-
- <setup-step id="importRolemap"
- version="20040518-01"
- handler="Products.CMFSetup.rolemap.importRolemap"
- title="Role / Permission import"
- >Import additional roles, and map roles to permissions.</setup-step>
-
- """
- site = context.getSite()
- encoding = context.getEncoding()
-
- if context.shouldPurge():
-
- items = site.__dict__.items()
-
- for k, v in items: # XXX: WAAA
-
- if k == '__ac_roles__':
- delattr( site, k )
-
- if k.startswith( '_' ) and k.endswith( '_Permission' ):
- delattr( site, k )
-
- text = context.readDataFile( _FILENAME )
-
- if text is not None:
-
- rc = RolemapConfigurator( site, encoding )
- rolemap_info = rc.parseXML( text )
-
- immediate_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
- already = {}
-
- for role in site.valid_roles():
- already[ role ] = 1
-
- for role in rolemap_info[ 'roles' ]:
-
- if already.get( role ) is None:
- immediate_roles.append( role )
- already[ role ] = 1
-
- immediate_roles.sort()
- site.__ac_roles__ = tuple( immediate_roles )
-
- for permission in rolemap_info[ 'permissions' ]:
-
- site.manage_permission( permission[ 'name' ]
- , permission[ 'roles' ]
- , permission[ 'acquire' ]
- )
-
- return 'Role / permission map imported.'
-
-
-def exportRolemap( context ):
-
- """ Export roles / permission map as an XML file
-
- o 'context' must implement IExportContext.
-
- o Register via Python:
-
- registry = site.portal_setup.export_steps
- registry.registerStep( 'exportRolemap'
- , Products.CMFSetup.rolemap.exportRolemap
- , 'Role / Permission export'
- , 'Export additional roles, and '
- 'role / permission map '
- )
-
- o Register via XML:
-
- <export-script id="exportRolemap"
- version="20040518-01"
- handler="Products.CMFSetup.rolemap.exportRolemap"
- title="Role / Permission export"
- >Export additional roles, and role / permission map.</export-script>
-
- """
- site = context.getSite()
- rc = RolemapConfigurator( site ).__of__( site )
- text = rc.generateXML()
-
- context.writeDataFile( _FILENAME, text, 'text/xml' )
-
- return 'Role / permission map exported.'
-
-
-class RolemapConfigurator(ConfiguratorBase):
- """ Synthesize XML description of sitewide role-permission settings.
- """
- security = ClassSecurityInfo()
-
- security.declareProtected( ManagePortal, 'listRoles' )
- def listRoles( self ):
-
- """ List the valid role IDs for our site.
- """
- return self._site.valid_roles()
-
- security.declareProtected( ManagePortal, 'listPermissions' )
- def listPermissions( self ):
-
- """ List permissions for export.
-
- o Returns a sqeuence of mappings describing locally-modified
- permission / role settings. Keys include:
-
- 'permission' -- the name of the permission
-
- 'acquire' -- a flag indicating whether to acquire roles from the
- site's container
-
- 'roles' -- the list of roles which have the permission.
-
- o Do not include permissions which both acquire and which define
- no local changes to the acquired policy.
- """
- permissions = []
- valid_roles = self.listRoles()
-
- for perm in self._site.ac_inherited_permissions( 1 ):
-
- name = perm[ 0 ]
- p = Permission( name, perm[ 1 ], self._site )
- roles = p.getRoles( default=[] )
- acquire = isinstance( roles, list ) # tuple means don't acquire
- roles = [ r for r in roles if r in valid_roles ]
-
- if roles or not acquire:
- permissions.append( { 'name' : name
- , 'acquire' : acquire
- , 'roles' : roles
- } )
-
- return permissions
-
- def _getExportTemplate(self):
-
- return PageTemplateFile('rmeExport.xml', _xmldir)
-
- def _getImportMapping(self):
-
- return {
- 'rolemap':
- { 'roles': {CONVERTER: self._convertToUnique},
- 'permissions': {CONVERTER: self._convertToUnique} },
- 'roles':
- { 'role': {KEY: None} },
- 'role':
- { 'name': {KEY: None} },
- 'permissions':
- { 'permission': {KEY: None, DEFAULT: ()} },
- 'permission':
- { 'name': {},
- 'role': {KEY: 'roles'},
- 'acquire': {CONVERTER: self._convertToBoolean} } }
-
-InitializeClass(RolemapConfigurator)
+# BBB
+from Products.GenericSetup.rolemap import importRolemap
+from Products.GenericSetup.rolemap import exportRolemap
Deleted: CMF/branches/goldegg-phase-1/CMFSetup/tests/test_context.py
===================================================================
--- CMF/branches/goldegg-phase-1/CMFSetup/tests/test_context.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/CMFSetup/tests/test_context.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -1,988 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-""" Unit tests for import / export contexts.
-
-$Id$
-"""
-
-import unittest
-import Testing
-import Zope2
-Zope2.startup()
-
-import os
-import time
-from StringIO import StringIO
-
-from DateTime.DateTime import DateTime
-from OFS.Folder import Folder
-from OFS.Image import File
-
-from Products.CMFCore.tests.base.testcase import SecurityRequestTest
-
-from common import FilesystemTestBase
-from common import TarballTester
-from common import _makeTestFile
-from conformance import ConformsToISetupContext
-from conformance import ConformsToIImportContext
-from conformance import ConformsToIExportContext
-
-
-class DummySite( Folder ):
-
- pass
-
-class DummyTool( Folder ):
-
- pass
-
-class DirectoryImportContextTests( FilesystemTestBase
- , ConformsToISetupContext
- , ConformsToIImportContext
- ):
-
- _PROFILE_PATH = '/tmp/ICTTexts'
-
- def _getTargetClass( self ):
-
- from Products.CMFSetup.context import DirectoryImportContext
- return DirectoryImportContext
-
- def test_readDataFile_nonesuch( self ):
-
- FILENAME = 'nonesuch.txt'
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- self.assertEqual( ctx.readDataFile( FILENAME ), None )
-
- def test_readDataFile_simple( self ):
-
- from string import printable
-
- FILENAME = 'simple.txt'
- self._makeFile( FILENAME, printable )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- self.assertEqual( ctx.readDataFile( FILENAME ), printable )
-
- def test_readDataFile_subdir( self ):
-
- from string import printable
-
- FILENAME = 'subdir/nested.txt'
- self._makeFile( FILENAME, printable )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- self.assertEqual( ctx.readDataFile( FILENAME ), printable )
-
- def test_getLastModified_nonesuch( self ):
-
- FILENAME = 'nonesuch.txt'
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- self.assertEqual( ctx.getLastModified( FILENAME ), None )
-
- def test_getLastModified_simple( self ):
-
- from string import printable
-
- FILENAME = 'simple.txt'
- fqpath = self._makeFile( FILENAME, printable )
- timestamp = os.path.getmtime( fqpath )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- lm = ctx.getLastModified( FILENAME )
- self.failUnless( isinstance( lm, DateTime ) )
- self.assertEqual( lm, timestamp )
-
- def test_getLastModified_subdir( self ):
-
- from string import printable
-
- SUBDIR = 'subdir'
- FILENAME = os.path.join( SUBDIR, 'nested.txt' )
- fqpath = self._makeFile( FILENAME, printable )
- timestamp = os.path.getmtime( fqpath )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- lm = ctx.getLastModified( FILENAME )
- self.failUnless( isinstance( lm, DateTime ) )
- self.assertEqual( lm, timestamp )
-
- def test_getLastModified_directory( self ):
-
- from string import printable
-
- SUBDIR = 'subdir'
- FILENAME = os.path.join( SUBDIR, 'nested.txt' )
- fqpath = self._makeFile( FILENAME, printable )
- path, file = os.path.split( fqpath )
- timestamp = os.path.getmtime( path )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- lm = ctx.getLastModified( SUBDIR )
- self.failUnless( isinstance( lm, DateTime ) )
- self.assertEqual( lm, timestamp )
-
- def test_isDirectory_nonesuch( self ):
-
- FILENAME = 'nonesuch.txt'
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- self.assertEqual( ctx.isDirectory( FILENAME ), None )
-
- def test_isDirectory_simple( self ):
-
- from string import printable
-
- FILENAME = 'simple.txt'
- fqpath = self._makeFile( FILENAME, printable )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- self.assertEqual( ctx.isDirectory( FILENAME ), False )
-
- def test_isDirectory_nested( self ):
-
- from string import printable
-
- SUBDIR = 'subdir'
- FILENAME = os.path.join( SUBDIR, 'nested.txt' )
- fqpath = self._makeFile( FILENAME, printable )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- self.assertEqual( ctx.isDirectory( FILENAME ), False )
-
- def test_isDirectory_directory( self ):
-
- from string import printable
-
- SUBDIR = 'subdir'
- FILENAME = os.path.join( SUBDIR, 'nested.txt' )
- fqpath = self._makeFile( FILENAME, printable )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- self.assertEqual( ctx.isDirectory( SUBDIR ), True )
-
- def test_listDirectory_nonesuch( self ):
-
- FILENAME = 'nonesuch.txt'
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- self.assertEqual( ctx.listDirectory( FILENAME ), None )
-
- def test_listDirectory_root( self ):
-
- from string import printable
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- FILENAME = 'simple.txt'
- self._makeFile( FILENAME, printable )
-
- self.assertEqual( len( ctx.listDirectory( None ) ), 1 )
- self.failUnless( FILENAME in ctx.listDirectory( None ) )
-
- def test_listDirectory_simple( self ):
-
- from string import printable
-
- FILENAME = 'simple.txt'
- self._makeFile( FILENAME, printable )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- self.assertEqual( ctx.listDirectory( FILENAME ), None )
-
- def test_listDirectory_nested( self ):
-
- from string import printable
-
- SUBDIR = 'subdir'
- FILENAME = os.path.join( SUBDIR, 'nested.txt' )
- self._makeFile( FILENAME, printable )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- self.assertEqual( ctx.listDirectory( FILENAME ), None )
-
- def test_listDirectory_single( self ):
-
- from string import printable
-
- SUBDIR = 'subdir'
- FILENAME = os.path.join( SUBDIR, 'nested.txt' )
- self._makeFile( FILENAME, printable )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- names = ctx.listDirectory( SUBDIR )
- self.assertEqual( len( names ), 1 )
- self.failUnless( 'nested.txt' in names )
-
- def test_listDirectory_multiple( self ):
-
- from string import printable
- SUBDIR = 'subdir'
- FILENAME = os.path.join( SUBDIR, 'nested.txt' )
- self._makeFile( FILENAME, printable )
- self._makeFile( os.path.join( SUBDIR, 'another.txt' ), 'ABC' )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- names = ctx.listDirectory( SUBDIR )
- self.assertEqual( len( names ), 2 )
- self.failUnless( 'nested.txt' in names )
- self.failUnless( 'another.txt' in names )
-
- def test_listDirectory_skip_implicit( self ):
-
- from string import printable
- SUBDIR = 'subdir'
- FILENAME = os.path.join( SUBDIR, 'nested.txt' )
- self._makeFile( FILENAME, printable )
- self._makeFile( os.path.join( SUBDIR, 'another.txt' ), 'ABC' )
- self._makeFile( os.path.join( SUBDIR, 'CVS/skip.txt' ), 'DEF' )
- self._makeFile( os.path.join( SUBDIR, '.svn/skip.txt' ), 'GHI' )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- names = ctx.listDirectory( SUBDIR )
- self.assertEqual( len( names ), 2 )
- self.failUnless( 'nested.txt' in names )
- self.failUnless( 'another.txt' in names )
- self.failIf( 'CVS' in names )
- self.failIf( '.svn' in names )
-
- def test_listDirectory_skip_explicit( self ):
-
- from string import printable
- SUBDIR = 'subdir'
- FILENAME = os.path.join( SUBDIR, 'nested.txt' )
- self._makeFile( FILENAME, printable )
- self._makeFile( os.path.join( SUBDIR, 'another.txt' ), 'ABC' )
- self._makeFile( os.path.join( SUBDIR, 'CVS/skip.txt' ), 'DEF' )
- self._makeFile( os.path.join( SUBDIR, '.svn/skip.txt' ), 'GHI' )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- names = ctx.listDirectory( SUBDIR, ( 'nested.txt', ) )
- self.assertEqual( len( names ), 3 )
- self.failIf( 'nested.txt' in names )
- self.failUnless( 'another.txt' in names )
- self.failUnless( 'CVS' in names )
- self.failUnless( '.svn' in names )
-
-class DirectoryExportContextTests( FilesystemTestBase
- , ConformsToISetupContext
- , ConformsToIExportContext
- ):
-
- _PROFILE_PATH = '/tmp/ECTTexts'
-
- def _getTargetClass( self ):
-
- from Products.CMFSetup.context import DirectoryExportContext
- return DirectoryExportContext
-
- def test_writeDataFile_simple( self ):
-
- from string import printable, digits
- FILENAME = 'simple.txt'
- fqname = self._makeFile( FILENAME, printable )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- ctx.writeDataFile( FILENAME, digits, 'text/plain' )
-
- self.assertEqual( open( fqname, 'rb' ).read(), digits )
-
- def test_writeDataFile_new_subdir( self ):
-
- from string import printable, digits
- SUBDIR = 'subdir'
- FILENAME = 'nested.txt'
- fqname = os.path.join( self._PROFILE_PATH, SUBDIR, FILENAME )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- ctx.writeDataFile( FILENAME, digits, 'text/plain', SUBDIR )
-
- self.assertEqual( open( fqname, 'rb' ).read(), digits )
-
- def test_writeDataFile_overwrite( self ):
-
- from string import printable, digits
- SUBDIR = 'subdir'
- FILENAME = 'nested.txt'
- fqname = self._makeFile( os.path.join( SUBDIR, FILENAME )
- , printable )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- ctx.writeDataFile( FILENAME, digits, 'text/plain', SUBDIR )
-
- self.assertEqual( open( fqname, 'rb' ).read(), digits )
-
- def test_writeDataFile_existing_subdir( self ):
-
- from string import printable, digits
- SUBDIR = 'subdir'
- FILENAME = 'nested.txt'
- self._makeFile( os.path.join( SUBDIR, 'another.txt' ), printable )
- fqname = os.path.join( self._PROFILE_PATH, SUBDIR, FILENAME )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._makeOne( site, self._PROFILE_PATH )
-
- ctx.writeDataFile( FILENAME, digits, 'text/plain', SUBDIR )
-
- self.assertEqual( open( fqname, 'rb' ).read(), digits )
-
-
-class TarballExportContextTests( FilesystemTestBase
- , TarballTester
- , ConformsToISetupContext
- , ConformsToIExportContext
- ):
-
- _PROFILE_PATH = '/tmp/TECT_tests'
-
- def _getTargetClass( self ):
-
- from Products.CMFSetup.context import TarballExportContext
- return TarballExportContext
-
- def test_writeDataFile_simple( self ):
-
- from string import printable
- now = long( time.time() )
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._getTargetClass()( site )
-
- ctx.writeDataFile( 'foo.txt', printable, 'text/plain' )
-
- fileish = StringIO( ctx.getArchive() )
-
- self._verifyTarballContents( fileish, [ 'foo.txt' ], now )
- self._verifyTarballEntry( fileish, 'foo.txt', printable )
-
- def test_writeDataFile_multiple( self ):
-
- from string import printable
- from string import digits
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._getTargetClass()( site )
-
- ctx.writeDataFile( 'foo.txt', printable, 'text/plain' )
- ctx.writeDataFile( 'bar.txt', digits, 'text/plain' )
-
- fileish = StringIO( ctx.getArchive() )
-
- self._verifyTarballContents( fileish, [ 'foo.txt', 'bar.txt' ] )
- self._verifyTarballEntry( fileish, 'foo.txt', printable )
- self._verifyTarballEntry( fileish, 'bar.txt', digits )
-
- def test_writeDataFile_subdir( self ):
-
- from string import printable
- from string import digits
-
- site = DummySite( 'site' ).__of__( self.root )
- ctx = self._getTargetClass()( site )
-
- ctx.writeDataFile( 'foo.txt', printable, 'text/plain' )
- ctx.writeDataFile( 'bar/baz.txt', digits, 'text/plain' )
-
- fileish = StringIO( ctx.getArchive() )
-
- self._verifyTarballContents( fileish, [ 'foo.txt', 'bar/baz.txt' ] )
- self._verifyTarballEntry( fileish, 'foo.txt', printable )
- self._verifyTarballEntry( fileish, 'bar/baz.txt', digits )
-
-
-class SnapshotExportContextTests( SecurityRequestTest
- , ConformsToISetupContext
- , ConformsToIExportContext
- ):
-
- def _getTargetClass( self ):
-
- from Products.CMFSetup.context import SnapshotExportContext
- return SnapshotExportContext
-
- def _makeOne( self, *args, **kw ):
-
- return self._getTargetClass()( *args, **kw )
-
- def test_writeDataFile_simple_image( self ):
-
- from OFS.Image import Image
- FILENAME = 'simple.txt'
- _CONTENT_TYPE = 'image/png'
- png_filename = os.path.join( os.path.split( __file__ )[0]
- , 'simple.png' )
- png_file = open( png_filename, 'rb' )
- png_data = png_file.read()
- png_file.close()
-
- site = DummySite( 'site' ).__of__( self.root )
- site.portal_setup = DummyTool( 'portal_setup' )
- tool = site.portal_setup
- ctx = self._makeOne( tool, 'simple' )
-
- ctx.writeDataFile( FILENAME, png_data, _CONTENT_TYPE )
-
- snapshot = tool.snapshots._getOb( 'simple' )
-
- self.assertEqual( len( snapshot.objectIds() ), 1 )
- self.failUnless( FILENAME in snapshot.objectIds() )
-
- fileobj = snapshot._getOb( FILENAME )
-
- self.assertEqual( fileobj.getId(), FILENAME )
- self.assertEqual( fileobj.meta_type, Image.meta_type )
- self.assertEqual( fileobj.getContentType(), _CONTENT_TYPE )
- self.assertEqual( fileobj.data, png_data )
-
- def test_writeDataFile_simple_plain_text( self ):
-
- from string import digits
- from OFS.Image import File
- FILENAME = 'simple.txt'
- _CONTENT_TYPE = 'text/plain'
-
- site = DummySite( 'site' ).__of__( self.root )
- site.portal_setup = DummyTool( 'portal_setup' )
- tool = site.portal_setup
- ctx = self._makeOne( tool, 'simple' )
-
- ctx.writeDataFile( FILENAME, digits, _CONTENT_TYPE )
-
- snapshot = tool.snapshots._getOb( 'simple' )
-
- self.assertEqual( len( snapshot.objectIds() ), 1 )
- self.failUnless( FILENAME in snapshot.objectIds() )
-
- fileobj = snapshot._getOb( FILENAME )
-
- self.assertEqual( fileobj.getId(), FILENAME )
- self.assertEqual( fileobj.meta_type, File.meta_type )
- self.assertEqual( fileobj.getContentType(), _CONTENT_TYPE )
- self.assertEqual( str( fileobj ), digits )
-
- def test_writeDataFile_simple_xml( self ):
-
- from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
- FILENAME = 'simple.xml'
- _CONTENT_TYPE = 'text/xml'
- _XML = """<?xml version="1.0"?><simple />"""
-
- site = DummySite( 'site' ).__of__( self.root )
- site.portal_setup = DummyTool( 'portal_setup' )
- tool = site.portal_setup
- ctx = self._makeOne( tool, 'simple' )
-
- ctx.writeDataFile( FILENAME, _XML, _CONTENT_TYPE )
-
- snapshot = tool.snapshots._getOb( 'simple' )
-
- self.assertEqual( len( snapshot.objectIds() ), 1 )
- self.failUnless( FILENAME in snapshot.objectIds() )
-
- template = snapshot._getOb( FILENAME )
-
- self.assertEqual( template.getId(), FILENAME )
- self.assertEqual( template.meta_type, ZopePageTemplate.meta_type )
- self.assertEqual( template.read(), _XML )
- self.failIf( template.html() )
-
- def test_writeDataFile_unicode_xml( self ):
-
- from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
- FILENAME = 'simple.xml'
- _CONTENT_TYPE = 'text/xml'
- _XML = u"""<?xml version="1.0"?><simple />"""
-
- site = DummySite( 'site' ).__of__( self.root )
- site.portal_setup = DummyTool( 'portal_setup' )
- tool = site.portal_setup
- ctx = self._makeOne( tool, 'simple' )
-
- ctx.writeDataFile( FILENAME, _XML, _CONTENT_TYPE )
-
- snapshot = tool.snapshots._getOb( 'simple' )
-
- self.assertEqual( len( snapshot.objectIds() ), 1 )
- self.failUnless( FILENAME in snapshot.objectIds() )
-
- template = snapshot._getOb( FILENAME )
-
- self.assertEqual( template.getId(), FILENAME )
- self.assertEqual( template.meta_type, ZopePageTemplate.meta_type )
- self.assertEqual( template.read(), _XML )
- self.failIf( template.html() )
-
- def test_writeDataFile_subdir_dtml( self ):
-
- from OFS.DTMLDocument import DTMLDocument
- FILENAME = 'simple.dtml'
- _CONTENT_TYPE = 'text/html'
- _HTML = """<html><body><h1>HTML</h1></body></html>"""
-
- site = DummySite( 'site' ).__of__( self.root )
- site.portal_setup = DummyTool( 'portal_setup' )
- tool = site.portal_setup
- ctx = self._makeOne( tool, 'simple' )
-
- ctx.writeDataFile( FILENAME, _HTML, _CONTENT_TYPE, 'sub1' )
-
- snapshot = tool.snapshots._getOb( 'simple' )
- sub1 = snapshot._getOb( 'sub1' )
-
- self.assertEqual( len( sub1.objectIds() ), 1 )
- self.failUnless( FILENAME in sub1.objectIds() )
-
- template = sub1._getOb( FILENAME )
-
- self.assertEqual( template.getId(), FILENAME )
- self.assertEqual( template.meta_type, DTMLDocument.meta_type )
- self.assertEqual( template.read(), _HTML )
-
- def test_writeDataFile_nested_subdirs_html( self ):
-
- from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
- FILENAME = 'simple.html'
- _CONTENT_TYPE = 'text/html'
- _HTML = """<html><body><h1>HTML</h1></body></html>"""
-
- site = DummySite( 'site' ).__of__( self.root )
- site.portal_setup = DummyTool( 'portal_setup' )
- tool = site.portal_setup
- ctx = self._makeOne( tool, 'simple' )
-
- ctx.writeDataFile( FILENAME, _HTML, _CONTENT_TYPE, 'sub1/sub2' )
-
- snapshot = tool.snapshots._getOb( 'simple' )
- sub1 = snapshot._getOb( 'sub1' )
- sub2 = sub1._getOb( 'sub2' )
-
- self.assertEqual( len( sub2.objectIds() ), 1 )
- self.failUnless( FILENAME in sub2.objectIds() )
-
- template = sub2._getOb( FILENAME )
-
- self.assertEqual( template.getId(), FILENAME )
- self.assertEqual( template.meta_type, ZopePageTemplate.meta_type )
- self.assertEqual( template.read(), _HTML )
- self.failUnless( template.html() )
-
- def test_writeDataFile_multiple( self ):
-
- from string import printable
- from string import digits
-
- site = DummySite( 'site' ).__of__( self.root )
- site.portal_setup = DummyTool( 'portal_setup' )
- tool = site.portal_setup
- ctx = self._makeOne( tool, 'multiple' )
-
- ctx.writeDataFile( 'foo.txt', printable, 'text/plain' )
- ctx.writeDataFile( 'bar.txt', digits, 'text/plain' )
-
- snapshot = tool.snapshots._getOb( 'multiple' )
-
- self.assertEqual( len( snapshot.objectIds() ), 2 )
-
- for id in [ 'foo.txt', 'bar.txt' ]:
- self.failUnless( id in snapshot.objectIds() )
-
-
-class SnapshotImportContextTests( SecurityRequestTest
- , ConformsToISetupContext
- , ConformsToIImportContext
- ):
-
- def _getTargetClass( self ):
-
- from Products.CMFSetup.context import SnapshotImportContext
- return SnapshotImportContext
-
- def _makeOne( self, context_id, *args, **kw ):
-
- site = DummySite( 'site' ).__of__( self.root )
- site._setObject( 'portal_setup', Folder( 'portal_setup' ) )
- tool = site._getOb( 'portal_setup' )
-
- tool._setObject( 'snapshots', Folder( 'snapshots' ) )
- tool.snapshots._setObject( context_id, Folder( context_id ) )
-
- ctx = self._getTargetClass()( tool, context_id, *args, **kw )
-
- return site, tool, ctx.__of__( tool )
-
- def _makeFile( self
- , tool
- , snapshot_id
- , filename
- , contents
- , content_type='text/plain'
- , mod_time=None
- , subdir=None
- ):
-
- snapshots = tool._getOb( 'snapshots' )
- folder = snapshot = snapshots._getOb( snapshot_id )
-
- if subdir is not None:
-
- for element in subdir.split( '/' ):
-
- try:
- folder = folder._getOb( element )
- except AttributeError:
- folder._setObject( element, Folder( element ) )
- folder = folder._getOb( element )
-
- file = File( filename, '', contents, content_type )
- folder._setObject( filename, file )
-
- if mod_time is not None:
-
- def __faux_mod_time():
- return mod_time
-
- folder.bobobase_modification_time = \
- file.bobobase_modification_time = __faux_mod_time
-
- return folder._getOb( filename )
-
- def test_ctorparms( self ):
-
- SNAPSHOT_ID = 'ctorparms'
- ENCODING = 'latin-1'
- site, tool, ctx = self._makeOne( SNAPSHOT_ID
- , encoding=ENCODING
- , should_purge=True
- )
-
- self.assertEqual( ctx.getEncoding(), ENCODING )
- self.assertEqual( ctx.shouldPurge(), True )
-
- def test_empty( self ):
-
- SNAPSHOT_ID = 'empty'
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
-
- self.assertEqual( ctx.getSite(), site )
- self.assertEqual( ctx.getEncoding(), None )
- self.assertEqual( ctx.shouldPurge(), False )
-
- # These methods are all specified to return 'None' for non-existing
- # paths / entities
- self.assertEqual( ctx.isDirectory( 'nonesuch/path' ), None )
- self.assertEqual( ctx.listDirectory( 'nonesuch/path' ), None )
-
- def test_readDataFile_nonesuch( self ):
-
- SNAPSHOT_ID = 'readDataFile_nonesuch'
- FILENAME = 'nonesuch.txt'
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
-
- self.assertEqual( ctx.readDataFile( FILENAME ), None )
- self.assertEqual( ctx.readDataFile( FILENAME, 'subdir' ), None )
-
- def test_readDataFile_simple( self ):
-
- from string import printable
-
- SNAPSHOT_ID = 'readDataFile_simple'
- FILENAME = 'simple.txt'
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
- self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable )
-
- self.assertEqual( ctx.readDataFile( FILENAME ), printable )
-
- def test_readDataFile_subdir( self ):
-
- from string import printable
-
- SNAPSHOT_ID = 'readDataFile_subdir'
- FILENAME = 'subdir.txt'
- SUBDIR = 'subdir'
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
- self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
- , subdir=SUBDIR )
-
- self.assertEqual( ctx.readDataFile( FILENAME, SUBDIR ), printable )
-
- def test_getLastModified_nonesuch( self ):
-
- SNAPSHOT_ID = 'getLastModified_nonesuch'
- FILENAME = 'nonesuch.txt'
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
-
- self.assertEqual( ctx.getLastModified( FILENAME ), None )
-
- def test_getLastModified_simple( self ):
-
- from string import printable
-
- SNAPSHOT_ID = 'getLastModified_simple'
- FILENAME = 'simple.txt'
- WHEN = DateTime( '2004-01-01T00:00:00Z' )
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
- file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
- , mod_time=WHEN )
-
- self.assertEqual( ctx.getLastModified( FILENAME ), WHEN )
-
- def test_getLastModified_subdir( self ):
-
- from string import printable
-
- SNAPSHOT_ID = 'getLastModified_subdir'
- FILENAME = 'subdir.txt'
- SUBDIR = 'subdir'
- PATH = '%s/%s' % ( SUBDIR, FILENAME )
- WHEN = DateTime( '2004-01-01T00:00:00Z' )
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
- file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
- , mod_time=WHEN, subdir=SUBDIR )
-
- self.assertEqual( ctx.getLastModified( PATH ), WHEN )
-
- def test_getLastModified_directory( self ):
-
- from string import printable
-
- SNAPSHOT_ID = 'readDataFile_subdir'
- FILENAME = 'subdir.txt'
- SUBDIR = 'subdir'
- WHEN = DateTime( '2004-01-01T00:00:00Z' )
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
- file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
- , mod_time=WHEN, subdir=SUBDIR )
-
- self.assertEqual( ctx.getLastModified( SUBDIR ), WHEN )
-
- def test_isDirectory_nonesuch( self ):
-
- SNAPSHOT_ID = 'isDirectory_nonesuch'
- FILENAME = 'nonesuch.txt'
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
-
- self.assertEqual( ctx.isDirectory( FILENAME ), None )
-
- def test_isDirectory_simple( self ):
-
- from string import printable
-
- SNAPSHOT_ID = 'isDirectory_simple'
- FILENAME = 'simple.txt'
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
- file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable )
-
- self.assertEqual( ctx.isDirectory( FILENAME ), False )
-
- def test_isDirectory_nested( self ):
-
- from string import printable
-
- SNAPSHOT_ID = 'isDirectory_nested'
- SUBDIR = 'subdir'
- FILENAME = 'nested.txt'
- PATH = '%s/%s' % ( SUBDIR, FILENAME )
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
- file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
- , subdir=SUBDIR )
-
- self.assertEqual( ctx.isDirectory( PATH ), False )
-
- def test_isDirectory_subdir( self ):
-
- from string import printable
-
- SNAPSHOT_ID = 'isDirectory_subdir'
- SUBDIR = 'subdir'
- FILENAME = 'nested.txt'
- PATH = '%s/%s' % ( SUBDIR, FILENAME )
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
- file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
- , subdir=SUBDIR )
-
- self.assertEqual( ctx.isDirectory( SUBDIR ), True )
-
- def test_listDirectory_nonesuch( self ):
-
- SNAPSHOT_ID = 'listDirectory_nonesuch'
- SUBDIR = 'nonesuch/path'
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
-
- self.assertEqual( ctx.listDirectory( SUBDIR ), None )
-
- def test_listDirectory_root( self ):
-
- from string import printable
-
- SNAPSHOT_ID = 'listDirectory_root'
- FILENAME = 'simple.txt'
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
- file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable )
-
- self.assertEqual( len( ctx.listDirectory( None ) ), 1 )
- self.failUnless( FILENAME in ctx.listDirectory( None ) )
-
- def test_listDirectory_simple( self ):
-
- from string import printable
-
- SNAPSHOT_ID = 'listDirectory_simple'
- FILENAME = 'simple.txt'
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
- file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable )
-
- self.assertEqual( ctx.listDirectory( FILENAME ), None )
-
- def test_listDirectory_nested( self ):
-
- from string import printable
-
- SNAPSHOT_ID = 'listDirectory_nested'
- SUBDIR = 'subdir'
- FILENAME = 'nested.txt'
- PATH = '%s/%s' % ( SUBDIR, FILENAME )
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
- file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
- , subdir=SUBDIR )
-
- self.assertEqual( ctx.listDirectory( PATH ), None )
-
- def test_listDirectory_single( self ):
-
- from string import printable
-
- SNAPSHOT_ID = 'listDirectory_nested'
- SUBDIR = 'subdir'
- FILENAME = 'nested.txt'
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
- file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
- , subdir=SUBDIR )
-
- names = ctx.listDirectory( SUBDIR )
- self.assertEqual( len( names ), 1 )
- self.failUnless( FILENAME in names )
-
- def test_listDirectory_multiple( self ):
-
- from string import printable, uppercase
-
- SNAPSHOT_ID = 'listDirectory_nested'
- SUBDIR = 'subdir'
- FILENAME1 = 'nested.txt'
- FILENAME2 = 'another.txt'
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
- file1 = self._makeFile( tool, SNAPSHOT_ID, FILENAME1, printable
- , subdir=SUBDIR )
- file2 = self._makeFile( tool, SNAPSHOT_ID, FILENAME2, uppercase
- , subdir=SUBDIR )
-
- names = ctx.listDirectory( SUBDIR )
- self.assertEqual( len( names ), 2 )
- self.failUnless( FILENAME1 in names )
- self.failUnless( FILENAME2 in names )
-
- def test_listDirectory_skip( self ):
-
- from string import printable, uppercase
-
- SNAPSHOT_ID = 'listDirectory_nested'
- SUBDIR = 'subdir'
- FILENAME1 = 'nested.txt'
- FILENAME2 = 'another.txt'
-
- site, tool, ctx = self._makeOne( SNAPSHOT_ID )
- file1 = self._makeFile( tool, SNAPSHOT_ID, FILENAME1, printable
- , subdir=SUBDIR )
- file2 = self._makeFile( tool, SNAPSHOT_ID, FILENAME2, uppercase
- , subdir=SUBDIR )
-
- names = ctx.listDirectory( SUBDIR, skip=( FILENAME1, ) )
- self.assertEqual( len( names ), 1 )
- self.failIf( FILENAME1 in names )
- self.failUnless( FILENAME2 in names )
-
-
-def test_suite():
- return unittest.TestSuite((
- unittest.makeSuite( DirectoryImportContextTests ),
- unittest.makeSuite( DirectoryExportContextTests ),
- unittest.makeSuite( TarballExportContextTests ),
- unittest.makeSuite( SnapshotExportContextTests ),
- unittest.makeSuite( SnapshotImportContextTests ),
- ))
-
-if __name__ == '__main__':
- unittest.main(defaultTest='test_suite')
Deleted: CMF/branches/goldegg-phase-1/CMFSetup/tests/test_differ.py
===================================================================
--- CMF/branches/goldegg-phase-1/CMFSetup/tests/test_differ.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/CMFSetup/tests/test_differ.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -1,406 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-""" Unit tests for differ module.
-
-$Id$
-"""
-
-import unittest
-import Testing
-import Zope2
-Zope2.startup()
-
-from OFS.Folder import Folder
-from OFS.Image import File
-
-from DateTime.DateTime import DateTime
-from Products.CMFCore.tests.base.testcase import SecurityRequestTest
-
-
-class DummySite( Folder ):
-
- pass
-
-
-class Test_unidiff( unittest.TestCase ):
-
- def test_unidiff_both_text( self ):
-
- from Products.CMFSetup.differ import unidiff
-
- diff_lines = unidiff( ONE_FOUR, ZERO_FOUR )
- diff_text = '\n'.join( diff_lines )
- self.assertEqual( diff_text, DIFF_TEXT )
-
- def test_unidiff_both_lines( self ):
-
- from Products.CMFSetup.differ import unidiff
-
- diff_lines = unidiff( ONE_FOUR.splitlines(), ZERO_FOUR.splitlines() )
- diff_text = '\n'.join( diff_lines )
- self.assertEqual( diff_text, DIFF_TEXT )
-
- def test_unidiff_mixed( self ):
-
- from Products.CMFSetup.differ import unidiff
-
- diff_lines = unidiff( ONE_FOUR, ZERO_FOUR.splitlines() )
- diff_text = '\n'.join( diff_lines )
- self.assertEqual( diff_text, DIFF_TEXT )
-
- def test_unidiff_ignore_blanks( self ):
-
- from Products.CMFSetup.differ import unidiff
-
- double_spaced = ONE_FOUR.replace( '\n', '\n\n' )
- diff_lines = unidiff( double_spaced
- , ZERO_FOUR.splitlines()
- , ignore_blanks=True
- )
-
- diff_text = '\n'.join( diff_lines )
- self.assertEqual( diff_text, DIFF_TEXT )
-
-ZERO_FOUR = """\
-zero
-one
-tree
-four
-"""
-
-ONE_FOUR = """\
-one
-two
-three
-four
-"""
-
-DIFF_TEXT = """\
---- original None
-+++ modified None
-@@ -1,4 +1,4 @@
-+zero
- one
--two
--three
-+tree
- four\
-"""
-
-class ConfigDiffTests( SecurityRequestTest ):
-
- site = None
- tool = None
-
- def _getTargetClass( self ):
-
- from Products.CMFSetup.differ import ConfigDiff
- return ConfigDiff
-
- def _makeOne( self, lhs, rhs, *args, **kw ):
-
- return self._getTargetClass()( lhs, rhs, *args, **kw )
-
- def _makeSite( self ):
-
- if self.site is not None:
- return
-
- site = self.site = DummySite( 'site' ).__of__( self.root )
- site._setObject( 'portal_setup', Folder( 'portal_setup' ) )
- self.tool = tool = site._getOb( 'portal_setup' )
-
- tool._setObject( 'snapshots', Folder( 'snapshots' ) )
-
- def _makeContext( self, context_id ):
-
- from Products.CMFSetup.context import SnapshotImportContext
-
- self._makeSite()
-
- if context_id not in self.tool.snapshots.objectIds():
- self.tool.snapshots._setObject( context_id, Folder( context_id ) )
-
- ctx = SnapshotImportContext( self.tool, context_id )
-
- return ctx.__of__( self.tool )
-
- def _makeDirectory( self, snapshot_id, subdir ):
-
- self._makeSite()
- folder = self.tool.snapshots._getOb( snapshot_id )
-
- for element in subdir.split( '/' ):
-
- try:
- folder = folder._getOb( element )
- except AttributeError:
- folder._setObject( element, Folder( element ) )
- folder = folder._getOb( element )
-
- return folder
-
- def _makeFile( self
- , snapshot_id
- , filename
- , contents
- , content_type='text/plain'
- , mod_time=None
- , subdir=None
- ):
-
- self._makeSite()
- snapshots = self.tool.snapshots
- snapshot = snapshots._getOb( snapshot_id )
-
- if subdir is not None:
- folder = self._makeDirectory( snapshot_id, subdir )
- else:
- folder = snapshot
-
- file = File( filename, '', contents, content_type )
- folder._setObject( filename, file )
-
- if mod_time is not None:
-
- def __faux_mod_time():
- return mod_time
-
- folder.bobobase_modification_time = \
- file.bobobase_modification_time = __faux_mod_time
-
- return folder._getOb( filename )
-
- def test_compare_empties( self ):
-
- lhs = self._makeContext( 'lhs' )
- rhs = self._makeContext( 'rhs' )
-
- cd = self._makeOne( lhs, rhs )
-
- diffs = cd.compare()
-
- self.assertEqual( diffs, '' )
-
- def test_compare_identical( self ):
-
- lhs = self._makeContext( 'lhs' )
- rhs = self._makeContext( 'rhs' )
-
- self._makeFile( 'lhs', 'test.txt', 'ABCDEF' )
- self._makeFile( 'lhs', 'again.txt', 'GHIJKL', subdir='sub' )
- self._makeFile( 'rhs', 'test.txt', 'ABCDEF' )
- self._makeFile( 'rhs', 'again.txt', 'GHIJKL', subdir='sub' )
-
- cd = self._makeOne( lhs, rhs )
-
- diffs = cd.compare()
-
- self.assertEqual( diffs, '' )
-
- def test_compare_changed_file( self ):
-
- BEFORE = DateTime( '2004-01-01T00:00:00Z' )
- AFTER = DateTime( '2004-02-29T23:59:59Z' )
-
- lhs = self._makeContext( 'lhs' )
- rhs = self._makeContext( 'rhs' )
-
- self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ', mod_time=BEFORE )
- self._makeFile( 'lhs', 'again.txt', 'GHIJKL', subdir='sub' )
- self._makeFile( 'rhs', 'test.txt', 'ABCDEF\nQRST', mod_time=AFTER )
- self._makeFile( 'rhs', 'again.txt', 'GHIJKL', subdir='sub' )
-
- cd = self._makeOne( lhs, rhs )
-
- diffs = cd.compare()
-
- self.assertEqual( diffs, TEST_TXT_DIFFS % ( BEFORE, AFTER ) )
-
- def test_compare_changed_file_ignore_blanks( self ):
-
- BEFORE = DateTime( '2004-01-01T00:00:00Z' )
- AFTER = DateTime( '2004-02-29T23:59:59Z' )
-
- lhs = self._makeContext( 'lhs' )
- rhs = self._makeContext( 'rhs' )
-
- self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ', mod_time=BEFORE )
- self._makeFile( 'rhs', 'test.txt', 'ABCDEF\n\n\nWXYZ', mod_time=AFTER )
-
- cd = self._makeOne( lhs, rhs, ignore_blanks=True )
-
- diffs = cd.compare()
-
- self.assertEqual( diffs, '' )
-
- def test_compare_changed_file_explicit_skip( self ):
-
- BEFORE = DateTime( '2004-01-01T00:00:00Z' )
- AFTER = DateTime( '2004-02-29T23:59:59Z' )
-
- lhs = self._makeContext( 'lhs' )
- rhs = self._makeContext( 'rhs' )
-
- self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ', subdir='skipme'
- , mod_time=BEFORE )
- self._makeFile( 'lhs', 'again.txt', 'GHIJKL', subdir='sub' )
- self._makeFile( 'rhs', 'test.txt', 'ABCDEF\nQRST', subdir='skipme'
- , mod_time=AFTER )
- self._makeFile( 'rhs', 'again.txt', 'GHIJKL', subdir='sub' )
-
- cd = self._makeOne( lhs, rhs, skip=[ 'skipme' ] )
-
- diffs = cd.compare()
-
- self.assertEqual( diffs, '' )
-
- def test_compare_changed_file_implicit_skip( self ):
-
- BEFORE = DateTime( '2004-01-01T00:00:00Z' )
- AFTER = DateTime( '2004-02-29T23:59:59Z' )
-
- lhs = self._makeContext( 'lhs' )
- rhs = self._makeContext( 'rhs' )
-
- self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ', subdir='CVS'
- , mod_time=BEFORE )
- self._makeFile( 'lhs', 'again.txt', 'GHIJKL', subdir='.svn'
- , mod_time=BEFORE )
-
- self._makeFile( 'rhs', 'test.txt', 'ABCDEF\nQRST', subdir='CVS'
- , mod_time=AFTER )
- self._makeFile( 'rhs', 'again.txt', 'MNOPQR', subdir='.svn'
- , mod_time=AFTER )
-
- cd = self._makeOne( lhs, rhs )
-
- diffs = cd.compare()
-
- self.assertEqual( diffs, '' )
-
- def test_compare_added_file_no_missing_as_empty( self ):
-
- lhs = self._makeContext( 'lhs' )
- rhs = self._makeContext( 'rhs' )
-
- self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ' )
- self._makeDirectory( 'lhs', subdir='sub' )
- self._makeFile( 'rhs', 'test.txt', 'ABCDEF\nWXYZ' )
- self._makeFile( 'rhs', 'again.txt', 'GHIJKL', subdir='sub' )
-
- cd = self._makeOne( lhs, rhs )
-
- diffs = cd.compare()
-
- self.assertEqual( diffs, ADDED_FILE_DIFFS_NO_MAE )
-
- def test_compare_added_file_missing_as_empty( self ):
-
- AFTER = DateTime( '2004-02-29T23:59:59Z' )
- lhs = self._makeContext( 'lhs' )
- rhs = self._makeContext( 'rhs' )
-
- self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ' )
- self._makeDirectory( 'lhs', subdir='sub' )
- self._makeFile( 'rhs', 'test.txt', 'ABCDEF\nWXYZ' )
- self._makeFile( 'rhs', 'again.txt', 'GHIJKL', subdir='sub'
- , mod_time=AFTER )
-
- cd = self._makeOne( lhs, rhs, missing_as_empty=True )
-
- diffs = cd.compare()
-
- self.assertEqual( diffs, ADDED_FILE_DIFFS_MAE % AFTER )
-
- def test_compare_removed_file_no_missing_as_empty( self ):
-
- lhs = self._makeContext( 'lhs' )
- rhs = self._makeContext( 'rhs' )
-
- self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ' )
- self._makeFile( 'lhs', 'again.txt', 'GHIJKL', subdir='sub' )
- self._makeFile( 'rhs', 'test.txt', 'ABCDEF\nWXYZ' )
- self._makeDirectory( 'rhs', subdir='sub' )
-
- cd = self._makeOne( lhs, rhs )
-
- diffs = cd.compare()
-
- self.assertEqual( diffs, REMOVED_FILE_DIFFS_NO_MAE )
-
- def test_compare_removed_file_missing_as_empty( self ):
-
- BEFORE = DateTime( '2004-01-01T00:00:00Z' )
- lhs = self._makeContext( 'lhs' )
- rhs = self._makeContext( 'rhs' )
-
- self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ' )
- self._makeFile( 'lhs', 'again.txt', 'GHIJKL', subdir='sub'
- , mod_time=BEFORE )
- self._makeFile( 'rhs', 'test.txt', 'ABCDEF\nWXYZ' )
- self._makeDirectory( 'rhs', subdir='sub' )
-
- cd = self._makeOne( lhs, rhs, missing_as_empty=True )
-
- diffs = cd.compare()
-
- self.assertEqual( diffs, REMOVED_FILE_DIFFS_MAE % BEFORE )
-
-
-TEST_TXT_DIFFS = """\
-Index: test.txt
-===================================================================
---- test.txt %s
-+++ test.txt %s
-@@ -1,2 +1,2 @@
- ABCDEF
--WXYZ
-+QRST\
-"""
-
-ADDED_FILE_DIFFS_NO_MAE = """\
-** File sub/again.txt added
-"""
-
-ADDED_FILE_DIFFS_MAE = """\
-Index: sub/again.txt
-===================================================================
---- sub/again.txt 0
-+++ sub/again.txt %s
-@@ -1,0 +1,1 @@
-+GHIJKL\
-"""
-
-REMOVED_FILE_DIFFS_NO_MAE = """\
-** File sub/again.txt removed
-"""
-
-REMOVED_FILE_DIFFS_MAE = """\
-Index: sub/again.txt
-===================================================================
---- sub/again.txt %s
-+++ sub/again.txt 0
-@@ -1,1 +1,0 @@
--GHIJKL\
-"""
-
-
-def test_suite():
- return unittest.TestSuite((
- unittest.makeSuite( Test_unidiff ),
- unittest.makeSuite( ConfigDiffTests ),
- ))
-
-if __name__ == '__main__':
- unittest.main(defaultTest='test_suite')
Deleted: CMF/branches/goldegg-phase-1/CMFSetup/tests/test_registry.py
===================================================================
--- CMF/branches/goldegg-phase-1/CMFSetup/tests/test_registry.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/CMFSetup/tests/test_registry.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -1,1098 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-""" Registry unit tests.
-
-$Id$
-"""
-
-import unittest
-import Testing
-import Zope2
-Zope2.startup()
-
-from OFS.Folder import Folder
-from Products.CMFSetup.tests.common import BaseRegistryTests
-from Products.CMFSetup import EXTENSION
-
-from conformance import ConformsToIStepRegistry
-from conformance import ConformsToIImportStepRegistry
-from conformance import ConformsToIExportStepRegistry
-from conformance import ConformsToIToolsetRegistry
-from conformance import ConformsToIProfileRegistry
-
-
-#==============================================================================
-# Dummy handlers
-#==============================================================================
-def ONE_FUNC( context ): pass
-def TWO_FUNC( context ): pass
-def THREE_FUNC( context ): pass
-def FOUR_FUNC( context ): pass
-
-ONE_FUNC_NAME = '%s.%s' % ( __name__, ONE_FUNC.__name__ )
-TWO_FUNC_NAME = '%s.%s' % ( __name__, TWO_FUNC.__name__ )
-THREE_FUNC_NAME = '%s.%s' % ( __name__, THREE_FUNC.__name__ )
-FOUR_FUNC_NAME = '%s.%s' % ( __name__, FOUR_FUNC.__name__ )
-
-
-#==============================================================================
-# SSR tests
-#==============================================================================
-class ImportStepRegistryTests( BaseRegistryTests
- , ConformsToIStepRegistry
- , ConformsToIImportStepRegistry
- ):
-
- def _getTargetClass( self ):
-
- from Products.CMFSetup.registry import ImportStepRegistry
- return ImportStepRegistry
-
- def test_empty( self ):
-
- registry = self._makeOne()
-
- self.assertEqual( len( registry.listSteps() ), 0 )
- self.assertEqual( len( registry.listStepMetadata() ), 0 )
- self.assertEqual( len( registry.sortSteps() ), 0 )
-
- def test_getStep_nonesuch( self ):
-
- registry = self._makeOne()
-
- self.assertEqual( registry.getStep( 'nonesuch' ), None )
- self.assertEqual( registry.getStep( 'nonesuch' ), None )
- default = object()
- self.failUnless( registry.getStepMetadata( 'nonesuch'
- , default ) is default )
- self.failUnless( registry.getStep( 'nonesuch', default ) is default )
- self.failUnless( registry.getStepMetadata( 'nonesuch'
- , default ) is default )
-
- def test_getStep_defaulted( self ):
-
- registry = self._makeOne()
- default = object()
-
- self.failUnless( registry.getStep( 'nonesuch', default ) is default )
- self.assertEqual( registry.getStepMetadata( 'nonesuch', {} ), {} )
-
- def test_registerStep_docstring( self ):
-
- def func_with_doc( site ):
- """This is the first line.
-
- This is the second line.
- """
- FUNC_NAME = '%s.%s' % ( __name__, func_with_doc.__name__ )
-
- registry = self._makeOne()
-
- registry.registerStep( id='docstring'
- , version='1'
- , handler=func_with_doc
- , dependencies=()
- )
-
- info = registry.getStepMetadata( 'docstring' )
- self.assertEqual( info[ 'id' ], 'docstring' )
- self.assertEqual( info[ 'handler' ], FUNC_NAME )
- self.assertEqual( info[ 'dependencies' ], () )
- self.assertEqual( info[ 'title' ], 'This is the first line.' )
- self.assertEqual( info[ 'description' ] , 'This is the second line.' )
-
- def test_registerStep_docstring_override( self ):
-
- def func_with_doc( site ):
- """This is the first line.
-
- This is the second line.
- """
- FUNC_NAME = '%s.%s' % ( __name__, func_with_doc.__name__ )
-
- registry = self._makeOne()
-
- registry.registerStep( id='docstring'
- , version='1'
- , handler=func_with_doc
- , dependencies=()
- , title='Title'
- )
-
- info = registry.getStepMetadata( 'docstring' )
- self.assertEqual( info[ 'id' ], 'docstring' )
- self.assertEqual( info[ 'handler' ], FUNC_NAME )
- self.assertEqual( info[ 'dependencies' ], () )
- self.assertEqual( info[ 'title' ], 'Title' )
- self.assertEqual( info[ 'description' ] , 'This is the second line.' )
-
- def test_registerStep_single( self ):
-
- registry = self._makeOne()
-
- registry.registerStep( id='one'
- , version='1'
- , handler=ONE_FUNC
- , dependencies=( 'two', 'three' )
- , title='One Step'
- , description='One small step'
- )
-
- steps = registry.listSteps()
- self.assertEqual( len( steps ), 1 )
- self.failUnless( 'one' in steps )
-
- sorted = registry.sortSteps()
- self.assertEqual( len( sorted ), 1 )
- self.assertEqual( sorted[ 0 ], 'one' )
-
- self.assertEqual( registry.getStep( 'one' ), ONE_FUNC )
-
- info = registry.getStepMetadata( 'one' )
- self.assertEqual( info[ 'id' ], 'one' )
- self.assertEqual( info[ 'version' ], '1' )
- self.assertEqual( info[ 'handler' ], ONE_FUNC_NAME )
- self.assertEqual( info[ 'dependencies' ], ( 'two', 'three' ) )
- self.assertEqual( info[ 'title' ], 'One Step' )
- self.assertEqual( info[ 'description' ], 'One small step' )
-
- info_list = registry.listStepMetadata()
- self.assertEqual( len( info_list ), 1 )
- self.assertEqual( info, info_list[ 0 ] )
-
- def test_registerStep_conflict( self ):
-
- registry = self._makeOne()
-
- registry.registerStep( id='one', version='1', handler=ONE_FUNC )
-
- self.assertRaises( KeyError
- , registry.registerStep
- , id='one'
- , version='0'
- , handler=ONE_FUNC
- )
-
- registry.registerStep( id='one', version='1', handler=ONE_FUNC )
-
- info_list = registry.listStepMetadata()
- self.assertEqual( len( info_list ), 1 )
-
- def test_registerStep_replacement( self ):
-
- registry = self._makeOne()
-
- registry.registerStep( id='one'
- , version='1'
- , handler=ONE_FUNC
- , dependencies=( 'two', 'three' )
- , title='One Step'
- , description='One small step'
- )
-
- registry.registerStep( id='one'
- , version='1.1'
- , handler=ONE_FUNC
- , dependencies=()
- , title='Leads to Another'
- , description='Another small step'
- )
-
- info = registry.getStepMetadata( 'one' )
- self.assertEqual( info[ 'id' ], 'one' )
- self.assertEqual( info[ 'version' ], '1.1' )
- self.assertEqual( info[ 'dependencies' ], () )
- self.assertEqual( info[ 'title' ], 'Leads to Another' )
- self.assertEqual( info[ 'description' ], 'Another small step' )
-
- def test_registerStep_multiple( self ):
-
- registry = self._makeOne()
-
- registry.registerStep( id='one'
- , version='1'
- , handler=ONE_FUNC
- , dependencies=()
- )
-
- registry.registerStep( id='two'
- , version='2'
- , handler=TWO_FUNC
- , dependencies=()
- )
-
- registry.registerStep( id='three'
- , version='3'
- , handler=THREE_FUNC
- , dependencies=()
- )
-
- steps = registry.listSteps()
- self.assertEqual( len( steps ), 3 )
- self.failUnless( 'one' in steps )
- self.failUnless( 'two' in steps )
- self.failUnless( 'three' in steps )
-
- def test_sortStep_simple( self ):
-
- registry = self._makeOne()
-
- registry.registerStep( id='one'
- , version='1'
- , handler=ONE_FUNC
- , dependencies=( 'two', )
- )
-
- registry.registerStep( id='two'
- , version='2'
- , handler=TWO_FUNC
- , dependencies=()
- )
-
- steps = registry.sortSteps()
- self.assertEqual( len( steps ), 2 )
- one = steps.index( 'one' )
- two = steps.index( 'two' )
-
- self.failUnless( 0 <= two < one )
-
- def test_sortStep_chained( self ):
-
- registry = self._makeOne()
-
- registry.registerStep( id='one'
- , version='1'
- , handler=ONE_FUNC
- , dependencies=( 'two', )
- , title='One small step'
- )
-
- registry.registerStep( id='two'
- , version='2'
- , handler=TWO_FUNC
- , dependencies=( 'three', )
- , title='Texas two step'
- )
-
- registry.registerStep( id='three'
- , version='3'
- , handler=THREE_FUNC
- , dependencies=()
- , title='Gimme three steps'
- )
-
- steps = registry.sortSteps()
- self.assertEqual( len( steps ), 3 )
- one = steps.index( 'one' )
- two = steps.index( 'two' )
- three = steps.index( 'three' )
-
- self.failUnless( 0 <= three < two < one )
-
- def test_sortStep_complex( self ):
-
- registry = self._makeOne()
-
- registry.registerStep( id='one'
- , version='1'
- , handler=ONE_FUNC
- , dependencies=( 'two', )
- , title='One small step'
- )
-
- registry.registerStep( id='two'
- , version='2'
- , handler=TWO_FUNC
- , dependencies=( 'four', )
- , title='Texas two step'
- )
-
- registry.registerStep( id='three'
- , version='3'
- , handler=THREE_FUNC
- , dependencies=( 'four', )
- , title='Gimme three steps'
- )
-
- registry.registerStep( id='four'
- , version='4'
- , handler=FOUR_FUNC
- , dependencies=()
- , title='Four step program'
- )
-
- steps = registry.sortSteps()
- self.assertEqual( len( steps ), 4 )
- one = steps.index( 'one' )
- two = steps.index( 'two' )
- three = steps.index( 'three' )
- four = steps.index( 'four' )
-
- self.failUnless( 0 <= four < two < one )
- self.failUnless( 0 <= four < three )
-
- def test_sortStep_equivalence( self ):
-
- registry = self._makeOne()
-
- registry.registerStep( id='one'
- , version='1'
- , handler=ONE_FUNC
- , dependencies=( 'two', 'three' )
- , title='One small step'
- )
-
- registry.registerStep( id='two'
- , version='2'
- , handler=TWO_FUNC
- , dependencies=( 'four', )
- , title='Texas two step'
- )
-
- registry.registerStep( id='three'
- , version='3'
- , handler=THREE_FUNC
- , dependencies=( 'four', )
- , title='Gimme three steps'
- )
-
- registry.registerStep( id='four'
- , version='4'
- , handler=FOUR_FUNC
- , dependencies=()
- , title='Four step program'
- )
-
- steps = registry.sortSteps()
- self.assertEqual( len( steps ), 4 )
- one = steps.index( 'one' )
- two = steps.index( 'two' )
- three = steps.index( 'three' )
- four = steps.index( 'four' )
-
- self.failUnless( 0 <= four < two < one )
- self.failUnless( 0 <= four < three < one )
-
- def test_checkComplete_simple( self ):
-
- registry = self._makeOne()
-
- registry.registerStep( id='one'
- , version='1'
- , handler=ONE_FUNC
- , dependencies=( 'two', )
- )
-
- incomplete = registry.checkComplete()
- self.assertEqual( len( incomplete ), 1 )
- self.failUnless( ( 'one', 'two' ) in incomplete )
-
- registry.registerStep( id='two'
- , version='2'
- , handler=TWO_FUNC
- , dependencies=()
- )
-
- self.assertEqual( len( registry.checkComplete() ), 0 )
-
- def test_checkComplete_double( self ):
-
- registry = self._makeOne()
-
- registry.registerStep( id='one'
- , version='1'
- , handler=ONE_FUNC
- , dependencies=( 'two', 'three' )
- )
-
- incomplete = registry.checkComplete()
- self.assertEqual( len( incomplete ), 2 )
- self.failUnless( ( 'one', 'two' ) in incomplete )
- self.failUnless( ( 'one', 'three' ) in incomplete )
-
- registry.registerStep( id='two'
- , version='2'
- , handler=TWO_FUNC
- , dependencies=()
- )
-
- incomplete = registry.checkComplete()
- self.assertEqual( len( incomplete ), 1 )
- self.failUnless( ( 'one', 'three' ) in incomplete )
-
- registry.registerStep( id='three'
- , version='3'
- , handler=THREE_FUNC
- , dependencies=()
- )
-
- self.assertEqual( len( registry.checkComplete() ), 0 )
-
- registry.registerStep( id='two'
- , version='2.1'
- , handler=TWO_FUNC
- , dependencies=( 'four', )
- )
-
- incomplete = registry.checkComplete()
- self.assertEqual( len( incomplete ), 1 )
- self.failUnless( ( 'two', 'four' ) in incomplete )
-
- def test_generateXML_empty( self ):
-
- registry = self._makeOne().__of__( self.root )
-
- xml = registry.generateXML()
-
- self._compareDOM( registry.generateXML(), _EMPTY_IMPORT_XML )
-
- def test_generateXML_single( self ):
-
- registry = self._makeOne().__of__( self.root )
-
- registry.registerStep( id='one'
- , version='1'
- , handler=ONE_FUNC
- , dependencies=()
- , title='One Step'
- , description='One small step'
- )
-
- self._compareDOM( registry.generateXML(), _SINGLE_IMPORT_XML )
-
- def test_generateXML_ordered( self ):
-
- registry = self._makeOne().__of__( self.root )
-
- registry.registerStep( id='one'
- , version='1'
- , handler=ONE_FUNC
- , dependencies=( 'two', )
- , title='One Step'
- , description='One small step'
- )
-
- registry.registerStep( id='two'
- , version='2'
- , handler=TWO_FUNC
- , dependencies=( 'three', )
- , title='Two Steps'
- , description='Texas two step'
- )
-
- registry.registerStep( id='three'
- , version='3'
- , handler=THREE_FUNC
- , dependencies=()
- , title='Three Steps'
- , description='Gimme three steps'
- )
-
- self._compareDOM( registry.generateXML(), _ORDERED_IMPORT_XML )
-
- def test_parseXML_empty( self ):
-
- registry = self._makeOne().__of__( self.root )
-
- registry.registerStep( id='one'
- , version='1'
- , handler=ONE_FUNC
- , dependencies=()
- , description='One small step'
- )
-
- info_list = registry.parseXML( _EMPTY_IMPORT_XML )
-
- self.assertEqual( len( info_list ), 0 )
-
- def test_parseXML_single( self ):
-
- registry = self._makeOne().__of__( self.root )
-
- registry.registerStep( id='two'
- , version='2'
- , handler=TWO_FUNC
- , dependencies=()
- , title='Two Steps'
- , description='Texas two step'
- )
-
- info_list = registry.parseXML( _SINGLE_IMPORT_XML )
-
- self.assertEqual( len( info_list ), 1 )
-
- info = info_list[ 0 ]
- self.assertEqual( info[ 'id' ], 'one' )
- self.assertEqual( info[ 'version' ], '1' )
- self.assertEqual( info[ 'handler' ], ONE_FUNC_NAME )
- self.assertEqual( info[ 'dependencies' ], () )
- self.assertEqual( info[ 'title' ], 'One Step' )
- self.failUnless( 'One small step' in info[ 'description' ] )
-
-
-_EMPTY_IMPORT_XML = """\
-<?xml version="1.0"?>
-<import-steps>
-</import-steps>
-"""
-
-_SINGLE_IMPORT_XML = """\
-<?xml version="1.0"?>
-<import-steps>
- <import-step id="one"
- version="1"
- handler="%s"
- title="One Step">
- One small step
- </import-step>
-</import-steps>
-""" % ( ONE_FUNC_NAME, )
-
-_ORDERED_IMPORT_XML = """\
-<?xml version="1.0"?>
-<import-steps>
- <import-step id="one"
- version="1"
- handler="%s"
- title="One Step">
- <dependency step="two" />
- One small step
- </import-step>
- <import-step id="three"
- version="3"
- handler="%s"
- title="Three Steps">
- Gimme three steps
- </import-step>
- <import-step id="two"
- version="2"
- handler="%s"
- title="Two Steps">
- <dependency step="three" />
- Texas two step
- </import-step>
-</import-steps>
-""" % ( ONE_FUNC_NAME, THREE_FUNC_NAME, TWO_FUNC_NAME )
-
-
-#==============================================================================
-# ESR tests
-#==============================================================================
-class ExportStepRegistryTests( BaseRegistryTests
- , ConformsToIStepRegistry
- , ConformsToIExportStepRegistry
- ):
-
- def _getTargetClass( self ):
-
- from Products.CMFSetup.registry import ExportStepRegistry
- return ExportStepRegistry
-
- def _makeOne( self, *args, **kw ):
-
- return self._getTargetClass()( *args, **kw )
-
- def test_empty( self ):
-
- registry = self._makeOne()
- self.assertEqual( len( registry.listSteps() ), 0 )
- self.assertEqual( len( registry.listStepMetadata() ), 0 )
-
- def test_getStep_nonesuch( self ):
-
- registry = self._makeOne()
- self.assertEqual( registry.getStep( 'nonesuch' ), None )
-
- def test_getStep_defaulted( self ):
-
- registry = self._makeOne()
- default = lambda x: false
- self.assertEqual( registry.getStep( 'nonesuch', default ), default )
-
- def test_getStepMetadata_nonesuch( self ):
-
- registry = self._makeOne()
- self.assertEqual( registry.getStepMetadata( 'nonesuch' ), None )
-
- def test_getStepMetadata_defaulted( self ):
-
- registry = self._makeOne()
- self.assertEqual( registry.getStepMetadata( 'nonesuch', {} ), {} )
-
- def test_registerStep_simple( self ):
-
- registry = self._makeOne()
- registry.registerStep( 'one', ONE_FUNC )
- info = registry.getStepMetadata( 'one', {} )
-
- self.assertEqual( info[ 'id' ], 'one' )
- self.assertEqual( info[ 'handler' ], ONE_FUNC_NAME )
- self.assertEqual( info[ 'title' ], 'one' )
- self.assertEqual( info[ 'description' ], '' )
-
- def test_registerStep_docstring( self ):
-
- def func_with_doc( site ):
- """This is the first line.
-
- This is the second line.
- """
- FUNC_NAME = '%s.%s' % ( __name__, func_with_doc.__name__ )
-
- registry = self._makeOne()
- registry.registerStep( 'one', func_with_doc )
- info = registry.getStepMetadata( 'one', {} )
-
- self.assertEqual( info[ 'id' ], 'one' )
- self.assertEqual( info[ 'handler' ], FUNC_NAME )
- self.assertEqual( info[ 'title' ], 'This is the first line.' )
- self.assertEqual( info[ 'description' ] , 'This is the second line.' )
-
- def test_registerStep_docstring_with_override( self ):
-
- def func_with_doc( site ):
- """This is the first line.
-
- This is the second line.
- """
- FUNC_NAME = '%s.%s' % ( __name__, func_with_doc.__name__ )
-
- registry = self._makeOne()
- registry.registerStep( 'one', func_with_doc
- , description='Description' )
- info = registry.getStepMetadata( 'one', {} )
-
- self.assertEqual( info[ 'id' ], 'one' )
- self.assertEqual( info[ 'handler' ], FUNC_NAME )
- self.assertEqual( info[ 'title' ], 'This is the first line.' )
- self.assertEqual( info[ 'description' ], 'Description' )
-
- def test_registerStep_collision( self ):
-
- registry = self._makeOne()
- registry.registerStep( 'one', ONE_FUNC )
- registry.registerStep( 'one', TWO_FUNC )
- info = registry.getStepMetadata( 'one', {} )
-
- self.assertEqual( info[ 'id' ], 'one' )
- self.assertEqual( info[ 'handler' ], TWO_FUNC_NAME )
- self.assertEqual( info[ 'title' ], 'one' )
- self.assertEqual( info[ 'description' ], '' )
-
- def test_generateXML_empty( self ):
-
- registry = self._makeOne().__of__( self.root )
-
- xml = registry.generateXML()
-
- self._compareDOM( registry.generateXML(), _EMPTY_EXPORT_XML )
-
- def test_generateXML_single( self ):
-
- registry = self._makeOne().__of__( self.root )
-
- registry.registerStep( id='one'
- , handler=ONE_FUNC
- , title='One Step'
- , description='One small step'
- )
-
- self._compareDOM( registry.generateXML(), _SINGLE_EXPORT_XML )
-
- def test_generateXML_ordered( self ):
-
- registry = self._makeOne().__of__( self.root )
-
- registry.registerStep( id='one'
- , handler=ONE_FUNC
- , title='One Step'
- , description='One small step'
- )
-
- registry.registerStep( id='two'
- , handler=TWO_FUNC
- , title='Two Steps'
- , description='Texas two step'
- )
-
- registry.registerStep( id='three'
- , handler=THREE_FUNC
- , title='Three Steps'
- , description='Gimme three steps'
- )
-
- self._compareDOM( registry.generateXML(), _ORDERED_EXPORT_XML )
-
- def test_parseXML_empty( self ):
-
- registry = self._makeOne().__of__( self.root )
-
- registry.registerStep( id='one'
- , handler=ONE_FUNC
- , description='One small step'
- )
-
- info_list = registry.parseXML( _EMPTY_EXPORT_XML )
-
- self.assertEqual( len( info_list ), 0 )
-
- def test_parseXML_single( self ):
-
- registry = self._makeOne().__of__( self.root )
-
- registry.registerStep( id='two'
- , handler=TWO_FUNC
- , title='Two Steps'
- , description='Texas two step'
- )
-
- info_list = registry.parseXML( _SINGLE_EXPORT_XML )
-
- self.assertEqual( len( info_list ), 1 )
-
- info = info_list[ 0 ]
- self.assertEqual( info[ 'id' ], 'one' )
- self.assertEqual( info[ 'handler' ], ONE_FUNC_NAME )
- self.assertEqual( info[ 'title' ], 'One Step' )
- self.failUnless( 'One small step' in info[ 'description' ] )
-
- def test_parseXML_single_as_ascii( self ):
-
- registry = self._makeOne().__of__( self.root )
-
- registry.registerStep( id='two'
- , handler=TWO_FUNC
- , title='Two Steps'
- , description='Texas two step'
- )
-
- info_list = registry.parseXML( _SINGLE_EXPORT_XML, encoding='ascii' )
-
- self.assertEqual( len( info_list ), 1 )
-
- info = info_list[ 0 ]
- self.assertEqual( info[ 'id' ], 'one' )
- self.assertEqual( info[ 'handler' ], ONE_FUNC_NAME )
- self.assertEqual( info[ 'title' ], 'One Step' )
- self.failUnless( 'One small step' in info[ 'description' ] )
-
-
-_EMPTY_EXPORT_XML = """\
-<?xml version="1.0"?>
-<export-steps>
-</export-steps>
-"""
-
-_SINGLE_EXPORT_XML = """\
-<?xml version="1.0"?>
-<export-steps>
- <export-step id="one"
- handler="%s"
- title="One Step">
- One small step
- </export-step>
-</export-steps>
-""" % ( ONE_FUNC_NAME, )
-
-_ORDERED_EXPORT_XML = """\
-<?xml version="1.0"?>
-<export-steps>
- <export-step id="one"
- handler="%s"
- title="One Step">
- One small step
- </export-step>
- <export-step id="three"
- handler="%s"
- title="Three Steps">
- Gimme three steps
- </export-step>
- <export-step id="two"
- handler="%s"
- title="Two Steps">
- Texas two step
- </export-step>
-</export-steps>
-""" % ( ONE_FUNC_NAME, THREE_FUNC_NAME, TWO_FUNC_NAME )
-
-#==============================================================================
-# ToolsetRegistry tests
-#==============================================================================
-class ToolsetRegistryTests( BaseRegistryTests
- , ConformsToIToolsetRegistry
- ):
-
- def _getTargetClass( self ):
-
- from Products.CMFSetup.registry import ToolsetRegistry
- return ToolsetRegistry
-
- def _initSite( self ):
-
- self.root.site = Folder( id='site' )
- site = self.root.site
-
- return site
-
- def test_empty( self ):
-
- site = self._initSite()
- configurator = self._makeOne().__of__( site )
-
- self.assertEqual( len( configurator.listForbiddenTools() ), 0 )
- self.assertEqual( len( configurator.listRequiredTools() ), 0 )
- self.assertEqual( len( configurator.listRequiredToolInfo() ), 0 )
-
- self.assertRaises( KeyError
- , configurator.getRequiredToolInfo, 'nonesuch' )
-
- def test_addForbiddenTool_multiple( self ):
-
- VERBOTTEN = ( 'foo', 'bar', 'bam' )
-
- site = self._initSite()
- configurator = self._makeOne().__of__( site )
-
- for verbotten in VERBOTTEN:
- configurator.addForbiddenTool( verbotten )
-
- self.assertEqual( len( configurator.listForbiddenTools() )
- , len( VERBOTTEN ) )
-
- for verbotten in configurator.listForbiddenTools():
- self.failUnless( verbotten in VERBOTTEN )
-
- def test_addForbiddenTool_duplicate( self ):
-
- site = self._initSite()
- configurator = self._makeOne().__of__( site )
-
- configurator.addForbiddenTool( 'once' )
- configurator.addForbiddenTool( 'once' )
-
- self.assertEqual( len( configurator.listForbiddenTools() ), 1 )
-
- def test_addForbiddenTool_but_required( self ):
-
- site = self._initSite()
- configurator = self._makeOne().__of__( site )
-
- configurator.addRequiredTool( 'required', 'some.dotted.name' )
-
- self.assertRaises( ValueError
- , configurator.addForbiddenTool, 'required' )
-
- def test_addRequiredTool_multiple( self ):
-
- REQUIRED = ( ( 'one', 'path.to.one' )
- , ( 'two', 'path.to.two' )
- , ( 'three', 'path.to.three' )
- )
-
- site = self._initSite()
- configurator = self._makeOne().__of__( site )
-
- for tool_id, dotted_name in REQUIRED:
- configurator.addRequiredTool( tool_id, dotted_name )
-
- self.assertEqual( len( configurator.listRequiredTools() )
- , len( REQUIRED ) )
-
- for id in [ x[0] for x in REQUIRED ]:
- self.failUnless( id in configurator.listRequiredTools() )
-
- self.assertEqual( len( configurator.listRequiredToolInfo() )
- , len( REQUIRED ) )
-
- for tool_id, dotted_name in REQUIRED:
- info = configurator.getRequiredToolInfo( tool_id )
- self.assertEqual( info[ 'id' ], tool_id )
- self.assertEqual( info[ 'class' ], dotted_name )
-
- def test_addRequiredTool_duplicate( self ):
-
- site = self._initSite()
- configurator = self._makeOne().__of__( site )
-
- configurator.addRequiredTool( 'required', 'some.dotted.name' )
- configurator.addRequiredTool( 'required', 'another.name' )
-
- info = configurator.getRequiredToolInfo( 'required' )
- self.assertEqual( info[ 'id' ], 'required' )
- self.assertEqual( info[ 'class' ], 'another.name' )
-
- def test_addRequiredTool_but_forbidden( self ):
-
- site = self._initSite()
- configurator = self._makeOne().__of__( site )
-
- configurator.addForbiddenTool( 'forbidden' )
-
- self.assertRaises( ValueError
- , configurator.addRequiredTool
- , 'forbidden'
- , 'a.name'
- )
-
- def test_generateXML_empty( self ):
-
- site = self._initSite()
- configurator = self._makeOne().__of__( site )
-
- self._compareDOM( configurator.generateXML(), _EMPTY_TOOLSET_XML )
-
- def test_generateXML_normal( self ):
-
- site = self._initSite()
- configurator = self._makeOne().__of__( site )
-
- configurator.addForbiddenTool( 'doomed' )
- configurator.addRequiredTool( 'mandatory', 'path.to.one' )
- configurator.addRequiredTool( 'obligatory', 'path.to.another' )
-
- configurator.parseXML( _NORMAL_TOOLSET_XML )
-
- def test_parseXML_empty( self ):
-
- site = self._initSite()
- configurator = self._makeOne().__of__( site )
-
- configurator.parseXML( _EMPTY_TOOLSET_XML )
-
- self.assertEqual( len( configurator.listForbiddenTools() ), 0 )
- self.assertEqual( len( configurator.listRequiredTools() ), 0 )
-
- def test_parseXML_normal( self ):
-
- site = self._initSite()
- configurator = self._makeOne().__of__( site )
-
- configurator.parseXML( _NORMAL_TOOLSET_XML )
-
- self.assertEqual( len( configurator.listForbiddenTools() ), 1 )
- self.failUnless( 'doomed' in configurator.listForbiddenTools() )
-
- self.assertEqual( len( configurator.listRequiredTools() ), 2 )
-
- self.failUnless( 'mandatory' in configurator.listRequiredTools() )
- info = configurator.getRequiredToolInfo( 'mandatory' )
- self.assertEqual( info[ 'class' ], 'path.to.one' )
-
- self.failUnless( 'obligatory' in configurator.listRequiredTools() )
- info = configurator.getRequiredToolInfo( 'obligatory' )
- self.assertEqual( info[ 'class' ], 'path.to.another' )
-
- def test_parseXML_confused( self ):
-
- site = self._initSite()
- configurator = self._makeOne().__of__( site )
-
- self.assertRaises( ValueError
- , configurator.parseXML, _CONFUSED_TOOLSET_XML )
-
-
-_EMPTY_TOOLSET_XML = """\
-<?xml version="1.0"?>
-<tool-setup>
-</tool-setup>
-"""
-
-_NORMAL_TOOLSET_XML = """\
-<?xml version="1.0"?>
-<tool-setup>
- <forbidden tool_id="doomed" />
- <required tool_id="mandatory" class="path.to.one" />
- <required tool_id="obligatory" class="path.to.another" />
-</tool-setup>
-"""
-
-_CONFUSED_TOOLSET_XML = """\
-<?xml version="1.0"?>
-<tool-setup>
- <forbidden tool_id="confused" />
- <required tool_id="confused" class="path.to.one" />
-</tool-setup>
-"""
-
-class ProfileRegistryTests( BaseRegistryTests
- , ConformsToIProfileRegistry
- ):
-
- def _getTargetClass( self ):
-
- from Products.CMFSetup.registry import ProfileRegistry
- return ProfileRegistry
-
- def test_empty( self ):
-
- registry = self._makeOne()
-
- self.assertEqual( len( registry.listProfiles() ), 0 )
- self.assertEqual( len( registry.listProfiles() ), 0 )
- self.assertRaises( KeyError, registry.getProfileInfo, 'nonesuch' )
-
- def test_registerProfile_normal( self ):
-
- NAME = 'one'
- TITLE = 'One'
- DESCRIPTION = 'One profile'
- PATH = '/path/to/one'
- PRODUCT = 'TestProduct'
- PROFILE_TYPE = EXTENSION
- PROFILE_ID = 'TestProduct:one'
-
- registry = self._makeOne()
- registry.registerProfile( NAME
- , TITLE
- , DESCRIPTION
- , PATH
- , PRODUCT
- , PROFILE_TYPE
- )
-
- self.assertEqual( len( registry.listProfiles() ), 1 )
- self.assertEqual( len( registry.listProfileInfo() ), 1 )
-
- info = registry.getProfileInfo( PROFILE_ID )
-
- self.assertEqual( info[ 'id' ], PROFILE_ID )
- self.assertEqual( info[ 'title' ], TITLE )
- self.assertEqual( info[ 'description' ], DESCRIPTION )
- self.assertEqual( info[ 'path' ], PATH )
- self.assertEqual( info[ 'product' ], PRODUCT )
- self.assertEqual( info[ 'type' ], PROFILE_TYPE )
-
- def test_registerProfile_duplicate( self ):
-
- PROFILE_ID = 'one'
- TITLE = 'One'
- DESCRIPTION = 'One profile'
- PATH = '/path/to/one'
-
- registry = self._makeOne()
- registry.registerProfile( PROFILE_ID, TITLE, DESCRIPTION, PATH )
- self.assertRaises( KeyError
- , registry.registerProfile
- , PROFILE_ID, TITLE, DESCRIPTION, PATH )
-
-
-def test_suite():
- return unittest.TestSuite((
- unittest.makeSuite( ImportStepRegistryTests ),
- unittest.makeSuite( ExportStepRegistryTests ),
- unittest.makeSuite( ToolsetRegistryTests ),
- unittest.makeSuite( ProfileRegistryTests ),
- ))
-
-if __name__ == '__main__':
- unittest.main(defaultTest='test_suite')
Deleted: CMF/branches/goldegg-phase-1/CMFSetup/tests/test_rolemap.py
===================================================================
--- CMF/branches/goldegg-phase-1/CMFSetup/tests/test_rolemap.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/CMFSetup/tests/test_rolemap.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -1,784 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-""" CMFSetup rolemap export / import unit tests
-
-$Id$
-"""
-
-import unittest
-import Testing
-import Zope2
-Zope2.startup()
-
-from OFS.Folder import Folder
-
-from common import BaseRegistryTests
-from common import DummyExportContext
-from common import DummyImportContext
-
-class RolemapConfiguratorTests( BaseRegistryTests ):
-
- def _getTargetClass( self ):
-
- from Products.CMFSetup.rolemap import RolemapConfigurator
- return RolemapConfigurator
-
- def test_listRoles_normal( self ):
-
- EXPECTED = [ 'Anonymous', 'Authenticated', 'Manager', 'Owner' ]
- self.root.site = Folder( id='site' )
- site = self.root.site
- configurator = self._makeOne( site )
-
- roles = list( configurator.listRoles() )
- self.assertEqual( len( roles ), len( EXPECTED ) )
-
- roles.sort()
-
- for found, expected in zip( roles, EXPECTED ):
- self.assertEqual( found, expected )
-
- def test_listRoles_added( self ):
-
- EXPECTED = [ 'Anonymous', 'Authenticated', 'Manager', 'Owner', 'ZZZ' ]
- self.root.site = Folder( id='site' )
- site = self.root.site
- existing_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
- existing_roles.append( 'ZZZ' )
- site.__ac_roles__ = existing_roles
-
- configurator = self._makeOne( site )
-
- roles = list( configurator.listRoles() )
- self.assertEqual( len( roles ), len( EXPECTED ) )
-
- roles.sort()
-
- for found, expected in zip( roles, EXPECTED ):
- self.assertEqual( found, expected )
-
- def test_listPermissions_nooverrides( self ):
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- configurator = self._makeOne( site )
-
- self.assertEqual( len( configurator.listPermissions() ), 0 )
-
- def test_listPermissions_nooverrides( self ):
-
- site = Folder( id='site' ).__of__( self.root )
- configurator = self._makeOne( site )
-
- self.assertEqual( len( configurator.listPermissions() ), 0 )
-
- def test_listPermissions_acquire( self ):
-
- ACI = 'Access contents information'
- ROLES = [ 'Manager', 'Owner' ]
-
- site = Folder( id='site' ).__of__( self.root )
- site.manage_permission( ACI, ROLES, acquire=1 )
- configurator = self._makeOne( site )
-
- self.assertEqual( len( configurator.listPermissions() ), 1 )
- info = configurator.listPermissions()[ 0 ]
- self.assertEqual( info[ 'name' ], ACI )
- self.assertEqual( info[ 'roles' ], ROLES )
- self.failUnless( info[ 'acquire' ] )
-
- def test_listPermissions_no_acquire( self ):
-
- ACI = 'Access contents information'
- ROLES = [ 'Manager', 'Owner' ]
-
- site = Folder( id='site' ).__of__( self.root )
- site.manage_permission( ACI, ROLES )
- configurator = self._makeOne( site )
-
- self.assertEqual( len( configurator.listPermissions() ), 1 )
- info = configurator.listPermissions()[ 0 ]
- self.assertEqual( info[ 'name' ], ACI )
- self.assertEqual( info[ 'roles' ], ROLES )
- self.failIf( info[ 'acquire' ] )
-
- def test_generateXML_empty( self ):
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- configurator = self._makeOne( site ).__of__( site )
-
- self._compareDOM( configurator.generateXML(), _EMPTY_EXPORT )
-
- def test_generateXML_added_role( self ):
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- existing_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
- existing_roles.append( 'ZZZ' )
- site.__ac_roles__ = existing_roles
- configurator = self._makeOne( site ).__of__( site )
-
- self._compareDOM( configurator.generateXML(), _ADDED_ROLE_EXPORT )
-
- def test_generateEXML_acquired_perm( self ):
-
- ACI = 'Access contents information'
- ROLES = [ 'Manager', 'Owner' ]
-
- site = Folder( id='site' ).__of__( self.root )
- site.manage_permission( ACI, ROLES, acquire=1 )
- configurator = self._makeOne( site ).__of__( site )
-
- self._compareDOM( configurator.generateXML(), _ACQUIRED_EXPORT )
-
- def test_generateEXML_unacquired_perm( self ):
-
- ACI = 'Access contents information'
- ROLES = [ 'Manager', 'Owner', 'ZZZ' ]
-
- site = Folder( id='site' ).__of__( self.root )
- existing_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
- existing_roles.append( 'ZZZ' )
- site.__ac_roles__ = existing_roles
- site.manage_permission( ACI, ROLES )
- configurator = self._makeOne( site ).__of__( site )
-
- self._compareDOM( configurator.generateXML(), _COMBINED_EXPORT )
-
- def test_generateEXML_unacquired_perm_added_role( self ):
-
- ACI = 'Access contents information'
- ROLES = [ 'Manager', 'Owner' ]
-
- site = Folder( id='site' ).__of__( self.root )
- site.manage_permission( ACI, ROLES )
- configurator = self._makeOne( site ).__of__( site )
-
- self._compareDOM( configurator.generateXML(), _UNACQUIRED_EXPORT )
-
- def test_parseXML_empty( self ):
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- existing_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
- configurator = self._makeOne( site )
-
- rolemap_info = configurator.parseXML( _EMPTY_EXPORT )
-
- self.assertEqual( len( rolemap_info[ 'roles' ] ), 4 )
- self.assertEqual( len( rolemap_info[ 'permissions' ] ), 0 )
-
- def test_parseXML_added_role( self ):
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- configurator = self._makeOne( site )
-
- rolemap_info = configurator.parseXML( _ADDED_ROLE_EXPORT )
- roles = rolemap_info[ 'roles' ]
-
- self.assertEqual( len( roles ), 5 )
- self.failUnless( 'Anonymous' in roles )
- self.failUnless( 'Authenticated' in roles )
- self.failUnless( 'Manager' in roles )
- self.failUnless( 'Owner' in roles )
- self.failUnless( 'ZZZ' in roles )
-
- def test_parseXML_acquired_permission( self ):
-
- ACI = 'Access contents information'
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- configurator = self._makeOne( site )
-
- rolemap_info = configurator.parseXML( _ACQUIRED_EXPORT )
-
- self.assertEqual( len( rolemap_info[ 'permissions' ] ), 1 )
- permission = rolemap_info[ 'permissions' ][ 0 ]
-
- self.assertEqual( permission[ 'name' ], ACI )
- self.failUnless( permission[ 'acquire' ] )
-
- p_roles = permission[ 'roles' ]
- self.assertEqual( len( p_roles ), 2 )
- self.failUnless( 'Manager' in p_roles )
- self.failUnless( 'Owner' in p_roles )
-
- def test_parseXML_unacquired_permission( self ):
-
- ACI = 'Access contents information'
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- configurator = self._makeOne( site )
-
- rolemap_info = configurator.parseXML( _UNACQUIRED_EXPORT )
-
- self.assertEqual( len( rolemap_info[ 'permissions' ] ), 1 )
- permission = rolemap_info[ 'permissions' ][ 0 ]
-
- self.assertEqual( permission[ 'name' ], ACI )
- self.failIf( permission[ 'acquire' ] )
-
- p_roles = permission[ 'roles' ]
- self.assertEqual( len( p_roles ), 2 )
- self.failUnless( 'Manager' in p_roles )
- self.failUnless( 'Owner' in p_roles )
-
- def test_parseXML_unacquired_permission_added_role( self ):
-
- ACI = 'Access contents information'
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- configurator = self._makeOne( site )
-
- rolemap_info = configurator.parseXML( _COMBINED_EXPORT )
- roles = rolemap_info[ 'roles' ]
-
- self.assertEqual( len( roles ), 5 )
- self.failUnless( 'Anonymous' in roles )
- self.failUnless( 'Authenticated' in roles )
- self.failUnless( 'Manager' in roles )
- self.failUnless( 'Owner' in roles )
- self.failUnless( 'ZZZ' in roles )
-
- self.assertEqual( len( rolemap_info[ 'permissions' ] ), 1 )
- permission = rolemap_info[ 'permissions' ][ 0 ]
-
- self.assertEqual( permission[ 'name' ], ACI )
- self.failIf( permission[ 'acquire' ] )
-
- p_roles = permission[ 'roles' ]
- self.assertEqual( len( p_roles ), 3 )
- self.failUnless( 'Manager' in p_roles )
- self.failUnless( 'Owner' in p_roles )
- self.failUnless( 'ZZZ' in p_roles )
-
-
-
-_EMPTY_EXPORT = """\
-<?xml version="1.0"?>
-<rolemap>
- <roles>
- <role name="Anonymous"/>
- <role name="Authenticated"/>
- <role name="Manager"/>
- <role name="Owner"/>
- </roles>
- <permissions>
- </permissions>
-</rolemap>
-"""
-
-_ADDED_ROLE_EXPORT = """\
-<?xml version="1.0"?>
-<rolemap>
- <roles>
- <role name="Anonymous"/>
- <role name="Authenticated"/>
- <role name="Manager"/>
- <role name="Owner"/>
- <role name="ZZZ"/>
- </roles>
- <permissions>
- </permissions>
-</rolemap>
-"""
-
-_ACQUIRED_EXPORT = """\
-<?xml version="1.0"?>
-<rolemap>
- <roles>
- <role name="Anonymous"/>
- <role name="Authenticated"/>
- <role name="Manager"/>
- <role name="Owner"/>
- </roles>
- <permissions>
- <permission name="Access contents information"
- acquire="True">
- <role name="Manager"/>
- <role name="Owner"/>
- </permission>
- </permissions>
-</rolemap>
-"""
-
-_UNACQUIRED_EXPORT = """\
-<?xml version="1.0"?>
-<rolemap>
- <roles>
- <role name="Anonymous"/>
- <role name="Authenticated"/>
- <role name="Manager"/>
- <role name="Owner"/>
- </roles>
- <permissions>
- <permission name="Access contents information"
- acquire="False">
- <role name="Manager"/>
- <role name="Owner"/>
- </permission>
- </permissions>
-</rolemap>
-"""
-
-_COMBINED_EXPORT = """\
-<?xml version="1.0"?>
-<rolemap>
- <roles>
- <role name="Anonymous"/>
- <role name="Authenticated"/>
- <role name="Manager"/>
- <role name="Owner"/>
- <role name="ZZZ"/>
- </roles>
- <permissions>
- <permission name="Access contents information"
- acquire="False">
- <role name="Manager"/>
- <role name="Owner"/>
- <role name="ZZZ"/>
- </permission>
- </permissions>
-</rolemap>
-"""
-
-class Test_exportRolemap( BaseRegistryTests ):
-
- def test_unchanged( self ):
-
- self.root.site = Folder( 'site' )
- site = self.root.site
-
- context = DummyExportContext( site )
-
- from Products.CMFSetup.rolemap import exportRolemap
- exportRolemap( context )
-
- self.assertEqual( len( context._wrote ), 1 )
- filename, text, content_type = context._wrote[ 0 ]
- self.assertEqual( filename, 'rolemap.xml' )
- self._compareDOM( text, _EMPTY_EXPORT )
- self.assertEqual( content_type, 'text/xml' )
-
- def test_added_role( self ):
-
- self.root.site = Folder( 'site' )
- site = self.root.site
- existing_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
- existing_roles.append( 'ZZZ' )
- site.__ac_roles__ = existing_roles
-
- context = DummyExportContext( site )
-
- from Products.CMFSetup.rolemap import exportRolemap
- exportRolemap( context )
-
- self.assertEqual( len( context._wrote ), 1 )
- filename, text, content_type = context._wrote[ 0 ]
- self.assertEqual( filename, 'rolemap.xml' )
- self._compareDOM( text, _ADDED_ROLE_EXPORT )
- self.assertEqual( content_type, 'text/xml' )
-
-
- def test_acquired_perm( self ):
-
- ACI = 'Access contents information'
- ROLES = [ 'Manager', 'Owner' ]
-
- self.root.site = Folder( 'site' )
- site = self.root.site
- site.manage_permission( ACI, ROLES, acquire=1 )
-
- context = DummyExportContext( site )
-
- from Products.CMFSetup.rolemap import exportRolemap
- exportRolemap( context )
-
- self.assertEqual( len( context._wrote ), 1 )
- filename, text, content_type = context._wrote[ 0 ]
- self.assertEqual( filename, 'rolemap.xml' )
- self._compareDOM( text, _ACQUIRED_EXPORT )
- self.assertEqual( content_type, 'text/xml' )
-
- def test_unacquired_perm( self ):
-
- ACI = 'Access contents information'
- ROLES = [ 'Manager', 'Owner', 'ZZZ' ]
-
- self.root.site = Folder( 'site' )
- site = self.root.site
- existing_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
- existing_roles.append( 'ZZZ' )
- site.__ac_roles__ = existing_roles
- site.manage_permission( ACI, ROLES )
-
- context = DummyExportContext( site )
-
- from Products.CMFSetup.rolemap import exportRolemap
- exportRolemap( context )
-
- self.assertEqual( len( context._wrote ), 1 )
- filename, text, content_type = context._wrote[ 0 ]
- self.assertEqual( filename, 'rolemap.xml' )
- self._compareDOM( text, _COMBINED_EXPORT )
- self.assertEqual( content_type, 'text/xml' )
-
- def test_unacquired_perm_added_role( self ):
-
- ACI = 'Access contents information'
- ROLES = [ 'Manager', 'Owner' ]
-
- self.root.site = Folder( 'site' )
- site = self.root.site
- site.manage_permission( ACI, ROLES )
-
- context = DummyExportContext( site )
-
- from Products.CMFSetup.rolemap import exportRolemap
- exportRolemap( context )
-
- self.assertEqual( len( context._wrote ), 1 )
- filename, text, content_type = context._wrote[ 0 ]
- self.assertEqual( filename, 'rolemap.xml' )
- self._compareDOM( text, _UNACQUIRED_EXPORT )
- self.assertEqual( content_type, 'text/xml' )
-
-class Test_importRolemap( BaseRegistryTests ):
-
- def test_empty_default_purge( self ):
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- original_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
- modified_roles = original_roles[:]
- modified_roles.append( 'ZZZ' )
- site.__ac_roles__ = modified_roles
-
- context = DummyImportContext( site )
- context._files[ 'rolemap.xml' ] = _EMPTY_EXPORT
-
- from Products.CMFSetup.rolemap import importRolemap
- importRolemap( context )
-
- new_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
-
- original_roles.sort()
- new_roles.sort()
-
- self.assertEqual( original_roles, new_roles )
-
- def test_empty_explicit_purge( self ):
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- original_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
- modified_roles = original_roles[:]
- modified_roles.append( 'ZZZ' )
- site.__ac_roles__ = modified_roles
-
- context = DummyImportContext( site, True )
- context._files[ 'rolemap.xml' ] = _EMPTY_EXPORT
-
- from Products.CMFSetup.rolemap import importRolemap
- importRolemap( context )
-
- new_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
-
- original_roles.sort()
- new_roles.sort()
-
- self.assertEqual( original_roles, new_roles )
-
- def test_empty_skip_purge( self ):
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- original_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
- modified_roles = original_roles[:]
- modified_roles.append( 'ZZZ' )
- site.__ac_roles__ = modified_roles
-
- context = DummyImportContext( site, False )
- context._files[ 'rolemap.xml' ] = _EMPTY_EXPORT
-
- from Products.CMFSetup.rolemap import importRolemap
- importRolemap( context )
-
- new_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
-
- modified_roles.sort()
- new_roles.sort()
-
- self.assertEqual( modified_roles, new_roles )
-
- def test_acquired_permission_explicit_purge( self ):
-
- ACI = 'Access contents information'
- VIEW = 'View'
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- site.manage_permission( ACI, () )
- site.manage_permission( VIEW, () )
-
- existing_allowed = [ x[ 'name' ]
- for x in site.rolesOfPermission( ACI )
- if x[ 'selected' ] ]
-
- self.assertEqual( existing_allowed, [] )
-
- self.failIf( site.acquiredRolesAreUsedBy( ACI ) )
- self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
-
- context = DummyImportContext( site, True )
- context._files[ 'rolemap.xml' ] = _ACQUIRED_EXPORT
-
- from Products.CMFSetup.rolemap import importRolemap
- importRolemap( context )
-
- new_allowed = [ x[ 'name' ]
- for x in site.rolesOfPermission( ACI )
- if x[ 'selected' ] ]
-
- self.assertEqual( new_allowed, [ 'Manager', 'Owner' ] )
-
- # ACI is overwritten by XML, but VIEW was purged
- self.failUnless( site.acquiredRolesAreUsedBy( ACI ) )
- self.failUnless( site.acquiredRolesAreUsedBy( VIEW ) )
-
- def test_acquired_permission_no_purge( self ):
-
- ACI = 'Access contents information'
- VIEW = 'View'
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- site.manage_permission( ACI, () )
- site.manage_permission( VIEW, () )
-
- existing_allowed = [ x[ 'name' ]
- for x in site.rolesOfPermission( ACI )
- if x[ 'selected' ] ]
-
- self.assertEqual( existing_allowed, [] )
-
- self.failIf( site.acquiredRolesAreUsedBy( ACI ) )
-
- context = DummyImportContext( site, False )
- context._files[ 'rolemap.xml' ] = _ACQUIRED_EXPORT
-
- from Products.CMFSetup.rolemap import importRolemap
- importRolemap( context )
-
- new_allowed = [ x[ 'name' ]
- for x in site.rolesOfPermission( ACI )
- if x[ 'selected' ] ]
-
- self.assertEqual( new_allowed, [ 'Manager', 'Owner' ] )
-
- # ACI is overwritten by XML, but VIEW is not
- self.failUnless( site.acquiredRolesAreUsedBy( ACI ) )
- self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
-
- def test_unacquired_permission_explicit_purge( self ):
-
- ACI = 'Access contents information'
- VIEW = 'View'
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- site.manage_permission( VIEW, () )
-
- existing_allowed = [ x[ 'name' ]
- for x in site.rolesOfPermission( ACI )
- if x[ 'selected' ] ]
-
- self.assertEqual( existing_allowed, [ 'Manager' ] )
-
- self.failUnless( site.acquiredRolesAreUsedBy( ACI ) )
- self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
-
- context = DummyImportContext( site, True )
- context._files[ 'rolemap.xml' ] = _UNACQUIRED_EXPORT
-
- from Products.CMFSetup.rolemap import importRolemap
- importRolemap( context )
-
- new_allowed = [ x[ 'name' ]
- for x in site.rolesOfPermission( ACI )
- if x[ 'selected' ] ]
-
- self.assertEqual( new_allowed, [ 'Manager', 'Owner' ] )
-
- self.failIf( site.acquiredRolesAreUsedBy( ACI ) )
- self.failUnless( site.acquiredRolesAreUsedBy( VIEW ) )
-
- def test_unacquired_permission_skip_purge( self ):
-
- ACI = 'Access contents information'
- VIEW = 'View'
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- site.manage_permission( VIEW, () )
-
- existing_allowed = [ x[ 'name' ]
- for x in site.rolesOfPermission( ACI )
- if x[ 'selected' ] ]
-
- self.assertEqual( existing_allowed, [ 'Manager' ] )
-
- self.failUnless( site.acquiredRolesAreUsedBy( ACI ) )
- self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
-
- context = DummyImportContext( site, False )
- context._files[ 'rolemap.xml' ] = _UNACQUIRED_EXPORT
-
- from Products.CMFSetup.rolemap import importRolemap
- importRolemap( context )
-
- new_allowed = [ x[ 'name' ]
- for x in site.rolesOfPermission( ACI )
- if x[ 'selected' ] ]
-
- self.assertEqual( new_allowed, [ 'Manager', 'Owner' ] )
-
- self.failIf( site.acquiredRolesAreUsedBy( ACI ) )
- self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
-
- def test_unacquired_permission_added_role_explicit_purge( self ):
-
- ACI = 'Access contents information'
- VIEW = 'View'
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- site.manage_permission( VIEW, () )
-
- existing_allowed = [ x[ 'name' ]
- for x in site.rolesOfPermission( ACI )
- if x[ 'selected' ] ]
-
- self.assertEqual( existing_allowed, [ 'Manager' ] )
-
- self.failUnless( site.acquiredRolesAreUsedBy( ACI ) )
- self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
-
- self.failIf( site._has_user_defined_role( 'ZZZ' ) )
-
- context = DummyImportContext( site, True )
- context._files[ 'rolemap.xml' ] = _COMBINED_EXPORT
-
- from Products.CMFSetup.rolemap import importRolemap
- importRolemap( context )
-
- self.failUnless( site._has_user_defined_role( 'ZZZ' ) )
-
- new_allowed = [ x[ 'name' ]
- for x in site.rolesOfPermission( ACI )
- if x[ 'selected' ] ]
-
- self.assertEqual( new_allowed, [ 'Manager', 'Owner', 'ZZZ' ] )
-
- self.failIf( site.acquiredRolesAreUsedBy( ACI ) )
- self.failUnless( site.acquiredRolesAreUsedBy( VIEW ) )
-
- def test_unacquired_permission_added_role_skip_purge( self ):
-
- ACI = 'Access contents information'
- VIEW = 'View'
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- site.manage_permission( VIEW, () )
-
- existing_allowed = [ x[ 'name' ]
- for x in site.rolesOfPermission( ACI )
- if x[ 'selected' ] ]
-
- self.assertEqual( existing_allowed, [ 'Manager' ] )
-
- self.failUnless( site.acquiredRolesAreUsedBy( ACI ) )
- self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
-
- self.failIf( site._has_user_defined_role( 'ZZZ' ) )
-
- context = DummyImportContext( site, False )
- context._files[ 'rolemap.xml' ] = _COMBINED_EXPORT
-
- from Products.CMFSetup.rolemap import importRolemap
- importRolemap( context )
-
- self.failUnless( site._has_user_defined_role( 'ZZZ' ) )
-
- new_allowed = [ x[ 'name' ]
- for x in site.rolesOfPermission( ACI )
- if x[ 'selected' ] ]
-
- self.assertEqual( new_allowed, [ 'Manager', 'Owner', 'ZZZ' ] )
-
- self.failIf( site.acquiredRolesAreUsedBy( ACI ) )
- self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
-
- def test_unacquired_permission_added_role_skip_purge_encode_ascii( self ):
-
- ACI = 'Access contents information'
- VIEW = 'View'
-
- self.root.site = Folder( id='site' )
- site = self.root.site
- site.manage_permission( VIEW, () )
-
- existing_allowed = [ x[ 'name' ]
- for x in site.rolesOfPermission( ACI )
- if x[ 'selected' ] ]
-
- self.assertEqual( existing_allowed, [ 'Manager' ] )
-
- self.failUnless( site.acquiredRolesAreUsedBy( ACI ) )
- self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
-
- self.failIf( site._has_user_defined_role( 'ZZZ' ) )
-
- context = DummyImportContext( site, False, encoding='ascii' )
- context._files[ 'rolemap.xml' ] = _COMBINED_EXPORT
-
- from Products.CMFSetup.rolemap import importRolemap
- importRolemap( context )
-
- self.failUnless( site._has_user_defined_role( 'ZZZ' ) )
-
- new_allowed = [ x[ 'name' ]
- for x in site.rolesOfPermission( ACI )
- if x[ 'selected' ] ]
-
- self.assertEqual( new_allowed, [ 'Manager', 'Owner', 'ZZZ' ] )
-
- self.failIf( site.acquiredRolesAreUsedBy( ACI ) )
- self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
-
-
-def test_suite():
- return unittest.TestSuite((
- unittest.makeSuite( RolemapConfiguratorTests ),
- unittest.makeSuite( Test_exportRolemap ),
- unittest.makeSuite( Test_importRolemap ),
- ))
-
-if __name__ == '__main__':
- unittest.main(defaultTest='test_suite')
Deleted: CMF/branches/goldegg-phase-1/CMFSetup/tests/test_tool.py
===================================================================
--- CMF/branches/goldegg-phase-1/CMFSetup/tests/test_tool.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/CMFSetup/tests/test_tool.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -1,911 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-""" Unit tests for CMFSetup tool.
-
-$Id$
-"""
-
-import unittest
-import Testing
-import Zope2
-Zope2.startup()
-
-from StringIO import StringIO
-
-from Acquisition import aq_base
-from OFS.Folder import Folder
-
-from Products.CMFSetup import profile_registry
-
-from common import DOMComparator
-from common import DummyExportContext
-from common import DummyImportContext
-from common import FilesystemTestBase
-from common import SecurityRequestTest
-from common import TarballTester
-from conformance import ConformsToISetupTool
-
-
-class SetupToolTests( FilesystemTestBase
- , TarballTester
- , ConformsToISetupTool
- ):
-
- _PROFILE_PATH = '/tmp/STT_test'
-
- def setUp( self ):
-
- FilesystemTestBase.setUp( self )
- self._profile_registry_info = profile_registry._profile_info
- self._profile_registry_ids = profile_registry._profile_ids
- profile_registry.clear()
-
- def tearDown( self ):
-
- profile_registry._profile_info = self._profile_registry_info
- profile_registry._profile_ids = self._profile_registry_ids
- FilesystemTestBase.tearDown( self )
-
- def _getTargetClass( self ):
-
- from Products.CMFSetup.tool import SetupTool
- return SetupTool
-
- def _makeOne( self, *args, **kw ):
-
- return self._getTargetClass()( *args, **kw )
-
- def _makeSite( self, title="Don't care" ):
-
- site = Folder()
- site._setId( 'site' )
- site.title = title
-
- self.root._setObject( 'site', site )
- return self.root._getOb( 'site' )
-
- def test_empty( self ):
-
- tool = self._makeOne()
-
- self.assertEqual( tool.getImportContextID(), '' )
-
- import_registry = tool.getImportStepRegistry()
- self.assertEqual( len( import_registry.listSteps() ), 0 )
-
- export_registry = tool.getExportStepRegistry()
- export_steps = export_registry.listSteps()
- self.assertEqual( len( export_steps ), 1 )
- self.assertEqual( export_steps[ 0 ], 'step_registries' )
-
- toolset_registry = tool.getToolsetRegistry()
- self.assertEqual( len( toolset_registry.listForbiddenTools() ), 0 )
- self.assertEqual( len( toolset_registry.listRequiredTools() ), 0 )
-
- def test_getImportContextID( self ):
-
- from Products.CMFSetup.tool import IMPORT_STEPS_XML
- from Products.CMFSetup.tool import EXPORT_STEPS_XML
- from Products.CMFSetup.tool import TOOLSET_XML
- from test_registry import _EMPTY_IMPORT_XML
- from test_registry import _EMPTY_EXPORT_XML
- from test_registry import _EMPTY_TOOLSET_XML
- from common import _makeTestFile
-
- tool = self._makeOne()
-
- _makeTestFile( IMPORT_STEPS_XML
- , self._PROFILE_PATH
- , _EMPTY_IMPORT_XML
- )
-
- _makeTestFile( EXPORT_STEPS_XML
- , self._PROFILE_PATH
- , _EMPTY_EXPORT_XML
- )
-
- _makeTestFile( TOOLSET_XML
- , self._PROFILE_PATH
- , _EMPTY_TOOLSET_XML
- )
-
- profile_registry.registerProfile('foo', 'Foo', '', self._PROFILE_PATH)
- tool.setImportContext('profile-other:foo')
-
- self.assertEqual( tool.getImportContextID(), 'profile-other:foo' )
-
- def test_setImportContext_invalid( self ):
-
- tool = self._makeOne()
-
- self.assertRaises( KeyError
- , tool.setImportContext
- , 'profile-foo'
- )
-
- def test_setImportContext( self ):
-
- from Products.CMFSetup.tool import IMPORT_STEPS_XML
- from Products.CMFSetup.tool import EXPORT_STEPS_XML
- from Products.CMFSetup.tool import TOOLSET_XML
- from test_registry import _SINGLE_IMPORT_XML
- from test_registry import _SINGLE_EXPORT_XML
- from test_registry import _NORMAL_TOOLSET_XML
- from test_registry import ONE_FUNC
- from common import _makeTestFile
-
- tool = self._makeOne()
- tool.getExportStepRegistry().clear()
-
- _makeTestFile( IMPORT_STEPS_XML
- , self._PROFILE_PATH
- , _SINGLE_IMPORT_XML
- )
-
- _makeTestFile( EXPORT_STEPS_XML
- , self._PROFILE_PATH
- , _SINGLE_EXPORT_XML
- )
-
- _makeTestFile( TOOLSET_XML
- , self._PROFILE_PATH
- , _NORMAL_TOOLSET_XML
- )
-
- profile_registry.registerProfile('foo', 'Foo', '', self._PROFILE_PATH)
- tool.setImportContext('profile-other:foo')
-
- self.assertEqual( tool.getImportContextID(), 'profile-other:foo' )
-
- import_registry = tool.getImportStepRegistry()
- self.assertEqual( len( import_registry.listSteps() ), 1 )
- self.failUnless( 'one' in import_registry.listSteps() )
- info = import_registry.getStepMetadata( 'one' )
- self.assertEqual( info[ 'id' ], 'one' )
- self.assertEqual( info[ 'title' ], 'One Step' )
- self.assertEqual( info[ 'version' ], '1' )
- self.failUnless( 'One small step' in info[ 'description' ] )
- self.assertEqual( info[ 'handler' ]
- , 'Products.CMFSetup.tests.test_registry.ONE_FUNC' )
-
- self.assertEqual( import_registry.getStep( 'one' ), ONE_FUNC )
-
- export_registry = tool.getExportStepRegistry()
- self.assertEqual( len( export_registry.listSteps() ), 1 )
- self.failUnless( 'one' in import_registry.listSteps() )
- info = export_registry.getStepMetadata( 'one' )
- self.assertEqual( info[ 'id' ], 'one' )
- self.assertEqual( info[ 'title' ], 'One Step' )
- self.failUnless( 'One small step' in info[ 'description' ] )
- self.assertEqual( info[ 'handler' ]
- , 'Products.CMFSetup.tests.test_registry.ONE_FUNC' )
-
- self.assertEqual( export_registry.getStep( 'one' ), ONE_FUNC )
-
- toolset = tool.getToolsetRegistry()
- self.assertEqual( len( toolset.listForbiddenTools() ), 1 )
- self.failUnless( 'doomed' in toolset.listForbiddenTools() )
- self.assertEqual( len( toolset.listRequiredTools() ), 2 )
- self.failUnless( 'mandatory' in toolset.listRequiredTools() )
- info = toolset.getRequiredToolInfo( 'mandatory' )
- self.assertEqual( info[ 'class' ], 'path.to.one' )
- self.failUnless( 'obligatory' in toolset.listRequiredTools() )
- info = toolset.getRequiredToolInfo( 'obligatory' )
- self.assertEqual( info[ 'class' ], 'path.to.another' )
-
- def test_runImportStep_nonesuch( self ):
-
- site = self._makeSite()
-
- tool = self._makeOne().__of__( site )
-
- self.assertRaises( ValueError, tool.runImportStep, 'nonesuch' )
-
- def test_runImportStep_simple( self ):
-
- TITLE = 'original title'
- site = self._makeSite( TITLE )
-
- tool = self._makeOne().__of__( site )
-
- registry = tool.getImportStepRegistry()
- registry.registerStep( 'simple', '1', _uppercaseSiteTitle )
-
- result = tool.runImportStep( 'simple' )
-
- self.assertEqual( len( result[ 'steps' ] ), 1 )
-
- self.assertEqual( result[ 'steps' ][ 0 ], 'simple' )
- self.assertEqual( result[ 'messages' ][ 'simple' ]
- , 'Uppercased title' )
-
- self.assertEqual( site.title, TITLE.upper() )
-
- def test_runImportStep_dependencies( self ):
-
- TITLE = 'original title'
- site = self._makeSite( TITLE )
-
- tool = self._makeOne().__of__( site )
-
- registry = tool.getImportStepRegistry()
- registry.registerStep( 'dependable', '1', _underscoreSiteTitle )
- registry.registerStep( 'dependent', '1'
- , _uppercaseSiteTitle, ( 'dependable', ) )
-
- result = tool.runImportStep( 'dependent' )
-
- self.assertEqual( len( result[ 'steps' ] ), 2 )
-
- self.assertEqual( result[ 'steps' ][ 0 ], 'dependable' )
- self.assertEqual( result[ 'messages' ][ 'dependable' ]
- , 'Underscored title' )
-
- self.assertEqual( result[ 'steps' ][ 1 ], 'dependent' )
- self.assertEqual( result[ 'messages' ][ 'dependent' ]
- , 'Uppercased title' )
- self.assertEqual( site.title, TITLE.replace( ' ', '_' ).upper() )
-
- def test_runImportStep_skip_dependencies( self ):
-
- TITLE = 'original title'
- site = self._makeSite( TITLE )
-
- tool = self._makeOne().__of__( site )
-
- registry = tool.getImportStepRegistry()
- registry.registerStep( 'dependable', '1', _underscoreSiteTitle )
- registry.registerStep( 'dependent', '1'
- , _uppercaseSiteTitle, ( 'dependable', ) )
-
- result = tool.runImportStep( 'dependent', run_dependencies=False )
-
- self.assertEqual( len( result[ 'steps' ] ), 1 )
-
- self.assertEqual( result[ 'steps' ][ 0 ], 'dependent' )
- self.assertEqual( result[ 'messages' ][ 'dependent' ]
- , 'Uppercased title' )
-
- self.assertEqual( site.title, TITLE.upper() )
-
- def test_runImportStep_default_purge( self ):
-
- site = self._makeSite()
-
- tool = self._makeOne().__of__( site )
- registry = tool.getImportStepRegistry()
- registry.registerStep( 'purging', '1', _purgeIfRequired )
-
- result = tool.runImportStep( 'purging' )
-
- self.assertEqual( len( result[ 'steps' ] ), 1 )
- self.assertEqual( result[ 'steps' ][ 0 ], 'purging' )
- self.assertEqual( result[ 'messages' ][ 'purging' ], 'Purged' )
- self.failUnless( site.purged )
-
- def test_runImportStep_explicit_purge( self ):
-
- site = self._makeSite()
-
- tool = self._makeOne().__of__( site )
- registry = tool.getImportStepRegistry()
- registry.registerStep( 'purging', '1', _purgeIfRequired )
-
- result = tool.runImportStep( 'purging', purge_old=True )
-
- self.assertEqual( len( result[ 'steps' ] ), 1 )
- self.assertEqual( result[ 'steps' ][ 0 ], 'purging' )
- self.assertEqual( result[ 'messages' ][ 'purging' ], 'Purged' )
- self.failUnless( site.purged )
-
- def test_runImportStep_skip_purge( self ):
-
- site = self._makeSite()
-
- tool = self._makeOne().__of__( site )
- registry = tool.getImportStepRegistry()
- registry.registerStep( 'purging', '1', _purgeIfRequired )
-
- result = tool.runImportStep( 'purging', purge_old=False )
-
- self.assertEqual( len( result[ 'steps' ] ), 1 )
- self.assertEqual( result[ 'steps' ][ 0 ], 'purging' )
- self.assertEqual( result[ 'messages' ][ 'purging' ], 'Unpurged' )
- self.failIf( site.purged )
-
- def test_runImportStep_consistent_context( self ):
-
- site = self._makeSite()
-
- tool = self._makeOne().__of__( site )
-
- registry = tool.getImportStepRegistry()
- registry.registerStep( 'purging', '1', _purgeIfRequired )
- registry.registerStep( 'dependent', '1'
- , _uppercaseSiteTitle, ( 'purging', ) )
-
- result = tool.runImportStep( 'dependent', purge_old=False )
- self.failIf( site.purged )
-
- def test_runAllImportSteps_empty( self ):
-
- site = self._makeSite()
- tool = self._makeOne().__of__( site )
-
- result = tool.runAllImportSteps()
-
- self.assertEqual( len( result[ 'steps' ] ), 0 )
-
- def test_runAllImportSteps_sorted_default_purge( self ):
-
- TITLE = 'original title'
- site = self._makeSite( TITLE )
- tool = self._makeOne().__of__( site )
-
- registry = tool.getImportStepRegistry()
- registry.registerStep( 'dependable', '1'
- , _underscoreSiteTitle, ( 'purging', ) )
- registry.registerStep( 'dependent', '1'
- , _uppercaseSiteTitle, ( 'dependable', ) )
- registry.registerStep( 'purging', '1'
- , _purgeIfRequired )
-
- result = tool.runAllImportSteps()
-
- self.assertEqual( len( result[ 'steps' ] ), 3 )
-
- self.assertEqual( result[ 'steps' ][ 0 ], 'purging' )
- self.assertEqual( result[ 'messages' ][ 'purging' ]
- , 'Purged' )
-
- self.assertEqual( result[ 'steps' ][ 1 ], 'dependable' )
- self.assertEqual( result[ 'messages' ][ 'dependable' ]
- , 'Underscored title' )
-
- self.assertEqual( result[ 'steps' ][ 2 ], 'dependent' )
- self.assertEqual( result[ 'messages' ][ 'dependent' ]
- , 'Uppercased title' )
-
- self.assertEqual( site.title, TITLE.replace( ' ', '_' ).upper() )
- self.failUnless( site.purged )
-
- def test_runAllImportSteps_sorted_explicit_purge( self ):
-
- site = self._makeSite()
- tool = self._makeOne().__of__( site )
-
- registry = tool.getImportStepRegistry()
- registry.registerStep( 'dependable', '1'
- , _underscoreSiteTitle, ( 'purging', ) )
- registry.registerStep( 'dependent', '1'
- , _uppercaseSiteTitle, ( 'dependable', ) )
- registry.registerStep( 'purging', '1'
- , _purgeIfRequired )
-
- result = tool.runAllImportSteps( purge_old=True )
-
- self.assertEqual( len( result[ 'steps' ] ), 3 )
-
- self.assertEqual( result[ 'steps' ][ 0 ], 'purging' )
- self.assertEqual( result[ 'messages' ][ 'purging' ]
- , 'Purged' )
-
- self.assertEqual( result[ 'steps' ][ 1 ], 'dependable' )
- self.assertEqual( result[ 'steps' ][ 2 ], 'dependent' )
- self.failUnless( site.purged )
-
- def test_runAllImportSteps_sorted_skip_purge( self ):
-
- site = self._makeSite()
- tool = self._makeOne().__of__( site )
-
- registry = tool.getImportStepRegistry()
- registry.registerStep( 'dependable', '1'
- , _underscoreSiteTitle, ( 'purging', ) )
- registry.registerStep( 'dependent', '1'
- , _uppercaseSiteTitle, ( 'dependable', ) )
- registry.registerStep( 'purging', '1'
- , _purgeIfRequired )
-
- result = tool.runAllImportSteps( purge_old=False )
-
- self.assertEqual( len( result[ 'steps' ] ), 3 )
-
- self.assertEqual( result[ 'steps' ][ 0 ], 'purging' )
- self.assertEqual( result[ 'messages' ][ 'purging' ]
- , 'Unpurged' )
-
- self.assertEqual( result[ 'steps' ][ 1 ], 'dependable' )
- self.assertEqual( result[ 'steps' ][ 2 ], 'dependent' )
- self.failIf( site.purged )
-
- def test_runExportStep_nonesuch( self ):
-
- site = self._makeSite()
- tool = self._makeOne().__of__( site )
-
- self.assertRaises( ValueError, tool.runExportStep, 'nonesuch' )
-
- def test_runExportStep_step_registry( self ):
-
- from test_registry import _EMPTY_IMPORT_XML
-
- site = self._makeSite()
- site.portal_setup = self._makeOne()
- tool = site.portal_setup
-
- result = tool.runExportStep( 'step_registries' )
-
- self.assertEqual( len( result[ 'steps' ] ), 1 )
- self.assertEqual( result[ 'steps' ][ 0 ], 'step_registries' )
- self.assertEqual( result[ 'messages' ][ 'step_registries' ]
- , 'Step registries exported'
- )
- fileish = StringIO( result[ 'tarball' ] )
-
- self._verifyTarballContents( fileish, [ 'import_steps.xml'
- , 'export_steps.xml'
- ] )
- self._verifyTarballEntryXML( fileish, 'import_steps.xml'
- , _EMPTY_IMPORT_XML )
- self._verifyTarballEntryXML( fileish, 'export_steps.xml'
- , _DEFAULT_STEP_REGISTRIES_EXPORT_XML )
-
- def test_runAllExportSteps_default( self ):
-
- from test_registry import _EMPTY_IMPORT_XML
-
- site = self._makeSite()
- site.portal_setup = self._makeOne()
- tool = site.portal_setup
-
- result = tool.runAllExportSteps()
-
- self.assertEqual( len( result[ 'steps' ] ), 1 )
- self.assertEqual( result[ 'steps' ][ 0 ], 'step_registries' )
- self.assertEqual( result[ 'messages' ][ 'step_registries' ]
- , 'Step registries exported'
- )
- fileish = StringIO( result[ 'tarball' ] )
-
- self._verifyTarballContents( fileish, [ 'import_steps.xml'
- , 'export_steps.xml'
- ] )
- self._verifyTarballEntryXML( fileish, 'import_steps.xml'
- , _EMPTY_IMPORT_XML )
- self._verifyTarballEntryXML( fileish, 'export_steps.xml'
- , _DEFAULT_STEP_REGISTRIES_EXPORT_XML )
-
- def test_runAllExportSteps_extras( self ):
-
- from test_registry import _EMPTY_IMPORT_XML
-
- site = self._makeSite()
- site.portal_setup = self._makeOne()
- tool = site.portal_setup
-
- import_reg = tool.getImportStepRegistry()
- import_reg.registerStep( 'dependable', '1'
- , _underscoreSiteTitle, ( 'purging', ) )
- import_reg.registerStep( 'dependent', '1'
- , _uppercaseSiteTitle, ( 'dependable', ) )
- import_reg.registerStep( 'purging', '1'
- , _purgeIfRequired )
-
- export_reg = tool.getExportStepRegistry()
- export_reg.registerStep( 'properties'
- , _exportPropertiesINI )
-
- result = tool.runAllExportSteps()
-
- self.assertEqual( len( result[ 'steps' ] ), 2 )
-
- self.failUnless( 'properties' in result[ 'steps' ] )
- self.assertEqual( result[ 'messages' ][ 'properties' ]
- , 'Exported properties'
- )
-
- self.failUnless( 'step_registries' in result[ 'steps' ] )
- self.assertEqual( result[ 'messages' ][ 'step_registries' ]
- , 'Step registries exported'
- )
-
- fileish = StringIO( result[ 'tarball' ] )
-
- self._verifyTarballContents( fileish, [ 'import_steps.xml'
- , 'export_steps.xml'
- , 'properties.ini'
- ] )
- self._verifyTarballEntryXML( fileish, 'import_steps.xml'
- , _EXTRAS_STEP_REGISTRIES_IMPORT_XML )
- self._verifyTarballEntryXML( fileish, 'export_steps.xml'
- , _EXTRAS_STEP_REGISTRIES_EXPORT_XML )
- self._verifyTarballEntry( fileish, 'properties.ini'
- , _PROPERTIES_INI % site.title )
-
- def test_createSnapshot_default( self ):
-
- from test_registry import _EMPTY_IMPORT_XML
-
- _EXPECTED = [ ( 'import_steps.xml', _EMPTY_IMPORT_XML )
- , ( 'export_steps.xml'
- , _DEFAULT_STEP_REGISTRIES_EXPORT_XML
- )
- ]
-
- site = self._makeSite()
- site.portal_setup = self._makeOne()
- tool = site.portal_setup
-
- self.assertEqual( len( tool.listSnapshotInfo() ), 0 )
-
- result = tool.createSnapshot( 'default' )
-
- self.assertEqual( len( result[ 'steps' ] ), 1 )
- self.assertEqual( result[ 'steps' ][ 0 ], 'step_registries' )
- self.assertEqual( result[ 'messages' ][ 'step_registries' ]
- , 'Step registries exported'
- )
-
- snapshot = result[ 'snapshot' ]
-
- self.assertEqual( len( snapshot.objectIds() ), len( _EXPECTED ) )
-
- for id in [ x[0] for x in _EXPECTED ]:
- self.failUnless( id in snapshot.objectIds() )
-
- def normalize_xml(xml):
- # using this might mask a real problem on windows, but so far the
- # different newlines just caused problems in this test
- lines = [ line for line in xml.splitlines() if line ]
- return '\n'.join(lines) + '\n'
-
- fileobj = snapshot._getOb( 'import_steps.xml' )
- self.assertEqual( normalize_xml( fileobj.read() ),
- _EMPTY_IMPORT_XML )
-
- fileobj = snapshot._getOb( 'export_steps.xml' )
-
- self.assertEqual( normalize_xml( fileobj.read() ),
- _DEFAULT_STEP_REGISTRIES_EXPORT_XML )
-
- self.assertEqual( len( tool.listSnapshotInfo() ), 1 )
-
- info = tool.listSnapshotInfo()[ 0 ]
-
- self.assertEqual( info[ 'id' ], 'default' )
- self.assertEqual( info[ 'title' ], 'default' )
-
-
-_DEFAULT_STEP_REGISTRIES_EXPORT_XML = """\
-<?xml version="1.0"?>
-<export-steps>
- <export-step id="step_registries"
- handler="Products.CMFSetup.tool.exportStepRegistries"
- title="Export import / export steps.">
-
- </export-step>
-</export-steps>
-"""
-
-_EXTRAS_STEP_REGISTRIES_EXPORT_XML = """\
-<?xml version="1.0"?>
-<export-steps>
- <export-step id="properties"
- handler="Products.CMFSetup.tests.test_tool._exportPropertiesINI"
- title="properties">
-
- </export-step>
- <export-step id="step_registries"
- handler="Products.CMFSetup.tool.exportStepRegistries"
- title="Export import / export steps.">
-
- </export-step>
-</export-steps>
-"""
-
-_EXTRAS_STEP_REGISTRIES_IMPORT_XML = """\
-<?xml version="1.0"?>
-<import-steps>
- <import-step id="dependable"
- version="1"
- handler="Products.CMFSetup.tests.test_tool._underscoreSiteTitle"
- title="dependable">
- <dependency step="purging" />
-
- </import-step>
- <import-step id="dependent"
- version="1"
- handler="Products.CMFSetup.tests.test_tool._uppercaseSiteTitle"
- title="dependent">
- <dependency step="dependable" />
-
- </import-step>
- <import-step id="purging"
- version="1"
- handler="Products.CMFSetup.tests.test_tool._purgeIfRequired"
- title="purging">
-
- </import-step>
-</import-steps>
-"""
-
-_PROPERTIES_INI = """\
-[Default]
-Title=%s
-"""
-
-def _underscoreSiteTitle( context ):
-
- site = context.getSite()
- site.title = site.title.replace( ' ', '_' )
- return 'Underscored title'
-
-def _uppercaseSiteTitle( context ):
-
- site = context.getSite()
- site.title = site.title.upper()
- return 'Uppercased title'
-
-def _purgeIfRequired( context ):
-
- site = context.getSite()
- purged = site.purged = context.shouldPurge()
- return purged and 'Purged' or 'Unpurged'
-
-def _exportPropertiesINI( context ):
-
- site = context.getSite()
- text = _PROPERTIES_INI % site.title
-
- context.writeDataFile( 'properties.ini', text, 'text/plain' )
-
- return 'Exported properties'
-
-class _ToolsetSetup( SecurityRequestTest ):
-
- def _initSite( self ):
-
- from Products.CMFSetup.tool import SetupTool
- site = Folder()
- site._setId( 'site' )
- self.root._setObject( 'site', site )
- site = self.root._getOb( 'site' )
- site._setObject( 'portal_setup', SetupTool() )
- return site
-
-class Test_exportToolset( _ToolsetSetup
- , DOMComparator
- ):
-
- def test_empty( self ):
-
- from Products.CMFSetup.tool import TOOLSET_XML
- from Products.CMFSetup.tool import exportToolset
-
- site = self._initSite()
- context = DummyExportContext( site )
-
- exportToolset( context )
-
- self.assertEqual( len( context._wrote ), 1 )
- filename, text, content_type = context._wrote[ 0 ]
- self.assertEqual( filename, TOOLSET_XML )
- self._compareDOM( text, _EMPTY_TOOLSET_XML )
- self.assertEqual( content_type, 'text/xml' )
-
- def test_normal( self ):
-
- from Products.CMFSetup.tool import TOOLSET_XML
- from Products.CMFSetup.tool import exportToolset
-
- site = self._initSite()
- toolset = site.portal_setup.getToolsetRegistry()
- toolset.addForbiddenTool( 'doomed' )
- toolset.addRequiredTool( 'mandatory', 'path.to.one' )
- toolset.addRequiredTool( 'obligatory', 'path.to.another' )
-
- context = DummyExportContext( site )
-
- exportToolset( context )
-
- self.assertEqual( len( context._wrote ), 1 )
- filename, text, content_type = context._wrote[ 0 ]
- self.assertEqual( filename, TOOLSET_XML )
- self._compareDOM( text, _NORMAL_TOOLSET_XML )
- self.assertEqual( content_type, 'text/xml' )
-
-class Test_importToolset( _ToolsetSetup ):
-
- def test_tool_ids( self ):
- # The tool import mechanism used to rely on the fact that all tools
- # have unique IDs set at the class level and that you can call their
- # constructor with no arguments. However, there might be tools
- # that need IDs set.
- from Products.CMFSetup.tool import TOOLSET_XML
- from Products.CMFSetup.tool import importToolset
-
- site = self._initSite()
- context = DummyImportContext( site )
- context._files[ TOOLSET_XML ] = _REQUIRED_TOOLSET_XML
-
- importToolset( context )
-
- for tool_id in ( 'mandatory', 'obligatory' ):
- tool = getattr( site, tool_id )
- self.assertEqual( tool.getId(), tool_id )
-
- def test_forbidden_tools( self ):
-
- from Products.CMFSetup.tool import TOOLSET_XML
- from Products.CMFSetup.tool import importToolset
- TOOL_IDS = ( 'doomed', 'blasted', 'saved' )
-
- site = self._initSite()
-
- for tool_id in TOOL_IDS:
- pseudo = Folder()
- pseudo._setId( tool_id )
- site._setObject( tool_id, pseudo )
-
- self.assertEqual( len( site.objectIds() ), len( TOOL_IDS ) + 1 )
-
- for tool_id in TOOL_IDS:
- self.failUnless( tool_id in site.objectIds() )
-
- context = DummyImportContext( site )
- context._files[ TOOLSET_XML ] = _FORBIDDEN_TOOLSET_XML
-
- importToolset( context )
-
- self.assertEqual( len( site.objectIds() ), 2 )
- self.failUnless( 'portal_setup' in site.objectIds() )
- self.failUnless( 'saved' in site.objectIds() )
-
- def test_required_tools_missing( self ):
-
- from Products.CMFSetup.tool import TOOLSET_XML
- from Products.CMFSetup.tool import importToolset
-
- site = self._initSite()
- self.assertEqual( len( site.objectIds() ), 1 )
-
- context = DummyImportContext( site )
- context._files[ TOOLSET_XML ] = _REQUIRED_TOOLSET_XML
-
- importToolset( context )
-
- self.assertEqual( len( site.objectIds() ), 3 )
- self.failUnless( isinstance( aq_base( site._getOb( 'mandatory' ) )
- , DummyTool ) )
- self.failUnless( isinstance( aq_base( site._getOb( 'obligatory' ) )
- , DummyTool ) )
-
- def test_required_tools_no_replacement( self ):
-
- from Products.CMFSetup.tool import TOOLSET_XML
- from Products.CMFSetup.tool import importToolset
-
- site = self._initSite()
-
- mandatory = DummyTool()
- mandatory._setId( 'mandatory' )
- site._setObject( 'mandatory', mandatory )
-
- obligatory = DummyTool()
- obligatory._setId( 'obligatory' )
- site._setObject( 'obligatory', obligatory )
-
- self.assertEqual( len( site.objectIds() ), 3 )
-
- context = DummyImportContext( site )
- context._files[ TOOLSET_XML ] = _REQUIRED_TOOLSET_XML
-
- importToolset( context )
-
- self.assertEqual( len( site.objectIds() ), 3 )
- self.failUnless( aq_base( site._getOb( 'mandatory' ) ) is mandatory )
- self.failUnless( aq_base( site._getOb( 'obligatory' ) ) is obligatory )
-
- def test_required_tools_with_replacement( self ):
-
- from Products.CMFSetup.tool import TOOLSET_XML
- from Products.CMFSetup.tool import importToolset
-
- site = self._initSite()
-
- mandatory = AnotherDummyTool()
- mandatory._setId( 'mandatory' )
- site._setObject( 'mandatory', mandatory )
-
- obligatory = AnotherDummyTool()
- obligatory._setId( 'obligatory' )
- site._setObject( 'obligatory', obligatory )
-
- self.assertEqual( len( site.objectIds() ), 3 )
-
- context = DummyImportContext( site )
- context._files[ TOOLSET_XML ] = _REQUIRED_TOOLSET_XML
-
- importToolset( context )
-
- self.assertEqual( len( site.objectIds() ), 3 )
-
- self.failIf( aq_base( site._getOb( 'mandatory' ) ) is mandatory )
- self.failUnless( isinstance( aq_base( site._getOb( 'mandatory' ) )
- , DummyTool ) )
-
- self.failIf( aq_base( site._getOb( 'obligatory' ) ) is obligatory )
- self.failUnless( isinstance( aq_base( site._getOb( 'obligatory' ) )
- , DummyTool ) )
-
-
-class DummyTool( Folder ):
-
- pass
-
-class AnotherDummyTool( Folder ):
-
- pass
-
-
-_EMPTY_TOOLSET_XML = """\
-<?xml version="1.0"?>
-<tool-setup>
-</tool-setup>
-"""
-
-_NORMAL_TOOLSET_XML = """\
-<?xml version="1.0" ?>
-<tool-setup>
-<forbidden tool_id="doomed"/>
-<required class="path.to.one" tool_id="mandatory"/>
-<required class="path.to.another" tool_id="obligatory"/>
-</tool-setup>
-"""
-
-_FORBIDDEN_TOOLSET_XML = """\
-<?xml version="1.0"?>
-<tool-setup>
- <forbidden tool_id="doomed" />
- <forbidden tool_id="damned" />
- <forbidden tool_id="blasted" />
-</tool-setup>
-"""
-
-_REQUIRED_TOOLSET_XML = """\
-<?xml version="1.0"?>
-<tool-setup>
- <required
- tool_id="mandatory"
- class="Products.CMFSetup.tests.test_tool.DummyTool" />
- <required
- tool_id="obligatory"
- class="Products.CMFSetup.tests.test_tool.DummyTool" />
-</tool-setup>
-"""
-
-def test_suite():
- # reimport to make sure tests are run from Products
- from Products.CMFSetup.tests.test_tool import SetupToolTests
- from Products.CMFSetup.tests.test_tool import Test_exportToolset
- from Products.CMFSetup.tests.test_tool import Test_importToolset
-
- return unittest.TestSuite((
- unittest.makeSuite( SetupToolTests ),
- unittest.makeSuite( Test_exportToolset ),
- unittest.makeSuite( Test_importToolset ),
- ))
-
-if __name__ == '__main__':
- unittest.main(defaultTest='test_suite')
Modified: CMF/branches/goldegg-phase-1/CMFSetup/tool.py
===================================================================
--- CMF/branches/goldegg-phase-1/CMFSetup/tool.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/CMFSetup/tool.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -15,715 +15,7 @@
$Id$
"""
-import os
-import time
-from cgi import escape
-
-from AccessControl import ClassSecurityInfo
-from Acquisition import aq_base
-from Globals import InitializeClass
-from OFS.Folder import Folder
-from Products.PageTemplates.PageTemplateFile import PageTemplateFile
-
-from Products.CMFCore.utils import UniqueObject
-from Products.CMFCore.utils import ImmutableId
-from Products.CMFCore.utils import getToolByName
-
-from interfaces import EXTENSION
-from interfaces import ISetupTool
-from permissions import ManagePortal
-from context import DirectoryImportContext
-from context import SnapshotImportContext
-from context import TarballExportContext
-from context import SnapshotExportContext
-from differ import ConfigDiff
-from registry import ImportStepRegistry
-from registry import ExportStepRegistry
-from registry import ToolsetRegistry
-from registry import _profile_registry
-
-from utils import _resolveDottedName
-from utils import _wwwdir
-
-IMPORT_STEPS_XML = 'import_steps.xml'
-EXPORT_STEPS_XML = 'export_steps.xml'
-TOOLSET_XML = 'toolset.xml'
-
-def exportStepRegistries( context ):
-
- """ Built-in handler for exporting import / export step registries.
- """
- site = context.getSite()
- tool = getToolByName( site, 'portal_setup' )
-
- import_steps_xml = tool.getImportStepRegistry().generateXML()
- context.writeDataFile( 'import_steps.xml', import_steps_xml, 'text/xml' )
-
- export_steps_xml = tool.getExportStepRegistry().generateXML()
- context.writeDataFile( 'export_steps.xml', export_steps_xml, 'text/xml' )
-
- return 'Step registries exported'
-
-def importToolset( context ):
-
- """ Import required / forbidden tools from XML file.
- """
- site = context.getSite()
- encoding = context.getEncoding()
-
- xml = context.readDataFile(TOOLSET_XML)
- if xml is None:
- return 'Toolset: Nothing to import.'
-
- setup_tool = getToolByName( site, 'portal_setup' )
- toolset = setup_tool.getToolsetRegistry()
-
- toolset.parseXML(xml, encoding)
-
- existing_ids = site.objectIds()
- existing_values = site.objectValues()
-
- for tool_id in toolset.listForbiddenTools():
-
- if tool_id in existing_ids:
- site._delObject( tool_id )
-
- for info in toolset.listRequiredToolInfo():
-
- tool_id = str( info[ 'id' ] )
- tool_class = _resolveDottedName( info[ 'class' ] )
-
- existing = getToolByName( site, tool_id, None )
- new_tool = tool_class()
-
- if not isinstance( new_tool, ImmutableId ):
- new_tool._setId( tool_id )
-
- if existing is None:
- site._setObject( tool_id, new_tool )
-
- else:
- unwrapped = aq_base( existing )
- if not isinstance( unwrapped, tool_class ):
- site._delObject( tool_id )
- site._setObject( tool_id, new_tool )
-
- return 'Toolset imported.'
-
-def exportToolset( context ):
-
- """ Export required / forbidden tools to XML file.
- """
- site = context.getSite()
- setup_tool = getToolByName( site, 'portal_setup' )
- toolset = setup_tool.getToolsetRegistry()
-
- xml = toolset.generateXML()
- context.writeDataFile( TOOLSET_XML, xml, 'text/xml' )
-
- return 'Toolset exported.'
-
-
-class SetupTool( UniqueObject, Folder ):
-
- """ Profile-based site configuration manager.
- """
- __implements__ = ( ISetupTool, ) + Folder.__implements__
-
- id = 'portal_setup'
- meta_type = 'Portal Setup Tool'
-
- _import_context_id = ''
-
- security = ClassSecurityInfo()
-
- def __init__( self ):
-
- self._import_registry = ImportStepRegistry()
- self._export_registry = ExportStepRegistry()
- self._export_registry.registerStep( 'step_registries'
- , exportStepRegistries
- , 'Export import / export steps.'
- )
- self._toolset_registry = ToolsetRegistry()
-
- #
- # ISetupTool API
- #
- security.declareProtected( ManagePortal, 'getEncoding' )
- def getEncoding( self ):
-
- """ See ISetupTool.
- """
- return 'ascii'
-
- security.declareProtected( ManagePortal, 'getImportContextId' )
- def getImportContextID( self ):
-
- """ See ISetupTool.
- """
- return self._import_context_id
-
- security.declareProtected(ManagePortal, 'setImportContext')
- def setImportContext(self, context_id, encoding=None):
-
- """ See ISetupTool.
- """
- self._import_context_id = context_id
-
- self._updateImportStepsRegistry( encoding )
- self._updateExportStepsRegistry( encoding )
- self._updateToolsetRegistry( encoding )
-
- security.declareProtected( ManagePortal, 'getImportStepRegistry' )
- def getImportStepRegistry( self ):
-
- """ See ISetupTool.
- """
- return self._import_registry
-
- security.declareProtected( ManagePortal, 'getImportStepRegistry' )
- def getExportStepRegistry( self ):
-
- """ See ISetupTool.
- """
- return self._export_registry
-
- security.declareProtected( ManagePortal, 'getToolsetRegistry' )
- def getToolsetRegistry( self ):
-
- """ See ISetupTool.
- """
- return self._toolset_registry
-
- security.declareProtected( ManagePortal, 'executeStep' )
- def runImportStep( self, step_id, run_dependencies=True, purge_old=None ):
-
- """ See ISetupTool.
- """
- context = self._getImportContext(self._import_context_id, purge_old)
-
- info = self._import_registry.getStepMetadata( step_id )
-
- if info is None:
- raise ValueError, 'No such import step: %s' % step_id
-
- dependencies = info.get( 'dependencies', () )
-
- messages = {}
- steps = []
- if run_dependencies:
- for dependency in dependencies:
-
- if dependency not in steps:
- message = self._doRunImportStep( dependency, context )
- messages[ dependency ] = message
- steps.append( dependency )
-
- message = self._doRunImportStep( step_id, context )
- messages[ step_id ] = message
- steps.append( step_id )
-
- return { 'steps' : steps, 'messages' : messages }
-
- security.declareProtected( ManagePortal, 'runAllSetupSteps')
- def runAllImportSteps( self, purge_old=None ):
-
- """ See ISetupTool.
- """
- context = self._getImportContext(self._import_context_id, purge_old)
-
- steps = self._import_registry.sortSteps()
- messages = {}
-
- for step in steps:
- message = self._doRunImportStep( step, context )
- messages[ step ] = message
-
- return { 'steps' : steps, 'messages' : messages }
-
- security.declareProtected( ManagePortal, 'runExportStep')
- def runExportStep( self, step_id ):
-
- """ See ISetupTool.
- """
- return self._doRunExportSteps( [ step_id ] )
-
- security.declareProtected(ManagePortal, 'runAllExportSteps')
- def runAllExportSteps( self ):
-
- """ See ISetupTool.
- """
- return self._doRunExportSteps( self._export_registry.listSteps() )
-
- security.declareProtected( ManagePortal, 'createSnapshot')
- def createSnapshot( self, snapshot_id ):
-
- """ See ISetupTool.
- """
- context = SnapshotExportContext( self, snapshot_id )
- messages = {}
- steps = self._export_registry.listSteps()
-
- for step_id in steps:
-
- handler = self._export_registry.getStep( step_id )
-
- if handler is None:
- raise ValueError( 'Invalid export step: %s' % step_id )
-
- messages[ step_id ] = handler( context )
-
-
- return { 'steps' : steps
- , 'messages' : messages
- , 'url' : context.getSnapshotURL()
- , 'snapshot' : context.getSnapshotFolder()
- }
-
- security.declareProtected(ManagePortal, 'compareConfigurations')
- def compareConfigurations( self
- , lhs_context
- , rhs_context
- , missing_as_empty=False
- , ignore_blanks=False
- , skip=( 'CVS', '.svn' )
- ):
- """ See ISetupTool.
- """
- differ = ConfigDiff( lhs_context
- , rhs_context
- , missing_as_empty
- , ignore_blanks
- , skip
- )
-
- return differ.compare()
-
- security.declareProtected( ManagePortal, 'markupComparison')
- def markupComparison(self, lines):
-
- """ See ISetupTool.
- """
- result = []
-
- for line in lines.splitlines():
-
- if line.startswith('** '):
-
- if line.find('File') > -1:
- if line.find('replaced') > -1:
- result.append( ( 'file-to-dir', line ) )
- elif line.find('added') > -1:
- result.append( ( 'file-added', line ) )
- else:
- result.append( ( 'file-removed', line ) )
- else:
- if line.find('replaced') > -1:
- result.append( ( 'dir-to-file', line ) )
- elif line.find('added') > -1:
- result.append( ( 'dir-added', line ) )
- else:
- result.append( ( 'dir-removed', line ) )
-
- elif line.startswith('@@'):
- result.append( ( 'diff-range', line ) )
-
- elif line.startswith(' '):
- result.append( ( 'diff-context', line ) )
-
- elif line.startswith('+'):
- result.append( ( 'diff-added', line ) )
-
- elif line.startswith('-'):
- result.append( ( 'diff-removed', line ) )
-
- elif line == '\ No newline at end of file':
- result.append( ( 'diff-context', line ) )
-
- else:
- result.append( ( 'diff-header', line ) )
-
- return '<pre>\n%s\n</pre>' % (
- '\n'.join( [ ( '<span class="%s">%s</span>' % ( cl, escape( l ) ) )
- for cl, l in result] ) )
-
- #
- # ZMI
- #
- manage_options = ( Folder.manage_options[ :1 ]
- + ( { 'label' : 'Properties'
- , 'action' : 'manage_tool'
- }
- , { 'label' : 'Import'
- , 'action' : 'manage_importSteps'
- }
- , { 'label' : 'Export'
- , 'action' : 'manage_exportSteps'
- }
- , { 'label' : 'Snapshots'
- , 'action' : 'manage_snapshots'
- }
- , { 'label' : 'Comparison'
- , 'action' : 'manage_showDiff'
- }
- )
- + Folder.manage_options[ 3: ] # skip "View", "Properties"
- )
-
- security.declareProtected( ManagePortal, 'manage_tool' )
- manage_tool = PageTemplateFile( 'sutProperties', _wwwdir )
-
- security.declareProtected( ManagePortal, 'manage_updateToolProperties' )
- def manage_updateToolProperties(self, context_id, RESPONSE):
- """ Update the tool's settings.
- """
- self.setImportContext(context_id)
-
- RESPONSE.redirect( '%s/manage_tool?manage_tabs_message=%s'
- % ( self.absolute_url(), 'Properties+updated.' )
- )
-
- security.declareProtected( ManagePortal, 'manage_importSteps' )
- manage_importSteps = PageTemplateFile( 'sutImportSteps', _wwwdir )
-
- security.declareProtected( ManagePortal, 'manage_importSelectedSteps' )
- def manage_importSelectedSteps( self
- , ids
- , run_dependencies
- , RESPONSE
- ):
- """ Import the steps selected by the user.
- """
- if not ids:
- message = 'No+steps+selected.'
-
- else:
- steps_run = []
- for step_id in ids:
- result = self.runImportStep( step_id, run_dependencies )
- steps_run.extend( result[ 'steps' ] )
-
- message = 'Steps+run:%s' % '+,'.join( steps_run )
-
- RESPONSE.redirect( '%s/manage_importSteps?manage_tabs_message=%s'
- % ( self.absolute_url(), message )
- )
-
- security.declareProtected( ManagePortal, 'manage_importSelectedSteps' )
- def manage_importAllSteps( self, RESPONSE ):
-
- """ Import all steps.
- """
- result = self.runAllImportSteps()
- message = 'Steps+run:%s' % '+,'.join( result[ 'steps' ] )
-
- RESPONSE.redirect( '%s/manage_importSteps?manage_tabs_message=%s'
- % ( self.absolute_url(), message )
- )
-
- security.declareProtected( ManagePortal, 'manage_exportSteps' )
- manage_exportSteps = PageTemplateFile( 'sutExportSteps', _wwwdir )
-
- security.declareProtected( ManagePortal, 'manage_exportSelectedSteps' )
- def manage_exportSelectedSteps( self, ids, RESPONSE ):
-
- """ Export the steps selected by the user.
- """
- if not ids:
- RESPONSE.redirect( '%s/manage_exportSteps?manage_tabs_message=%s'
- % ( self.absolute_url(), 'No+steps+selected.' )
- )
-
- result = self._doRunExportSteps( ids )
- RESPONSE.setHeader( 'Content-type', 'application/x-gzip')
- RESPONSE.setHeader( 'Content-disposition'
- , 'attachment; filename=%s' % result[ 'filename' ]
- )
- return result[ 'tarball' ]
-
- security.declareProtected( ManagePortal, 'manage_exportAllSteps' )
- def manage_exportAllSteps( self, RESPONSE ):
-
- """ Export all steps.
- """
- result = self.runAllExportSteps()
- RESPONSE.setHeader( 'Content-type', 'application/x-gzip')
- RESPONSE.setHeader( 'Content-disposition'
- , 'attachment; filename=%s' % result[ 'filename' ]
- )
- return result[ 'tarball' ]
-
- security.declareProtected( ManagePortal, 'manage_snapshots' )
- manage_snapshots = PageTemplateFile( 'sutSnapshots', _wwwdir )
-
- security.declareProtected( ManagePortal, 'listSnapshotInfo' )
- def listSnapshotInfo( self ):
-
- """ Return a list of mappings describing available snapshots.
-
- o Keys include:
-
- 'id' -- snapshot ID
-
- 'title' -- snapshot title or ID
-
- 'url' -- URL of the snapshot folder
- """
- result = []
- snapshots = self._getOb( 'snapshots', None )
-
- if snapshots:
-
- for id, folder in snapshots.objectItems( 'Folder' ):
-
- result.append( { 'id' : id
- , 'title' : folder.title_or_id()
- , 'url' : folder.absolute_url()
- } )
- return result
-
- security.declareProtected( ManagePortal, 'listProfileInfo' )
- def listProfileInfo( self ):
-
- """ Return a list of mappings describing registered profiles.
-
- o Keys include:
-
- 'id' -- profile ID
-
- 'title' -- profile title or ID
-
- 'description' -- description of the profile
-
- 'path' -- path to the profile within its product
-
- 'product' -- name of the registering product
- """
- return _profile_registry.listProfileInfo()
-
- security.declareProtected(ManagePortal, 'listContextInfos')
- def listContextInfos(self):
-
- """ List registered profiles and snapshots.
- """
-
- s_infos = [ { 'id': 'snapshot-%s' % info['id'],
- 'title': info['title'] }
- for info in self.listSnapshotInfo() ]
- p_infos = [ { 'id': 'profile-%s' % info['id'],
- 'title': info['title'] }
- for info in self.listProfileInfo() ]
-
- return tuple(s_infos + p_infos)
-
- security.declareProtected( ManagePortal, 'manage_createSnapshot' )
- def manage_createSnapshot( self, RESPONSE, snapshot_id=None ):
-
- """ Create a snapshot with the given ID.
-
- o If no ID is passed, generate one.
- """
- if snapshot_id is None:
- timestamp = time.gmtime()
- snapshot_id = 'snapshot-%4d%02d%02d%02d%02d%02d' % timestamp[:6]
-
- self.createSnapshot( snapshot_id )
-
- RESPONSE.redirect( '%s/manage_snapshots?manage_tabs_message=%s'
- % ( self.absolute_url(), 'Snapshot+created.' ) )
-
- security.declareProtected( ManagePortal, 'manage_showDiff' )
- manage_showDiff = PageTemplateFile( 'sutCompare', _wwwdir )
-
- def manage_downloadDiff( self
- , lhs
- , rhs
- , missing_as_empty
- , ignore_blanks
- , RESPONSE
- ):
- """ Crack request vars and call compareConfigurations.
-
- o Return the result as a 'text/plain' stream, suitable for framing.
- """
- comparison = self.manage_compareConfigurations( lhs
- , rhs
- , missing_as_empty
- , ignore_blanks
- )
- RESPONSE.setHeader( 'Content-Type', 'text/plain' )
- return _PLAINTEXT_DIFF_HEADER % ( lhs, rhs, comparison )
-
- security.declareProtected( ManagePortal, 'manage_compareConfigurations' )
- def manage_compareConfigurations( self
- , lhs
- , rhs
- , missing_as_empty
- , ignore_blanks
- ):
- """ Crack request vars and call compareConfigurations.
- """
- lhs_context = self._getImportContext( lhs )
- rhs_context = self._getImportContext( rhs )
-
- return self.compareConfigurations( lhs_context
- , rhs_context
- , missing_as_empty
- , ignore_blanks
- )
-
-
- #
- # Helper methods
- #
- security.declarePrivate( '_getProductPath' )
- def _getProductPath( self, product_name ):
-
- """ Return the absolute path of the product's directory.
- """
- try:
- product = __import__( 'Products.%s' % product_name
- , globals(), {}, ['initialize' ] )
- except ImportError:
- raise ValueError, 'Not a valid product name: %s' % product_name
-
- return product.__path__[0]
-
- security.declarePrivate( '_getImportContext' )
- def _getImportContext( self, context_id, should_purge=None ):
-
- """ Crack ID and generate appropriate import context.
- """
- encoding = self.getEncoding()
-
- if context_id.startswith( 'profile-' ):
-
- context_id = context_id[ len( 'profile-' ): ]
- info = _profile_registry.getProfileInfo( context_id )
-
- if info.get( 'product' ):
- path = os.path.join( self._getProductPath( info[ 'product' ] )
- , info[ 'path' ] )
- else:
- path = info[ 'path' ]
- if should_purge is None:
- should_purge = (info.get('type') != EXTENSION)
- return DirectoryImportContext(self, path, should_purge, encoding)
-
- # else snapshot
- context_id = context_id[ len( 'snapshot-' ): ]
- if should_purge is None:
- should_purge = True
- return SnapshotImportContext(self, context_id, should_purge, encoding)
-
- security.declarePrivate( '_updateImportStepsRegistry' )
- def _updateImportStepsRegistry( self, encoding ):
-
- """ Update our import steps registry from our profile.
- """
- context = self._getImportContext(self._import_context_id)
- xml = context.readDataFile(IMPORT_STEPS_XML)
- if xml is None:
- return
-
- info_list = self._import_registry.parseXML( xml, encoding )
-
- for step_info in info_list:
-
- id = step_info[ 'id' ]
- version = step_info[ 'version' ]
- handler = _resolveDottedName( step_info[ 'handler' ] )
-
- dependencies = tuple( step_info.get( 'dependencies', () ) )
- title = step_info.get( 'title', id )
- description = ''.join( step_info.get( 'description', [] ) )
-
- self._import_registry.registerStep( id=id
- , version=version
- , handler=handler
- , dependencies=dependencies
- , title=title
- , description=description
- )
-
- security.declarePrivate( '_updateExportStepsRegistry' )
- def _updateExportStepsRegistry( self, encoding ):
-
- """ Update our export steps registry from our profile.
- """
- context = self._getImportContext(self._import_context_id)
- xml = context.readDataFile(EXPORT_STEPS_XML)
- if xml is None:
- return
-
- info_list = self._export_registry.parseXML( xml, encoding )
-
- for step_info in info_list:
-
- id = step_info[ 'id' ]
- handler = _resolveDottedName( step_info[ 'handler' ] )
-
- title = step_info.get( 'title', id )
- description = ''.join( step_info.get( 'description', [] ) )
-
- self._export_registry.registerStep( id=id
- , handler=handler
- , title=title
- , description=description
- )
-
- security.declarePrivate( '_updateToolsetRegistry' )
- def _updateToolsetRegistry( self, encoding ):
-
- """ Update our toolset registry from our profile.
- """
- context = self._getImportContext(self._import_context_id)
- xml = context.readDataFile(TOOLSET_XML)
- if xml is None:
- return
-
- self._toolset_registry.parseXML( xml, encoding )
-
- security.declarePrivate( '_doRunImportStep' )
- def _doRunImportStep( self, step_id, context ):
-
- """ Run a single import step, using a pre-built context.
- """
- handler = self._import_registry.getStep( step_id )
-
- if handler is None:
- raise ValueError( 'Invalid import step: %s' % step_id )
-
- return handler( context )
-
- security.declarePrivate( '_doRunExportSteps')
- def _doRunExportSteps( self, steps ):
-
- """ See ISetupTool.
- """
- context = TarballExportContext( self )
- messages = {}
-
- for step_id in steps:
-
- handler = self._export_registry.getStep( step_id )
-
- if handler is None:
- raise ValueError( 'Invalid export step: %s' % step_id )
-
- messages[ step_id ] = handler( context )
-
-
- return { 'steps' : steps
- , 'messages' : messages
- , 'tarball' : context.getArchive()
- , 'filename' : context.getArchiveFilename()
- }
-
-InitializeClass( SetupTool )
-
-_PLAINTEXT_DIFF_HEADER ="""\
-Comparing configurations: '%s' and '%s'
-
-%s"""
+from Products.GenericSetup.tool import exportStepRegistries
+from Products.GenericSetup.tool import importToolset
+from Products.GenericSetup.tool import exportToolset
+from Products.GenericSetup.tool import SetupTool
Added: CMF/branches/goldegg-phase-1/GenericSetup/CHANGES.txt
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/CHANGES.txt 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/CHANGES.txt 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,24 @@
+GenericSetup Product Changelog
+
+ GenericSetup 1.0 (2005/09/23)
+
+ - CVS tag: GenericSetup-1_0
+
+ - Forward-ported i18n support from CMF 1.5 branch.
+
+ - Forward ported BBB for old instances that stored properties as
+ lists from CMFSetup.
+
+ - Forward ported fix for tools with non unique IDs from CMFSetup.
+
+ GenericSetup 0.10 (2005/08/11)
+
+ - CVS tag: GenericSetup-0_10
+
+ - Added TarballImportContext, including full test suite.
+
+ GenericSetup 0.9 (2005/08/08)
+
+ - CVS tag: GenericSetup-0_9
+
+ - Initial version, cut down from CMFSetup-1.5.3
Added: CMF/branches/goldegg-phase-1/GenericSetup/CREDITS.txt
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/CREDITS.txt 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/CREDITS.txt 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,7 @@
+GenericSetup Credits
+
+ - Martijn Pieters <mj at zopatista.com> wrote the original version of this
+ software while working at Zope Corporation.
+
+ - He developed his version as part of the "Bonzai" CMS which Zope corp.
+ built Boston.com using its Zope4Media Print product.
Added: CMF/branches/goldegg-phase-1/GenericSetup/DEPENDENCIES.txt
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/DEPENDENCIES.txt 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/DEPENDENCIES.txt 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1 @@
+Zope >= 2.8.0
Added: CMF/branches/goldegg-phase-1/GenericSetup/PROFILES.txt
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/PROFILES.txt 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/PROFILES.txt 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,40 @@
+Profiles
+
+ Overview
+
+ There are two different kinds of profiles: Base profiles and extension
+ profiles. Base profiles have no dependencies. Extension profiles are
+ profile fragments used to modify base profiles. They can be shipped with
+ add-on products or used for customization steps. Importing an extension
+ profile adds or overwrites existing settings in a fine-grained way. You
+ can't export extension profiles. Snapshots and exports always represent
+ the merged settings.
+
+ Update Directives
+
+ For some XML elements there are additional attributes and values to
+ specify update directives. They are only useful for extension profiles and
+ you will never see them in snapshots and exports.
+
+ 'insert-before' and 'insert-after'
+
+ applies to: object (generic); layer (skins.xml)
+
+ 'insert-before' and 'insert-after' specify the position of a new item
+ relative to an existing item. If they are omitted or not valid, items
+ are appended. You can also use '*' as wildcard. This will insert the new
+ item at the top (before all existing items) or the bottom (after all
+ existing items). If an item with the given ID exists already, it is
+ moved to the specified position.
+
+ 'id="*"' wildcard
+
+ applies to: skin-path (skins.xml)
+
+ Updates all existing items in the container with the same settings.
+
+ 'remove'
+
+ applies to: action-provider, skin layer (actions.xml, skins.xml)
+
+ Removes the specified item if it exists.
Added: CMF/branches/goldegg-phase-1/GenericSetup/README.txt
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/README.txt 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/README.txt 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,48 @@
+GenericSetup Product README
+
+ Overview
+
+ This product is a "cut-down" version of the CMFSetup product, shipped
+ with CMF 1.5.x: it removes all CMF dependencies. In the ideal world,
+ CMFSetup would depend on this product, and supply the CMF-specific bits
+ (handlers for actions, types, workflows, etc.).
+
+ This product provides a mini-framework for expressing the configured
+ state of a Zope Site as a set of filesystem artifacts. These artifacts
+ consist of declarative XML files, which spell out the configuration
+ settings for each "tool" in the site , and supporting scripts / templates,
+ in their "canonical" filesystem representations.
+
+ Configurations Included
+
+ The 'setup_tool' knows how to export / import configurations and scripts
+ for the following tools:
+
+ - (x) removal / creation of specified tools
+
+ - (x) itself :)
+
+ - (x) the role / permission map on the "site" object (its parent)
+
+ - (x) properties of the site object
+
+ Extending The Tool
+
+ Third-party products extend the tool by registering handlers for
+ import / export of their unique tools.
+
+ Glossary
+
+ Site --
+ The instance in the Zope URL space which defines a "zone of service"
+ for a set of tools.
+
+ Profile --
+ A "preset" configuration of a site, defined on the filesystem
+
+ Snapshot --
+ "Frozen" site configuration, captured within the setup tool
+
+ "dotted name" --
+ The Pythonic representation of the "path" to a given function /
+ module, e.g. 'Products.CMFSetup.utils.ConfiguratorBase'.
Added: CMF/branches/goldegg-phase-1/GenericSetup/__init__.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/__init__.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/__init__.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,26 @@
+""" GenericSetup product initialization.
+
+$Id: __init__.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+from AccessControl import ModuleSecurityInfo
+
+from interfaces import BASE, EXTENSION
+from permissions import ManagePortal
+from registry import _profile_registry as profile_registry
+
+security = ModuleSecurityInfo('Products.GenericSetup')
+security.declareProtected(ManagePortal, 'profile_registry')
+
+def initialize(context):
+
+ import tool
+
+ context.registerClass(tool.SetupTool,
+ constructors=(#tool.addSetupToolForm,
+ tool.addSetupTool,
+ ),
+ permissions=(ManagePortal,),
+ interfaces=None,
+ icon='www/tool.png',
+ )
Added: CMF/branches/goldegg-phase-1/GenericSetup/context.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/context.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/context.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,561 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Various context implementations for export / import of configurations.
+
+Wrappers representing the state of an import / export operation.
+
+$Id: context.py,v 1.2 2005/08/11 21:41:36 tseaver Exp $
+"""
+
+import os
+import time
+from StringIO import StringIO
+from tarfile import TarFile
+from tarfile import TarInfo
+
+from AccessControl import ClassSecurityInfo
+from Acquisition import aq_inner
+from Acquisition import aq_parent
+from Acquisition import aq_self
+from Acquisition import Implicit
+from DateTime.DateTime import DateTime
+from Globals import InitializeClass
+from OFS.DTMLDocument import DTMLDocument
+from OFS.Folder import Folder
+from OFS.Image import File
+from OFS.Image import Image
+from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
+from Products.PythonScripts.PythonScript import PythonScript
+from zope.interface import implements
+
+from interfaces import IExportContext
+from interfaces import IImportContext
+from permissions import ManagePortal
+
+
+class DirectoryImportContext( Implicit ):
+
+ implements(IImportContext)
+
+ security = ClassSecurityInfo()
+
+ def __init__( self
+ , tool
+ , profile_path
+ , should_purge=False
+ , encoding=None
+ ):
+
+ self._site = aq_parent( aq_inner( tool ) )
+ self._profile_path = profile_path
+ self._should_purge = bool( should_purge )
+ self._encoding = encoding
+
+ security.declareProtected( ManagePortal, 'getSite' )
+ def getSite( self ):
+
+ """ See ISetupContext.
+ """
+ return aq_self(self._site)
+
+ security.declareProtected( ManagePortal, 'getEncoding' )
+ def getEncoding( self ):
+
+ """ See IImportContext.
+ """
+ return self._encoding
+
+ security.declareProtected( ManagePortal, 'readDataFile' )
+ def readDataFile( self, filename, subdir=None ):
+
+ """ See IImportContext.
+ """
+ if subdir is None:
+ full_path = os.path.join( self._profile_path, filename )
+ else:
+ full_path = os.path.join( self._profile_path, subdir, filename )
+
+ if not os.path.exists( full_path ):
+ return None
+
+ file = open( full_path, 'rb' )
+ result = file.read()
+ file.close()
+
+ return result
+
+ security.declareProtected( ManagePortal, 'getLastModified' )
+ def getLastModified( self, path ):
+
+ """ See IImportContext.
+ """
+ full_path = os.path.join( self._profile_path, path )
+
+ if not os.path.exists( full_path ):
+ return None
+
+ return DateTime( os.path.getmtime( full_path ) )
+
+ security.declareProtected( ManagePortal, 'isDirectory' )
+ def isDirectory( self, path ):
+
+ """ See IImportContext.
+ """
+ full_path = os.path.join( self._profile_path, path )
+
+ if not os.path.exists( full_path ):
+ return None
+
+ return os.path.isdir( full_path )
+
+ security.declareProtected( ManagePortal, 'listDirectory' )
+ def listDirectory( self, path, skip=('CVS', '.svn') ):
+
+ """ See IImportContext.
+ """
+ if path is None:
+ path = ''
+
+ full_path = os.path.join( self._profile_path, path )
+
+ if not os.path.exists( full_path ) or not os.path.isdir( full_path ):
+ return None
+
+ names = os.listdir( full_path )
+
+ return [ name for name in names if name not in skip ]
+
+ security.declareProtected( ManagePortal, 'shouldPurge' )
+ def shouldPurge( self ):
+
+ """ See IImportContext.
+ """
+ return self._should_purge
+
+InitializeClass( DirectoryImportContext )
+
+
+class DirectoryExportContext( Implicit ):
+
+ implements(IExportContext)
+
+ security = ClassSecurityInfo()
+
+ def __init__( self, tool, profile_path ):
+
+ self._site = aq_parent( aq_inner( tool ) )
+ self._profile_path = profile_path
+
+ security.declareProtected( ManagePortal, 'getSite' )
+ def getSite( self ):
+
+ """ See ISetupContext.
+ """
+ return aq_self(self._site)
+
+ security.declareProtected( ManagePortal, 'writeDataFile' )
+ def writeDataFile( self, filename, text, content_type, subdir=None ):
+
+ """ See IExportContext.
+ """
+ if subdir is None:
+ prefix = self._profile_path
+ else:
+ prefix = os.path.join( self._profile_path, subdir )
+
+ full_path = os.path.join( prefix, filename )
+
+ if not os.path.exists( prefix ):
+ os.makedirs( prefix )
+
+ mode = content_type.startswith( 'text/' ) and 'w' or 'wb'
+
+ file = open( full_path, mode )
+ file.write( text )
+ file.close()
+
+InitializeClass( DirectoryExportContext )
+
+
+class TarballImportContext( Implicit ):
+
+ implements(IImportContext)
+
+ security = ClassSecurityInfo()
+
+ def __init__( self, tool, archive_bits, encoding=None, should_purge=False ):
+
+ self._site = aq_parent( aq_inner( tool ) )
+ timestamp = time.gmtime()
+ self._archive_stream = StringIO(archive_bits)
+ self._archive = TarFile.open( 'foo.bar', 'r:gz'
+ , self._archive_stream )
+ self._encoding = encoding
+ self._should_purge = bool( should_purge )
+
+ security.declareProtected( ManagePortal, 'getSite' )
+ def getSite( self ):
+
+ """ See ISetupContext.
+ """
+ return aq_self(self._site)
+
+ def getEncoding( self ):
+
+ """ See IImportContext.
+ """
+ return self._encoding
+
+ def readDataFile( self, filename, subdir=None ):
+
+ """ See IImportContext.
+ """
+ if subdir is not None:
+ filename = os.path.join( subdir, filename )
+
+ try:
+ file = self._archive.extractfile( filename )
+ except KeyError:
+ return None
+
+ return file.read()
+
+ def getLastModified( self, path ):
+
+ """ See IImportContext.
+ """
+ info = self._getTarInfo( path )
+ return info and info.mtime or None
+
+ def isDirectory( self, path ):
+
+ """ See IImportContext.
+ """
+ info = self._getTarInfo( path )
+
+ if info is not None:
+ return info.isdir()
+
+ def listDirectory( self, path, skip=('CVS', '.svn') ):
+
+ """ See IImportContext.
+ """
+ if path is None: # root is special case: no leading '/'
+ path = ''
+ else:
+ if not self.isDirectory(path):
+ return None
+
+ if path[-1] != '/':
+ path = path + '/'
+
+ pfx_len = len(path)
+
+ beneath = [x[pfx_len:] for x in self._archive.getnames()
+ if x.startswith(path) and x != path]
+
+ return [x for x in beneath if '/' not in x and x not in skip]
+
+ def shouldPurge( self ):
+
+ """ See IImportContext.
+ """
+ return self._should_purge
+
+ def _getTarInfo( self, path ):
+ if path[-1] == '/':
+ path = path[:-1]
+ try:
+ return self._archive.getmember( path )
+ except KeyError:
+ pass
+ try:
+ return self._archive.getmember( path + '/' )
+ except KeyError:
+ return None
+
+
+class TarballExportContext( Implicit ):
+
+ implements(IExportContext)
+
+ security = ClassSecurityInfo()
+
+ def __init__( self, tool ):
+
+ self._site = aq_parent( aq_inner( tool ) )
+ timestamp = time.gmtime()
+ archive_name = ( 'setup_tool-%4d%02d%02d%02d%02d%02d.tar.gz'
+ % timestamp[:6] )
+
+ self._archive_stream = StringIO()
+ self._archive_filename = archive_name
+ self._archive = TarFile.open( archive_name, 'w:gz'
+ , self._archive_stream )
+
+ security.declareProtected( ManagePortal, 'getSite' )
+ def getSite( self ):
+
+ """ See ISetupContext.
+ """
+ return aq_self(self._site)
+
+ security.declareProtected( ManagePortal, 'writeDataFile' )
+ def writeDataFile( self, filename, text, content_type, subdir=None ):
+
+ """ See IExportContext.
+ """
+ if subdir is not None:
+ filename = os.path.join( subdir, filename )
+
+ stream = StringIO( text )
+ info = TarInfo( filename )
+ info.size = len( text )
+ info.mtime = time.time()
+ self._archive.addfile( info, stream )
+
+ security.declareProtected( ManagePortal, 'getArchive' )
+ def getArchive( self ):
+
+ """ Close the archive, and return it as a big string.
+ """
+ self._archive.close()
+ return self._archive_stream.getvalue()
+
+ security.declareProtected( ManagePortal, 'getArchiveFilename' )
+ def getArchiveFilename( self ):
+
+ """ Close the archive, and return it as a big string.
+ """
+ return self._archive_filename
+
+InitializeClass( TarballExportContext )
+
+
+class SnapshotExportContext( Implicit ):
+
+ implements(IExportContext)
+
+ security = ClassSecurityInfo()
+
+ def __init__( self, tool, snapshot_id ):
+
+ self._tool = tool = aq_inner( tool )
+ self._site = aq_parent( tool )
+ self._snapshot_id = snapshot_id
+
+ security.declareProtected( ManagePortal, 'getSite' )
+ def getSite( self ):
+
+ """ See ISetupContext.
+ """
+ return aq_self(self._site)
+
+ security.declareProtected( ManagePortal, 'writeDataFile' )
+ def writeDataFile( self, filename, text, content_type, subdir=None ):
+
+ """ See IExportContext.
+ """
+ folder = self._ensureSnapshotsFolder( subdir )
+
+ # TODO: switch on content_type
+ ob = self._createObjectByType( filename, text, content_type )
+ folder._setObject( str( filename ), ob ) # No Unicode IDs!
+
+ security.declareProtected( ManagePortal, 'getSnapshotURL' )
+ def getSnapshotURL( self ):
+
+ """ See IExportContext.
+ """
+ return '%s/%s' % ( self._tool.absolute_url(), self._snapshot_id )
+
+ security.declareProtected( ManagePortal, 'getSnapshotFolder' )
+ def getSnapshotFolder( self ):
+
+ """ See IExportContext.
+ """
+ return self._ensureSnapshotsFolder()
+
+ #
+ # Helper methods
+ #
+ security.declarePrivate( '_createObjectByType' )
+ def _createObjectByType( self, name, body, content_type ):
+
+ if name.endswith('.py'):
+
+ ob = PythonScript( name )
+ ob.write( body )
+
+ elif name.endswith('.dtml'):
+
+ ob = DTMLDocument( '', __name__=name )
+ ob.munge( body )
+
+ elif content_type in ('text/html', 'text/xml' ):
+
+ ob = ZopePageTemplate( name, str( body )
+ , content_type=content_type )
+
+ elif content_type[:6]=='image/':
+
+ ob=Image( name, '', body, content_type=content_type )
+
+ else:
+ ob=File( name, '', body, content_type=content_type )
+
+ return ob
+
+ security.declarePrivate( '_ensureSnapshotsFolder' )
+ def _ensureSnapshotsFolder( self, subdir=None ):
+
+ """ Ensure that the appropriate snapshot folder exists.
+ """
+ path = [ 'snapshots', self._snapshot_id ]
+
+ if subdir is not None:
+ path.extend( subdir.split( '/' ) )
+
+ current = self._tool
+
+ for element in path:
+
+ if element not in current.objectIds():
+ # No Unicode IDs!
+ current._setObject( str( element ), Folder( element ) )
+
+ current = current._getOb( element )
+
+ return current
+
+InitializeClass( SnapshotExportContext )
+
+
+class SnapshotImportContext( Implicit ):
+
+ implements(IImportContext)
+
+ security = ClassSecurityInfo()
+
+ def __init__( self
+ , tool
+ , snapshot_id
+ , should_purge=False
+ , encoding=None
+ ):
+
+ self._tool = tool = aq_inner( tool )
+ self._site = aq_parent( tool )
+ self._snapshot_id = snapshot_id
+ self._encoding = encoding
+ self._should_purge = bool( should_purge )
+
+ security.declareProtected( ManagePortal, 'getSite' )
+ def getSite( self ):
+
+ """ See ISetupContext.
+ """
+ return aq_self(self._site)
+
+ security.declareProtected( ManagePortal, 'getEncoding' )
+ def getEncoding( self ):
+
+ """ Return the encoding used in data files.
+
+ o Return None if the data should not be encoded.
+ """
+ return self._encoding
+
+ security.declareProtected( ManagePortal, 'readDataFile' )
+ def readDataFile( self, filename, subdir=None ):
+
+ """ See IImportContext.
+ """
+ try:
+ snapshot = self._getSnapshotFolder( subdir )
+ object = snapshot._getOb( filename )
+ except ( AttributeError, KeyError ):
+ return None
+
+ try:
+ return object.read()
+ except AttributeError:
+ return object.manage_FTPget()
+
+ security.declareProtected( ManagePortal, 'getLastModified' )
+ def getLastModified( self, path ):
+
+ """ See IImportContext.
+ """
+ try:
+ snapshot = self._getSnapshotFolder()
+ object = snapshot.restrictedTraverse( path )
+ except ( AttributeError, KeyError ):
+ return None
+ else:
+ return object.bobobase_modification_time()
+
+ security.declareProtected( ManagePortal, 'isDirectory' )
+ def isDirectory( self, path ):
+
+ """ See IImportContext.
+ """
+ try:
+ snapshot = self._getSnapshotFolder()
+ object = snapshot.restrictedTraverse( path )
+ except ( AttributeError, KeyError ):
+ return None
+ else:
+ folderish = getattr( object, 'isPrincipiaFolderish', False )
+ return bool( folderish )
+
+ security.declareProtected( ManagePortal, 'listDirectory' )
+ def listDirectory( self, path, skip=() ):
+
+ """ See IImportContext.
+ """
+ try:
+ snapshot = self._getSnapshotFolder()
+ subdir = snapshot.restrictedTraverse( path )
+ except ( AttributeError, KeyError ):
+ return None
+ else:
+ if not getattr( subdir, 'isPrincipiaFolderish', False ):
+ return None
+
+ object_ids = subdir.objectIds()
+ return [ x for x in object_ids if x not in skip ]
+
+ security.declareProtected( ManagePortal, 'shouldPurge' )
+ def shouldPurge( self ):
+
+ """ See IImportContext.
+ """
+ return self._should_purge
+
+ #
+ # Helper methods
+ #
+ security.declarePrivate( '_getSnapshotFolder' )
+ def _getSnapshotFolder( self, subdir=None ):
+
+ """ Return the appropriate snapshot (sub)folder.
+ """
+ path = [ 'snapshots', self._snapshot_id ]
+
+ if subdir is not None:
+ path.extend( subdir.split( '/' ) )
+
+ return self._tool.restrictedTraverse( path )
+
+InitializeClass( SnapshotImportContext )
Added: CMF/branches/goldegg-phase-1/GenericSetup/differ.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/differ.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/differ.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,229 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Diff utilities for comparing configurations.
+
+$Id: differ.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+from difflib import unified_diff
+import re
+
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+
+BLANKS_REGEX = re.compile( r'^\s*$' )
+
+def unidiff( a
+ , b
+ , filename_a='original'
+ , timestamp_a=None
+ , filename_b='modified'
+ , timestamp_b=None
+ , ignore_blanks=False
+ ):
+ r"""Compare two sequences of lines; generate the resulting delta.
+
+ Each sequence must contain individual single-line strings
+ ending with newlines. Such sequences can be obtained from the
+ `readlines()` method of file-like objects. The delta
+ generated also consists of newline-terminated strings, ready
+ to be printed as-is via the writeline() method of a file-like
+ object.
+
+ Note that the last line of a file may *not* have a newline;
+ this is reported in the same way that GNU diff reports this.
+ *This method only supports UNIX line ending conventions.*
+
+ filename_a and filename_b are used to generate the header,
+ allowing other tools to determine what 'files' were used
+ to generate this output.
+
+ timestamp_a and timestamp_b, when supplied, are expected
+ to be last-modified timestamps to be inserted in the
+ header, as floating point values since the epoch.
+
+ Example:
+
+ >>> print ''.join(UniDiffer().compare(
+ ... 'one\ntwo\nthree\n'.splitlines(1),
+ ... 'ore\ntree\nemu\n'.splitlines(1))),
+ +++ original
+ --- modified
+ @@ -1,3 +1,3 @@
+ -one
+ +ore
+ -two
+ -three
+ +tree
+ +emu
+ """
+ if isinstance( a, basestring ):
+ a = a.splitlines()
+
+ if isinstance( b, basestring ):
+ b = b.splitlines()
+
+ if ignore_blanks:
+ a = [ x for x in a if not BLANKS_REGEX.match( x ) ]
+ b = [ x for x in b if not BLANKS_REGEX.match( x ) ]
+
+ return unified_diff( a
+ , b
+ , filename_a
+ , filename_b
+ , timestamp_a
+ , timestamp_b
+ , lineterm=""
+ )
+
+class ConfigDiff:
+
+ security = ClassSecurityInfo()
+
+ def __init__( self
+ , lhs
+ , rhs
+ , missing_as_empty=False
+ , ignore_blanks=False
+ , skip=('CVS','.svn')
+ ):
+ self._lhs = lhs
+ self._rhs = rhs
+ self._missing_as_empty = missing_as_empty
+ self._ignore_blanks=ignore_blanks
+ self._skip = skip
+
+ security.declarePrivate( 'compareDirectories' )
+ def compareDirectories( self, subdir=None ):
+
+ lhs_files = self._lhs.listDirectory( subdir, self._skip )
+ if lhs_files is None:
+ lhs_files = []
+
+ rhs_files = self._rhs.listDirectory( subdir, self._skip )
+ if rhs_files is None:
+ rhs_files = []
+
+ added = [ f for f in rhs_files if f not in lhs_files ]
+ removed = [ f for f in lhs_files if f not in rhs_files ]
+ all_files = lhs_files + added
+ all_files.sort()
+
+ result = []
+
+ for filename in all_files:
+
+ if subdir is None:
+ pathname = filename
+ else:
+ pathname = '%s/%s' % ( subdir, filename )
+
+ if filename not in added:
+ isDirectory = self._lhs.isDirectory( pathname )
+ else:
+ isDirectory = self._rhs.isDirectory( pathname )
+
+ if not self._missing_as_empty and filename in removed:
+
+ if isDirectory:
+ result.append( '** Directory %s removed\n' % pathname )
+ result.extend( self.compareDirectories( pathname ) )
+ else:
+ result.append( '** File %s removed\n' % pathname )
+
+ elif not self._missing_as_empty and filename in added:
+
+ if isDirectory:
+ result.append( '** Directory %s added\n' % pathname )
+ result.extend( self.compareDirectories( pathname ) )
+ else:
+ result.append( '** File %s added\n' % pathname )
+
+ elif isDirectory:
+
+ result.extend( self.compareDirectories( pathname ) )
+
+ if ( filename not in added + removed and
+ not self._rhs.isDirectory( pathname ) ):
+
+ result.append( '** Directory %s replaced with a file of '
+ 'the same name\n' % pathname )
+
+ if self._missing_as_empty:
+ result.extend( self.compareFiles( filename, subdir ) )
+ else:
+ if ( filename not in added + removed and
+ self._rhs.isDirectory( pathname ) ):
+
+ result.append( '** File %s replaced with a directory of '
+ 'the same name\n' % pathname )
+
+ if self._missing_as_empty:
+ result.extend( self.compareFiles( filename, subdir ) )
+
+ result.extend( self.compareDirectories( pathname ) )
+ else:
+ result.extend( self.compareFiles( filename, subdir ) )
+
+ return result
+
+ security.declarePrivate( 'compareFiles' )
+ def compareFiles( self, filename, subdir=None ):
+
+ if subdir is None:
+ path = filename
+ else:
+ path = '%s/%s' % ( subdir, filename )
+
+ lhs_file = self._lhs.readDataFile( filename, subdir )
+ lhs_time = self._lhs.getLastModified( path )
+
+ if lhs_file is None:
+ assert self._missing_as_empty
+ lhs_file = ''
+ lhs_time = 0
+
+ rhs_file = self._rhs.readDataFile( filename, subdir )
+ rhs_time = self._rhs.getLastModified( path )
+
+ if rhs_file is None:
+ assert self._missing_as_empty
+ rhs_file = ''
+ rhs_time = 0
+
+ if lhs_file == rhs_file:
+ diff_lines = []
+ else:
+ diff_lines = unidiff( lhs_file
+ , rhs_file
+ , filename_a=path
+ , timestamp_a=lhs_time
+ , filename_b=path
+ , timestamp_b=rhs_time
+ , ignore_blanks=self._ignore_blanks
+ )
+ diff_lines = list( diff_lines ) # generator
+
+ if len( diff_lines ) == 0: # No *real* difference found
+ return []
+
+ diff_lines.insert( 0, 'Index: %s' % path )
+ diff_lines.insert( 1, '=' * 67 )
+
+ return diff_lines
+
+ security.declarePrivate( 'compare' )
+ def compare( self ):
+ return '\n'.join( self.compareDirectories() )
+
+InitializeClass( ConfigDiff )
Added: CMF/branches/goldegg-phase-1/GenericSetup/exceptions.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/exceptions.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/exceptions.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,22 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" GenericSetup product exceptions.
+
+$Id: exceptions.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+from AccessControl import ModuleSecurityInfo
+security = ModuleSecurityInfo('Products.GenericSetup.exceptions')
+
+security.declarePublic('BadRequest')
+from zExceptions import BadRequest
Added: CMF/branches/goldegg-phase-1/GenericSetup/factory.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/factory.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/factory.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,76 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Configured site factory implementation.
+
+$Id: factory.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+
+from interfaces import EXTENSION
+from registry import _profile_registry as profile_registry
+from tool import SetupTool
+from utils import _wwwdir
+
+def addConfiguredSiteForm( dispatcher ):
+
+ """ Wrap the PTF in 'dispatcher', including 'profile_registry' in options.
+ """
+ wrapped = PageTemplateFile( 'siteAddForm', _wwwdir ).__of__( dispatcher )
+
+ base_profiles = []
+ extension_profiles = []
+
+ for info in profile_registry.listProfileInfo():
+ if info.get('type') == EXTENSION:
+ extension_profiles.append(info)
+ else:
+ base_profiles.append(info)
+
+ return wrapped( base_profiles=tuple(base_profiles),
+ extension_profiles =tuple(extension_profiles) )
+
+def addConfiguredSite( dispatcher
+ , site_id
+ , profile_id
+ , snapshot=True
+ , RESPONSE=None
+ , extension_ids=()
+ ):
+
+ """ Add a CMFSite to 'dispatcher', configured according to 'profile_id'.
+ """
+ from Products.CMFCore.utils import getToolByName
+ from Products.CMFDefault.Portal import CMFSite # XXX: store in profile!
+
+ site = CMFSite( site_id )
+ dispatcher._setObject( site_id, site )
+ site = dispatcher._getOb( site_id )
+
+ setup_tool = SetupTool()
+ site._setObject( 'setup_tool', setup_tool )
+ setup_tool = getToolByName( site, 'setup_tool' )
+
+ setup_tool.setImportContext( 'profile-%s' % profile_id )
+ setup_tool.runAllImportSteps()
+ for extension_id in extension_ids:
+ setup_tool.setImportContext( 'profile-%s' % extension_id )
+ setup_tool.runAllImportSteps()
+ setup_tool.setImportContext( 'profile-%s' % profile_id )
+
+ if snapshot is True:
+ setup_tool.createSnapshot( 'initial_configuration' )
+
+ if RESPONSE is not None:
+ RESPONSE.redirect( '%s/manage_main?update_menu=1'
+ % dispatcher.absolute_url() )
Added: CMF/branches/goldegg-phase-1/GenericSetup/interfaces.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/interfaces.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/interfaces.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,508 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" GenericSetup product interfaces
+
+$Id: interfaces.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+from zope.interface import Interface
+
+
+BASE, EXTENSION = range(2)
+
+
+class IPseudoInterface( Interface ):
+
+ """ API documentation; not testable / enforceable.
+ """
+
+class ISetupContext( Interface ):
+
+ """ Context used for export / import plugins.
+ """
+ def getSite():
+
+ """ Return the site object being configured / dumped.
+ """
+
+class IImportContext( ISetupContext ):
+
+ def getEncoding():
+
+ """ Get the encoding used for configuration data within the site.
+
+ o Return None if the data should not be encoded.
+ """
+
+ def readDataFile( filename, subdir=None ):
+
+ """ Search the current configuration for the requested file.
+
+ o 'filename' is the name (without path elements) of the file.
+
+ o 'subdir' is an optional subdirectory; if not supplied, search
+ only the "root" directory.
+
+ o Return the file contents as a string, or None if the
+ file cannot be found.
+ """
+
+ def getLastModified( path ):
+
+ """ Return the modification timestamp of the item at 'path'.
+
+ o Result will be a DateTime instance.
+
+ o Search profiles in the configuration in order.
+
+ o If the context is filesystem based, return the 'stat' timestamp
+ of the file / directory to which 'path' points.
+
+ o If the context is ZODB-based, return the Zope modification time
+ of the object to which 'path' points.
+
+ o Return None if 'path' does not point to any object.
+ """
+
+ def isDirectory( path ):
+
+ """ Test whether path points to a directory / folder.
+
+ o If the context is filesystem based, check that 'path' points to
+ a subdirectory within the "root" directory.
+
+ o If the context is ZODB-based, check that 'path' points to a
+ "container" under the context's tool.
+
+ o Return None if 'path' does not resolve; otherwise, return a
+ bool.
+ """
+
+ def listDirectory( path, skip=('CVS', '.svn') ):
+
+ """ List IDs of the contents of a directory / folder.
+
+ o Omit names in 'skip'.
+
+ o If 'path' does not point to a directory / folder, return None.
+ """
+
+ def shouldPurge():
+
+ """ When installing, should the existing setup be purged?
+ """
+
+class IImportPlugin( IPseudoInterface ):
+
+ """ Signature for callables used to import portions of site configuration.
+ """
+ def __call__( context ):
+
+ """ Perform the setup step.
+
+ o Return a message describing the work done.
+
+ o 'context' must implement IImportContext.
+ """
+
+class IExportContext( ISetupContext ):
+
+ def writeDataFile( filename, text, content_type, subdir=None ):
+
+ """ Write data into the specified location.
+
+ o 'filename' is the unqualified name of the file.
+
+ o 'text' is the content of the file.
+
+ o 'content_type' is the MIMEtype of the file.
+
+ o 'subdir', if passed, is a path to a subdirectory / folder in
+ which to write the file; if not passed, write the file to the
+ "root" of the target.
+ """
+
+class IExportPlugin( IPseudoInterface ):
+
+ """ Signature for callables used to export portions of site configuration.
+ """
+ def __call__( context ):
+
+ """ Write export data for the site wrapped by context.
+
+ o Return a message describing the work done.
+
+ o 'context' must implement IExportContext. The plugin will use
+ its 'writeDataFile' method for each file to be exported.
+ """
+
+class IStepRegistry( Interface ):
+
+ """ Base interface for step registries.
+ """
+ def listSteps():
+
+ """ Return a sequence of IDs of registered steps.
+
+ o Order is not significant.
+ """
+
+ def listStepMetadata():
+
+ """ Return a sequence of mappings describing registered steps.
+
+ o Mappings will be ordered alphabetically.
+ """
+
+ def getStepMetadata( key, default=None ):
+
+ """ Return a mapping of metadata for the step identified by 'key'.
+
+ o Return 'default' if no such step is registered.
+
+ o The 'handler' metadata is available via 'getStep'.
+ """
+
+ def generateXML():
+
+ """ Return a round-trippable XML representation of the registry.
+
+ o 'handler' values are serialized using their dotted names.
+ """
+
+ def parseXML( text ):
+
+ """ Parse 'text'.
+ """
+
+class IImportStepRegistry( IStepRegistry ):
+
+ """ API for import step registry.
+ """
+ def sortSteps():
+
+ """ Return a sequence of registered step IDs
+
+ o Sequence is sorted topologically by dependency, with the dependent
+ steps *after* the steps they depend on.
+ """
+
+ def checkComplete():
+
+ """ Return a sequence of ( node, edge ) tuples for unsatisifed deps.
+ """
+
+ def getStep( key, default=None ):
+
+ """ Return the IImportPlugin registered for 'key'.
+
+ o Return 'default' if no such step is registered.
+ """
+
+ def registerStep( id
+ , version
+ , handler
+ , dependencies=()
+ , title=None
+ , description=None
+ ):
+ """ Register a setup step.
+
+ o 'id' is a unique name for this step,
+
+ o 'version' is a string for comparing versions, it is preferred to
+ be a yyyy/mm/dd-ii formatted string (date plus two-digit
+ ordinal). when comparing two version strings, the version with
+ the lower sort order is considered the older version.
+
+ - Newer versions of a step supplant older ones.
+
+ - Attempting to register an older one after a newer one results
+ in a KeyError.
+
+ o 'handler' should implement IImportPlugin.
+
+ o 'dependencies' is a tuple of step ids which have to run before
+ this step in order to be able to run at all. Registration of
+ steps that have unmet dependencies are deferred until the
+ dependencies have been registered.
+
+ o 'title' is a one-line UI description for this step.
+ If None, the first line of the documentation string of the handler
+ is used, or the id if no docstring can be found.
+
+ o 'description' is a one-line UI description for this step.
+ If None, the remaining line of the documentation string of
+ the handler is used, or default to ''.
+ """
+
+class IExportStepRegistry( IStepRegistry ):
+
+ """ API for export step registry.
+ """
+ def getStep( key, default=None ):
+
+ """ Return the IExportPlugin registered for 'key'.
+
+ o Return 'default' if no such step is registered.
+ """
+
+ def registerStep( id, handler, title=None, description=None ):
+
+ """ Register an export step.
+
+ o 'id' is the unique identifier for this step
+
+ o 'handler' should implement IExportPlugin.
+
+ o 'title' is a one-line UI description for this step.
+ If None, the first line of the documentation string of the step
+ is used, or the id if no docstring can be found.
+
+ o 'description' is a one-line UI description for this step.
+ If None, the remaining line of the documentation string of
+ the step is used, or default to ''.
+ """
+
+class IToolsetRegistry( Interface ):
+
+ """ API for toolset registry.
+ """
+ def listForbiddenTools():
+
+ """ Return a list of IDs of tools which must be removed, if present.
+ """
+
+ def addForbiddenTool(tool_id ):
+
+ """ Add 'tool_id' to the list of forbidden tools.
+
+ o Raise KeyError if 'tool_id' is already in the list.
+
+ o Raise ValueError if 'tool_id' is in the "required" list.
+ """
+
+ def listRequiredTools():
+
+ """ Return a list of IDs of tools which must be present.
+ """
+
+ def getRequiredToolInfo( tool_id ):
+
+ """ Return a mapping describing a partiuclar required tool.
+
+ o Keys include:
+
+ 'id' -- the ID of the tool
+
+ 'class' -- a dotted path to its class
+
+ o Raise KeyError if 'tool_id' id not a known tool.
+ """
+
+ def listRequiredToolInfo():
+
+ """ Return a list of IDs of tools which must be present.
+ """
+
+ def addRequiredTool( tool_id, dotted_name ):
+
+ """ Add a tool to our "required" list.
+
+ o 'tool_id' is the tool's ID.
+
+ o 'dotted_name' is a dotted (importable) name of the tool's class.
+
+ o Raise KeyError if we have already registered a class for 'tool_id'.
+
+ o Raise ValueError if 'tool_id' is in the "forbidden" list.
+ """
+
+class IProfileRegistry( Interface ):
+
+ """ API for profile registry.
+ """
+ def getProfileInfo( profile_id ):
+
+ """ Return a mapping describing a registered filesystem profile.
+
+ o Keys include:
+
+ 'id' -- the ID of the profile
+
+ 'title' -- its title
+
+ 'description' -- a textual description of the profile
+
+ 'path' -- a path to the profile on the filesystem.
+
+ 'product' -- the name of the product to which 'path' is
+ relative (None for absolute paths).
+
+ 'type' -- either BASE or EXTENSION
+ """
+
+ def listProfiles():
+
+ """ Return a list of IDs for registered profiles.
+ """
+
+ def listProfileInfo():
+
+ """ Return a list of mappings describing registered profiles.
+
+ o See 'getProfileInfo' for a description of the mappings' keys.
+ """
+
+ def registerProfile( name
+ , title
+ , description
+ , path
+ , product=None
+ , profile_type=BASE
+ ):
+ """ Add a new profile to the registry.
+
+ o If an existing profile is already registered for 'product:name',
+ raise KeyError.
+
+ o If 'product' is passed, then 'path' should be interpreted as
+ relative to the corresponding product directory.
+ """
+
+class ISetupTool( Interface ):
+
+ """ API for SetupTool.
+ """
+
+ def getEncoding():
+
+ """ Get the encoding used for configuration data within the site.
+
+ o Return None if the data should not be encoded.
+ """
+
+ def getImportContextID():
+
+ """ Get the ID of the active import context.
+ """
+
+ def setImportContext( context_id ):
+
+ """ Set the ID of the active import context and update the registries.
+ """
+
+ def getImportStepRegistry():
+
+ """ Return the IImportStepRegistry for the tool.
+ """
+
+ def getExportStepRegistry():
+
+ """ Return the IExportStepRegistry for the tool.
+ """
+
+ def getToolsetRegistry():
+
+ """ Return the IToolsetRegistry for the tool.
+ """
+
+ def runImportStep( step_id, run_dependencies=True, purge_old=None ):
+
+ """ Execute a given setup step
+
+ o 'step_id' is the ID of the step to run.
+
+ o If 'purge_old' is True, then run the step after purging any
+ "old" setup first (this is the responsibility of the step,
+ which must check the context we supply).
+
+ o If 'run_dependencies' is True, then run any out-of-date
+ dependency steps first.
+
+ o Return a mapping, with keys:
+
+ 'steps' -- a sequence of IDs of the steps run.
+
+ 'messages' -- a dictionary holding messages returned from each
+ step
+ """
+
+ def runAllImportSteps( purge_old=None ):
+
+ """ Run all setup steps in dependency order.
+
+ o If 'purge_old' is True, then run each step after purging any
+ "old" setup first (this is the responsibility of the step,
+ which must check the context we supply).
+
+ o Return a mapping, with keys:
+
+ 'steps' -- a sequence of IDs of the steps run.
+
+ 'messages' -- a dictionary holding messages returned from each
+ step
+ """
+
+ def runExportStep( step_id ):
+
+ """ Generate a tarball containing artifacts from one export step.
+
+ o 'step_id' identifies the export step.
+
+ o Return a mapping, with keys:
+
+ 'steps' -- a sequence of IDs of the steps run.
+
+ 'messages' -- a dictionary holding messages returned from each
+ step
+
+ 'tarball' -- the stringified tar-gz data.
+ """
+
+ def runAllExportSteps():
+
+ """ Generate a tarball containing artifacts from all export steps.
+
+ o Return a mapping, with keys:
+
+ 'steps' -- a sequence of IDs of the steps run.
+
+ 'messages' -- a dictionary holding messages returned from each
+ step
+
+ 'tarball' -- the stringified tar-gz data.
+ """
+
+ def createSnapshot( snapshot_id ):
+
+ """ Create a snapshot folder using all steps.
+
+ o 'snapshot_id' is the ID of the new folder.
+ """
+
+ def compareConfigurations( lhs_context
+ , rhs_context
+ , missing_as_empty=False
+ , ignore_whitespace=False
+ ):
+ """ Compare two configurations.
+
+ o 'lhs_context' and 'rhs_context' must implement IImportContext.
+
+ o If 'missing_as_empty', then compare files not present as though
+ they were zero-length; otherwise, omit such files.
+
+ o If 'ignore_whitespace', then suppress diffs due only to whitespace
+ (c.f: 'diff -wbB')
+ """
Added: CMF/branches/goldegg-phase-1/GenericSetup/permissions.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/permissions.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/permissions.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,18 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" GenericSetup product permissions.
+
+$Id: permissions.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+ManagePortal = 'Manage Site'
Added: CMF/branches/goldegg-phase-1/GenericSetup/properties.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/properties.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/properties.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,97 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Site properties setup handlers.
+
+$Id: properties.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+from AccessControl import ClassSecurityInfo
+from Globals import InitializeClass
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+
+from permissions import ManagePortal
+from utils import _xmldir
+from utils import ConfiguratorBase
+from utils import DEFAULT, KEY
+
+
+#
+# Configurator entry points
+#
+_FILENAME = 'properties.xml'
+
+def importSiteProperties(context):
+ """ Import site properties from an XML file.
+ """
+ site = context.getSite()
+ encoding = context.getEncoding()
+
+ if context.shouldPurge():
+
+ for prop_map in site._propertyMap():
+ prop_id = prop_map['id']
+ if 'd' in prop_map.get('mode', 'wd') and \
+ prop_id not in ('title', 'description'):
+ site._delProperty(prop_id)
+ else:
+ if prop_map.get('type') == 'multiple selection':
+ prop_value = ()
+ else:
+ prop_value = ''
+ site._updateProperty(prop_id, prop_value)
+
+ xml = context.readDataFile(_FILENAME)
+ if xml is None:
+ return 'Site properties: Nothing to import.'
+
+ spc = SitePropertiesConfigurator(site, encoding)
+ site_info = spc.parseXML(xml)
+
+ for prop_info in site_info['properties']:
+ spc.initProperty(site, prop_info)
+
+ return 'Site properties imported.'
+
+def exportSiteProperties(context):
+ """ Export site properties as an XML file.
+ """
+ site = context.getSite()
+ spc = SitePropertiesConfigurator(site).__of__(site)
+
+ xml = spc.generateXML()
+ context.writeDataFile(_FILENAME, xml, 'text/xml')
+
+ return 'Site properties exported.'
+
+
+class SitePropertiesConfigurator(ConfiguratorBase):
+ """ Synthesize XML description of site's properties.
+ """
+ security = ClassSecurityInfo()
+
+ security.declareProtected(ManagePortal, 'listSiteInfos')
+ def listSiteInfos(self):
+ """ Get a sequence of mappings for site properties.
+ """
+ return tuple( [ self._extractProperty(self._site, prop_map)
+ for prop_map in self._site._propertyMap() ] )
+
+ def _getExportTemplate(self):
+
+ return PageTemplateFile('spcExport.xml', _xmldir)
+
+ def _getImportMapping(self):
+
+ return { 'site': { 'property': {KEY: 'properties', DEFAULT: () } } }
+
+InitializeClass(SitePropertiesConfigurator)
Added: CMF/branches/goldegg-phase-1/GenericSetup/registry.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/registry.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/registry.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,754 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Classes: ImportStepRegistry, ExportStepRegistry
+
+$Id: registry.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+from xml.sax import parseString
+
+from AccessControl import ClassSecurityInfo
+from Acquisition import Implicit
+from Globals import InitializeClass
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from zope.interface import implements
+
+from interfaces import BASE
+from interfaces import IImportStepRegistry
+from interfaces import IExportStepRegistry
+from interfaces import IToolsetRegistry
+from interfaces import IProfileRegistry
+from permissions import ManagePortal
+from utils import HandlerBase
+from utils import _xmldir
+from utils import _getDottedName
+from utils import _resolveDottedName
+from utils import _extractDocstring
+
+
+class ImportStepRegistry( Implicit ):
+
+ """ Manage knowledge about steps to create / configure site.
+
+ o Steps are composed together to define a site profile.
+ """
+ implements(IImportStepRegistry)
+
+ security = ClassSecurityInfo()
+
+ def __init__( self ):
+
+ self.clear()
+
+ security.declareProtected( ManagePortal, 'listSteps' )
+ def listSteps( self ):
+
+ """ Return a sequence of IDs of registered steps.
+
+ o Order is not significant.
+ """
+ return self._registered.keys()
+
+ security.declareProtected( ManagePortal, 'sortSteps' )
+ def sortSteps( self ):
+
+ """ Return a sequence of registered step IDs
+
+ o Sequence is sorted topologically by dependency, with the dependent
+ steps *after* the steps they depend on.
+ """
+ return self._computeTopologicalSort()
+
+ security.declareProtected( ManagePortal, 'checkComplete' )
+ def checkComplete( self ):
+
+ """ Return a sequence of ( node, edge ) tuples for unsatisifed deps.
+ """
+ result = []
+ seen = {}
+
+ graph = self._computeTopologicalSort()
+
+ for node in graph:
+
+ dependencies = self.getStepMetadata( node )[ 'dependencies' ]
+
+ for dependency in dependencies:
+
+ if seen.get( dependency ) is None:
+ result.append( ( node, dependency ) )
+
+ seen[ node ] = 1
+
+ return result
+
+ security.declareProtected( ManagePortal, 'getStepMetadata' )
+ def getStepMetadata( self, key, default=None ):
+
+ """ Return a mapping of metadata for the step identified by 'key'.
+
+ o Return 'default' if no such step is registered.
+
+ o The 'handler' metadata is available via 'getStep'.
+ """
+ result = {}
+
+ info = self._registered.get( key )
+
+ if info is None:
+ return default
+
+ return info.copy()
+
+ security.declareProtected( ManagePortal, 'listStepMetadata' )
+ def listStepMetadata( self ):
+
+ """ Return a sequence of mappings describing registered steps.
+
+ o Mappings will be ordered alphabetically.
+ """
+ step_ids = self.listSteps()
+ step_ids.sort()
+ return [ self.getStepMetadata( x ) for x in step_ids ]
+
+ security.declareProtected( ManagePortal, 'generateXML' )
+ def generateXML( self ):
+
+ """ Return a round-trippable XML representation of the registry.
+
+ o 'handler' values are serialized using their dotted names.
+ """
+ return self._exportTemplate()
+
+ security.declarePrivate( 'getStep' )
+ def getStep( self, key, default=None ):
+
+ """ Return the IImportPlugin registered for 'key'.
+
+ o Return 'default' if no such step is registered.
+ """
+ marker = object()
+ info = self._registered.get( key, marker )
+
+ if info is marker:
+ return default
+
+ return _resolveDottedName( info[ 'handler' ] )
+
+ security.declarePrivate( 'registerStep' )
+ def registerStep( self
+ , id
+ , version
+ , handler
+ , dependencies=()
+ , title=None
+ , description=None
+ ):
+ """ Register a setup step.
+
+ o 'id' is a unique name for this step,
+
+ o 'version' is a string for comparing versions, it is preferred to
+ be a yyyy/mm/dd-ii formatted string (date plus two-digit
+ ordinal). when comparing two version strings, the version with
+ the lower sort order is considered the older version.
+
+ - Newer versions of a step supplant older ones.
+
+ - Attempting to register an older one after a newer one results
+ in a KeyError.
+
+ o 'handler' should implement IImportPlugin.
+
+ o 'dependencies' is a tuple of step ids which have to run before
+ this step in order to be able to run at all. Registration of
+ steps that have unmet dependencies are deferred until the
+ dependencies have been registered.
+
+ o 'title' is a one-line UI description for this step.
+ If None, the first line of the documentation string of the handler
+ is used, or the id if no docstring can be found.
+
+ o 'description' is a one-line UI description for this step.
+ If None, the remaining line of the documentation string of
+ the handler is used, or default to ''.
+ """
+ already = self.getStepMetadata( id )
+
+ if already and already[ 'version' ] > version:
+ raise KeyError( 'Existing registration for step %s, version %s'
+ % ( id, already[ 'version' ] ) )
+
+ if title is None or description is None:
+
+ t, d = _extractDocstring( handler, id, '' )
+
+ title = title or t
+ description = description or d
+
+ info = { 'id' : id
+ , 'version' : version
+ , 'handler' : _getDottedName( handler )
+ , 'dependencies' : dependencies
+ , 'title' : title
+ , 'description' : description
+ }
+
+ self._registered[ id ] = info
+
+ security.declarePrivate( 'parseXML' )
+ def parseXML( self, text, encoding=None ):
+
+ """ Parse 'text'.
+ """
+ reader = getattr( text, 'read', None )
+
+ if reader is not None:
+ text = reader()
+
+ parser = _ImportStepRegistryParser( encoding )
+ parseString( text, parser )
+
+ return parser._parsed
+
+ security.declarePrivate( 'clear' )
+ def clear( self ):
+
+ self._registered = {}
+
+ #
+ # Helper methods
+ #
+ security.declarePrivate( '_computeTopologicalSort' )
+ def _computeTopologicalSort( self ):
+
+ result = []
+
+ graph = [ ( x[ 'id' ], x[ 'dependencies' ] )
+ for x in self._registered.values() ]
+
+ for node, edges in graph:
+
+ after = -1
+
+ for edge in edges:
+
+ if edge in result:
+ after = max( after, result.index( edge ) )
+
+ result.insert( after + 1, node )
+
+ return result
+
+ security.declarePrivate( '_exportTemplate' )
+ _exportTemplate = PageTemplateFile( 'isrExport.xml', _xmldir )
+
+InitializeClass( ImportStepRegistry )
+
+
+class ExportStepRegistry( Implicit ):
+
+ """ Registry of known site-configuration export steps.
+
+ o Each step is registered with a unique id.
+
+ o When called, with the portal object passed in as an argument,
+ the step must return a sequence of three-tuples,
+ ( 'data', 'content_type', 'filename' ), one for each file exported
+ by the step.
+
+ - 'data' is a string containing the file data;
+
+ - 'content_type' is the MIME type of the data;
+
+ - 'filename' is a suggested filename for use when downloading.
+
+ """
+ implements(IExportStepRegistry)
+
+ security = ClassSecurityInfo()
+
+ def __init__( self ):
+
+ self.clear()
+
+ security.declareProtected( ManagePortal, 'listSteps' )
+ def listSteps( self ):
+
+ """ Return a list of registered step IDs.
+ """
+ return self._registered.keys()
+
+ security.declareProtected( ManagePortal, 'getStepMetadata' )
+ def getStepMetadata( self, key, default=None ):
+
+ """ Return a mapping of metadata for the step identified by 'key'.
+
+ o Return 'default' if no such step is registered.
+
+ o The 'handler' metadata is available via 'getStep'.
+ """
+ info = self._registered.get( key )
+
+ if info is None:
+ return default
+
+ return info.copy()
+
+ security.declareProtected( ManagePortal, 'listStepMetadata' )
+ def listStepMetadata( self ):
+
+ """ Return a sequence of mappings describing registered steps.
+
+ o Steps will be alphabetical by ID.
+ """
+ step_ids = self.listSteps()
+ step_ids.sort()
+ return [ self.getStepMetadata( x ) for x in step_ids ]
+
+ security.declareProtected( ManagePortal, 'generateXML' )
+ def generateXML( self ):
+
+ """ Return a round-trippable XML representation of the registry.
+
+ o 'handler' values are serialized using their dotted names.
+ """
+ return self._exportTemplate()
+
+ security.declarePrivate( 'getStep' )
+ def getStep( self, key, default=None ):
+
+ """ Return the IExportPlugin registered for 'key'.
+
+ o Return 'default' if no such step is registered.
+ """
+ marker = object()
+ info = self._registered.get( key, marker )
+
+ if info is marker:
+ return default
+
+ return _resolveDottedName( info[ 'handler' ] )
+
+ security.declarePrivate( 'registerStep' )
+ def registerStep( self, id, handler, title=None, description=None ):
+
+ """ Register an export step.
+
+ o 'id' is the unique identifier for this step
+
+ o 'step' should implement IExportPlugin.
+
+ o 'title' is a one-line UI description for this step.
+ If None, the first line of the documentation string of the step
+ is used, or the id if no docstring can be found.
+
+ o 'description' is a one-line UI description for this step.
+ If None, the remaining line of the documentation string of
+ the step is used, or default to ''.
+ """
+ if title is None or description is None:
+
+ t, d = _extractDocstring( handler, id, '' )
+
+ title = title or t
+ description = description or d
+
+ info = { 'id' : id
+ , 'handler' : _getDottedName( handler )
+ , 'title' : title
+ , 'description' : description
+ }
+
+ self._registered[ id ] = info
+
+ security.declarePrivate( 'parseXML' )
+ def parseXML( self, text, encoding=None ):
+
+ """ Parse 'text'.
+ """
+ reader = getattr( text, 'read', None )
+
+ if reader is not None:
+ text = reader()
+
+ parser = _ExportStepRegistryParser( encoding )
+ parseString( text, parser )
+
+ return parser._parsed
+
+ security.declarePrivate( 'clear' )
+ def clear( self ):
+
+ self._registered = {}
+
+ #
+ # Helper methods
+ #
+ security.declarePrivate( '_exportTemplate' )
+ _exportTemplate = PageTemplateFile( 'esrExport.xml', _xmldir )
+
+InitializeClass( ExportStepRegistry )
+
+class ToolsetRegistry( Implicit ):
+
+ """ Track required / forbidden tools.
+ """
+ implements(IToolsetRegistry)
+
+ security = ClassSecurityInfo()
+ security.setDefaultAccess( 'allow' )
+
+ def __init__( self ):
+
+ self.clear()
+
+ #
+ # Toolset API
+ #
+ security.declareProtected( ManagePortal, 'listForbiddenTools' )
+ def listForbiddenTools( self ):
+
+ """ See IToolsetRegistry.
+ """
+ result = list( self._forbidden )
+ result.sort()
+ return result
+
+ security.declareProtected( ManagePortal, 'addForbiddenTool' )
+ def addForbiddenTool( self, tool_id ):
+
+ """ See IToolsetRegistry.
+ """
+ if tool_id in self._forbidden:
+ return
+
+ if self._required.get( tool_id ) is not None:
+ raise ValueError, 'Tool %s is required!' % tool_id
+
+ self._forbidden.append( tool_id )
+
+ security.declareProtected( ManagePortal, 'listRequiredTools' )
+ def listRequiredTools( self ):
+
+ """ See IToolsetRegistry.
+ """
+ result = list( self._required.keys() )
+ result.sort()
+ return result
+
+ security.declareProtected( ManagePortal, 'getRequiredToolInfo' )
+ def getRequiredToolInfo( self, tool_id ):
+
+ """ See IToolsetRegistry.
+ """
+ return self._required[ tool_id ]
+
+ security.declareProtected( ManagePortal, 'listRequiredToolInfo' )
+ def listRequiredToolInfo( self ):
+
+ """ See IToolsetRegistry.
+ """
+ return [ self.getRequiredToolInfo( x )
+ for x in self.listRequiredTools() ]
+
+ security.declareProtected( ManagePortal, 'addRequiredTool' )
+ def addRequiredTool( self, tool_id, dotted_name ):
+
+ """ See IToolsetRegistry.
+ """
+ if tool_id in self._forbidden:
+ raise ValueError, "Forbidden tool ID: %s" % tool_id
+
+ self._required[ tool_id ] = { 'id' : tool_id
+ , 'class' : dotted_name
+ }
+
+ security.declareProtected( ManagePortal, 'generateXML' )
+ def generateXML( self ):
+
+ """ Pseudo API.
+ """
+ return self._toolsetConfig()
+
+ security.declareProtected( ManagePortal, 'parseXML' )
+ def parseXML( self, text, encoding=None ):
+
+ """ Pseudo-API
+ """
+ reader = getattr( text, 'read', None )
+
+ if reader is not None:
+ text = reader()
+
+ parser = _ToolsetParser( encoding )
+ parseString( text, parser )
+
+ for tool_id in parser._forbidden:
+ self.addForbiddenTool( tool_id )
+
+ for tool_id, dotted_name in parser._required.items():
+ self.addRequiredTool( tool_id, dotted_name )
+
+ security.declarePrivate( 'clear' )
+ def clear( self ):
+
+ self._forbidden = []
+ self._required = {}
+
+ #
+ # Helper methods.
+ #
+ security.declarePrivate( '_toolsetConfig' )
+ _toolsetConfig = PageTemplateFile( 'tscExport.xml'
+ , _xmldir
+ , __name__='toolsetConfig'
+ )
+
+InitializeClass( ToolsetRegistry )
+
+class ProfileRegistry( Implicit ):
+
+ """ Track registered profiles.
+ """
+ implements(IProfileRegistry)
+
+ security = ClassSecurityInfo()
+ security.setDefaultAccess( 'allow' )
+
+ def __init__( self ):
+
+ self.clear()
+
+ security.declareProtected( ManagePortal, '' )
+ def getProfileInfo( self, profile_id ):
+
+ """ See IProfileRegistry.
+ """
+ result = self._profile_info[ profile_id ]
+ return result.copy()
+
+ security.declareProtected( ManagePortal, 'listProfiles' )
+ def listProfiles( self ):
+
+ """ See IProfileRegistry.
+ """
+ return tuple( self._profile_ids )
+
+ security.declareProtected( ManagePortal, 'listProfileInfo' )
+ def listProfileInfo( self ):
+
+ """ See IProfileRegistry.
+ """
+ return [ self.getProfileInfo( id ) for id in self.listProfiles() ]
+
+ security.declareProtected( ManagePortal, 'registerProfile' )
+ def registerProfile( self
+ , name
+ , title
+ , description
+ , path
+ , product=None
+ , profile_type=BASE
+ ):
+ """ See IProfileRegistry.
+ """
+ profile_id = '%s:%s' % (product or 'other', name)
+ if self._profile_info.get( profile_id ) is not None:
+ raise KeyError, 'Duplicate profile ID: %s' % profile_id
+
+ self._profile_ids.append( profile_id )
+
+ info = { 'id' : profile_id
+ , 'title' : title
+ , 'description' : description
+ , 'path' : path
+ , 'product' : product
+ , 'type': profile_type
+ }
+
+ self._profile_info[ profile_id ] = info
+
+ security.declarePrivate( 'clear' )
+ def clear( self ):
+
+ self._profile_info = {}
+ self._profile_ids = []
+
+InitializeClass( ProfileRegistry )
+
+_profile_registry = ProfileRegistry()
+
+class _ImportStepRegistryParser( HandlerBase ):
+
+ security = ClassSecurityInfo()
+ security.declareObjectPrivate()
+ security.setDefaultAccess( 'deny' )
+
+ def __init__( self, encoding ):
+
+ self._encoding = encoding
+ self._started = False
+ self._pending = None
+ self._parsed = []
+
+ def startElement( self, name, attrs ):
+
+ if name == 'import-steps':
+
+ if self._started:
+ raise ValueError, 'Duplicated setup-steps element: %s' % name
+
+ self._started = True
+
+ elif name == 'import-step':
+
+ if self._pending is not None:
+ raise ValueError, 'Cannot nest setup-step elements'
+
+ self._pending = dict( [ ( k, self._extract( attrs, k ) )
+ for k in attrs.keys() ] )
+
+ self._pending[ 'dependencies' ] = []
+
+ elif name == 'dependency':
+
+ if not self._pending:
+ raise ValueError, 'Dependency outside of step'
+
+ depended = self._extract( attrs, 'step' )
+ self._pending[ 'dependencies' ].append( depended )
+
+ else:
+ raise ValueError, 'Unknown element %s' % name
+
+ def characters( self, content ):
+
+ if self._pending is not None:
+ content = self._encode( content )
+ self._pending.setdefault( 'description', [] ).append( content )
+
+ def endElement(self, name):
+
+ if name == 'import-steps':
+ pass
+
+ elif name == 'import-step':
+
+ if self._pending is None:
+ raise ValueError, 'No pending step!'
+
+ deps = tuple( self._pending[ 'dependencies' ] )
+ self._pending[ 'dependencies' ] = deps
+
+ desc = ''.join( self._pending[ 'description' ] )
+ self._pending[ 'description' ] = desc
+
+ self._parsed.append( self._pending )
+ self._pending = None
+
+InitializeClass( _ImportStepRegistryParser )
+
+class _ExportStepRegistryParser( HandlerBase ):
+
+ security = ClassSecurityInfo()
+ security.declareObjectPrivate()
+ security.setDefaultAccess( 'deny' )
+
+ def __init__( self, encoding ):
+
+ self._encoding = encoding
+ self._started = False
+ self._pending = None
+ self._parsed = []
+
+ def startElement( self, name, attrs ):
+
+ if name == 'export-steps':
+
+ if self._started:
+ raise ValueError, 'Duplicated export-steps element: %s' % name
+
+ self._started = True
+
+ elif name == 'export-step':
+
+ if self._pending is not None:
+ raise ValueError, 'Cannot nest export-step elements'
+
+ self._pending = dict( [ ( k, self._extract( attrs, k ) )
+ for k in attrs.keys() ] )
+
+ else:
+ raise ValueError, 'Unknown element %s' % name
+
+ def characters( self, content ):
+
+ if self._pending is not None:
+ content = self._encode( content )
+ self._pending.setdefault( 'description', [] ).append( content )
+
+ def endElement(self, name):
+
+ if name == 'export-steps':
+ pass
+
+ elif name == 'export-step':
+
+ if self._pending is None:
+ raise ValueError, 'No pending step!'
+
+ desc = ''.join( self._pending[ 'description' ] )
+ self._pending[ 'description' ] = desc
+
+ self._parsed.append( self._pending )
+ self._pending = None
+
+InitializeClass( _ExportStepRegistryParser )
+
+
+class _ToolsetParser( HandlerBase ):
+
+ security = ClassSecurityInfo()
+ security.declareObjectPrivate()
+ security.setDefaultAccess( 'deny' )
+
+ def __init__( self, encoding ):
+
+ self._encoding = encoding
+ self._required = {}
+ self._forbidden = []
+
+ def startElement( self, name, attrs ):
+
+ if name == 'tool-setup':
+ pass
+
+ elif name == 'forbidden':
+
+ tool_id = self._extract( attrs, 'tool_id' )
+
+ if tool_id not in self._forbidden:
+ self._forbidden.append( tool_id )
+
+ elif name == 'required':
+
+ tool_id = self._extract( attrs, 'tool_id' )
+ dotted_name = self._extract( attrs, 'class' )
+ self._required[ tool_id ] = dotted_name
+
+ else:
+ raise ValueError, 'Unknown element %s' % name
+
+
+InitializeClass( _ToolsetParser )
Added: CMF/branches/goldegg-phase-1/GenericSetup/rolemap.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/rolemap.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/rolemap.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,212 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" GenericSetup: Role-permission export / import
+
+$Id: rolemap.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+from AccessControl import ClassSecurityInfo
+from AccessControl.Permission import Permission
+from Globals import InitializeClass
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+
+from permissions import ManagePortal
+from utils import _xmldir
+from utils import ConfiguratorBase
+from utils import CONVERTER, DEFAULT, KEY
+
+
+#
+# Configurator entry points
+#
+_FILENAME = 'rolemap.xml'
+
+def importRolemap( context ):
+
+ """ Import roles / permission map from an XML file.
+
+ o 'context' must implement IImportContext.
+
+ o Register via Python:
+
+ registry = site.setup_tool.setup_steps
+ registry.registerStep( 'importRolemap'
+ , '20040518-01'
+ , Products.GenericSetup.rolemap.importRolemap
+ , ()
+ , 'Role / Permission import'
+ , 'Import additional roles, and map '
+ 'roles to permissions'
+ )
+
+ o Register via XML:
+
+ <setup-step id="importRolemap"
+ version="20040518-01"
+ handler="Products.GenericSetup.rolemap.importRolemap"
+ title="Role / Permission import"
+ >Import additional roles, and map roles to permissions.</setup-step>
+
+ """
+ site = context.getSite()
+ encoding = context.getEncoding()
+
+ if context.shouldPurge():
+
+ items = site.__dict__.items()
+
+ for k, v in items: # XXX: WAAA
+
+ if k == '__ac_roles__':
+ delattr( site, k )
+
+ if k.startswith( '_' ) and k.endswith( '_Permission' ):
+ delattr( site, k )
+
+ text = context.readDataFile( _FILENAME )
+
+ if text is not None:
+
+ rc = RolemapConfigurator( site, encoding )
+ rolemap_info = rc.parseXML( text )
+
+ immediate_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
+ already = {}
+
+ for role in site.valid_roles():
+ already[ role ] = 1
+
+ for role in rolemap_info[ 'roles' ]:
+
+ if already.get( role ) is None:
+ immediate_roles.append( role )
+ already[ role ] = 1
+
+ immediate_roles.sort()
+ site.__ac_roles__ = tuple( immediate_roles )
+
+ for permission in rolemap_info[ 'permissions' ]:
+
+ site.manage_permission( permission[ 'name' ]
+ , permission[ 'roles' ]
+ , permission[ 'acquire' ]
+ )
+
+ return 'Role / permission map imported.'
+
+
+def exportRolemap( context ):
+
+ """ Export roles / permission map as an XML file
+
+ o 'context' must implement IExportContext.
+
+ o Register via Python:
+
+ registry = site.setup_tool.export_steps
+ registry.registerStep( 'exportRolemap'
+ , Products.GenericSetup.rolemap.exportRolemap
+ , 'Role / Permission export'
+ , 'Export additional roles, and '
+ 'role / permission map '
+ )
+
+ o Register via XML:
+
+ <export-script id="exportRolemap"
+ version="20040518-01"
+ handler="Products.GenericSetup.rolemap.exportRolemap"
+ title="Role / Permission export"
+ >Export additional roles, and role / permission map.</export-script>
+
+ """
+ site = context.getSite()
+ rc = RolemapConfigurator( site ).__of__( site )
+ text = rc.generateXML()
+
+ context.writeDataFile( _FILENAME, text, 'text/xml' )
+
+ return 'Role / permission map exported.'
+
+
+class RolemapConfigurator(ConfiguratorBase):
+ """ Synthesize XML description of sitewide role-permission settings.
+ """
+ security = ClassSecurityInfo()
+
+ security.declareProtected( ManagePortal, 'listRoles' )
+ def listRoles( self ):
+
+ """ List the valid role IDs for our site.
+ """
+ return self._site.valid_roles()
+
+ security.declareProtected( ManagePortal, 'listPermissions' )
+ def listPermissions( self ):
+
+ """ List permissions for export.
+
+ o Returns a sqeuence of mappings describing locally-modified
+ permission / role settings. Keys include:
+
+ 'permission' -- the name of the permission
+
+ 'acquire' -- a flag indicating whether to acquire roles from the
+ site's container
+
+ 'roles' -- the list of roles which have the permission.
+
+ o Do not include permissions which both acquire and which define
+ no local changes to the acquired policy.
+ """
+ permissions = []
+ valid_roles = self.listRoles()
+
+ for perm in self._site.ac_inherited_permissions( 1 ):
+
+ name = perm[ 0 ]
+ p = Permission( name, perm[ 1 ], self._site )
+ roles = p.getRoles( default=[] )
+ acquire = isinstance( roles, list ) # tuple means don't acquire
+ roles = [ r for r in roles if r in valid_roles ]
+
+ if roles or not acquire:
+ permissions.append( { 'name' : name
+ , 'acquire' : acquire
+ , 'roles' : roles
+ } )
+
+ return permissions
+
+ def _getExportTemplate(self):
+
+ return PageTemplateFile('rmeExport.xml', _xmldir)
+
+ def _getImportMapping(self):
+
+ return {
+ 'rolemap':
+ { 'roles': {CONVERTER: self._convertToUnique},
+ 'permissions': {CONVERTER: self._convertToUnique} },
+ 'roles':
+ { 'role': {KEY: None} },
+ 'role':
+ { 'name': {KEY: None} },
+ 'permissions':
+ { 'permission': {KEY: None, DEFAULT: ()} },
+ 'permission':
+ { 'name': {},
+ 'role': {KEY: 'roles'},
+ 'acquire': {CONVERTER: self._convertToBoolean} } }
+
+InitializeClass(RolemapConfigurator)
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/__init__.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tests/__init__.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tests/__init__.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,16 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" GenericSetup product unit tests.
+
+$Id: __init__.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/common.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tests/common.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tests/common.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,218 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" GenericSetup product: unit test utilities.
+
+$Id: common.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+import os
+import shutil
+from tarfile import TarFile
+
+from Acquisition import Implicit
+from Testing.ZopeTestCase import ZopeTestCase
+
+class OmnipotentUser(Implicit):
+ """ Omnipotent User for unit testing purposes.
+ """
+ def getId(self):
+ return 'all_powerful_Oz'
+
+ getUserName = getId
+
+ def getRoles(self):
+ return ('Manager',)
+
+ def allowed(self, object, object_roles=None):
+ return 1
+
+ def getRolesInContext(self, object):
+ return ('Manager',)
+
+class SecurityRequestTest(ZopeTestCase):
+ def setUp(self):
+ from AccessControl.SecurityManagement import newSecurityManager
+ ZopeTestCase.setUp(self)
+ self.root = self.app
+ newSecurityManager(None, OmnipotentUser().__of__(self.app.acl_users))
+
+ def tearDown(self):
+ from AccessControl.SecurityManagement import noSecurityManager
+ noSecurityManager()
+ ZopeTestCase.tearDown(self)
+
+class DOMComparator:
+
+ def _compareDOM( self, found_text, expected_text, debug=False ):
+
+ found_lines = [ x.strip() for x in found_text.splitlines() ]
+ found_text = '\n'.join( filter( None, found_lines ) )
+
+ expected_lines = [ x.strip() for x in expected_text.splitlines() ]
+ expected_text = '\n'.join( filter( None, expected_lines ) )
+
+ from xml.dom.minidom import parseString
+ found = parseString( found_text )
+ expected = parseString( expected_text )
+ fxml = found.toxml()
+ exml = expected.toxml()
+
+ if fxml != exml:
+
+ if debug:
+ zipped = zip( fxml, exml )
+ diff = [ ( i, zipped[i][0], zipped[i][1] )
+ for i in range( len( zipped ) )
+ if zipped[i][0] != zipped[i][1]
+ ]
+ import pdb; pdb.set_trace()
+
+ print 'Found:'
+ print fxml
+ print
+ print 'Expected:'
+ print exml
+ print
+
+ self.assertEqual( found.toxml(), expected.toxml() )
+
+class BaseRegistryTests( SecurityRequestTest, DOMComparator ):
+
+ def _makeOne( self, *args, **kw ):
+
+ # Derived classes must implement _getTargetClass
+ return self._getTargetClass()( *args, **kw )
+
+def _clearTestDirectory( root_path ):
+
+ if os.path.exists( root_path ):
+ shutil.rmtree( root_path )
+
+def _makeTestFile( filename, root_path, contents ):
+
+ path, filename = os.path.split( filename )
+
+ subdir = os.path.join( root_path, path )
+
+ if not os.path.exists( subdir ):
+ os.makedirs( subdir )
+
+ fqpath = os.path.join( subdir, filename )
+
+ file = open( fqpath, 'wb' )
+ file.write( contents )
+ file.close()
+ return fqpath
+
+class FilesystemTestBase( SecurityRequestTest ):
+
+ def _makeOne( self, *args, **kw ):
+
+ return self._getTargetClass()( *args, **kw )
+
+ def setUp( self ):
+
+ SecurityRequestTest.setUp( self )
+ self._clearTempDir()
+
+ def tearDown( self ):
+
+ self._clearTempDir()
+ SecurityRequestTest.tearDown( self )
+
+ def _clearTempDir( self ):
+
+ _clearTestDirectory( self._PROFILE_PATH )
+
+ def _makeFile( self, filename, contents ):
+
+ return _makeTestFile( filename, self._PROFILE_PATH, contents )
+
+
+class TarballTester( DOMComparator ):
+
+ def _verifyTarballContents( self, fileish, toc_list, when=None ):
+
+ fileish.seek( 0L )
+ tarfile = TarFile.open( 'foo.tar.gz', fileobj=fileish, mode='r:gz' )
+ items = tarfile.getnames()
+ items.sort()
+ toc_list.sort()
+
+ self.assertEqual( len( items ), len( toc_list ) )
+ for i in range( len( items ) ):
+ self.assertEqual( items[ i ], toc_list[ i ] )
+
+ if when is not None:
+ for tarinfo in tarfile:
+ self.failIf( tarinfo.mtime < when )
+
+ def _verifyTarballEntry( self, fileish, entry_name, data ):
+
+ fileish.seek( 0L )
+ tarfile = TarFile.open( 'foo.tar.gz', fileobj=fileish, mode='r:gz' )
+ extract = tarfile.extractfile( entry_name )
+ found = extract.read()
+ self.assertEqual( found, data )
+
+ def _verifyTarballEntryXML( self, fileish, entry_name, data ):
+
+ fileish.seek( 0L )
+ tarfile = TarFile.open( 'foo.tar.gz', fileobj=fileish, mode='r:gz' )
+ extract = tarfile.extractfile( entry_name )
+ found = extract.read()
+ self._compareDOM( found, data )
+
+
+class DummyExportContext:
+
+ def __init__( self, site ):
+ self._site = site
+ self._wrote = []
+
+ def getSite( self ):
+ return self._site
+
+ def writeDataFile( self, filename, text, content_type, subdir=None ):
+ if subdir is not None:
+ filename = '%s/%s' % ( subdir, filename )
+ self._wrote.append( ( filename, text, content_type ) )
+
+class DummyImportContext:
+
+ def __init__( self, site, purge=True, encoding=None ):
+ self._site = site
+ self._purge = purge
+ self._encoding = encoding
+ self._files = {}
+
+ def getSite( self ):
+ return self._site
+
+ def getEncoding( self ):
+ return self._encoding
+
+ def readDataFile( self, filename, subdir=None ):
+
+ if subdir is not None:
+ filename = '/'.join( (subdir, filename) )
+
+ return self._files.get( filename )
+
+ def shouldPurge( self ):
+
+ return self._purge
+
+def dummy_handler( context ):
+
+ pass
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/conformance.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tests/conformance.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tests/conformance.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,100 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Base classes for testing interface conformance.
+
+Derived testcase classes should define '_getTargetClass()', which must
+return the class being tested for conformance.
+
+$Id: conformance.py,v 1.2 2005/08/09 18:49:48 tseaver Exp $
+"""
+
+class ConformsToISetupContext:
+
+ def test_ISetupContext_conformance( self ):
+
+ from Products.GenericSetup.interfaces import ISetupContext
+ from zope.interface.verify import verifyClass
+
+ verifyClass( ISetupContext, self._getTargetClass() )
+
+class ConformsToIImportContext:
+
+ def test_IImportContext_conformance( self ):
+
+ from Products.GenericSetup.interfaces import IImportContext
+ from zope.interface.verify import verifyClass
+
+ verifyClass( IImportContext, self._getTargetClass() )
+
+class ConformsToIExportContext:
+
+ def test_IExportContext_conformance( self ):
+
+ from Products.GenericSetup.interfaces import IExportContext
+ from zope.interface.verify import verifyClass
+
+ verifyClass( IExportContext, self._getTargetClass() )
+
+class ConformsToIStepRegistry:
+
+ def test_IStepRegistry_conformance( self ):
+
+ from Products.GenericSetup.interfaces import IStepRegistry
+ from zope.interface.verify import verifyClass
+
+ verifyClass( IStepRegistry, self._getTargetClass() )
+
+class ConformsToIImportStepRegistry:
+
+ def test_IImportStepRegistry_conformance( self ):
+
+ from Products.GenericSetup.interfaces import IImportStepRegistry
+ from zope.interface.verify import verifyClass
+
+ verifyClass( IImportStepRegistry, self._getTargetClass() )
+
+class ConformsToIExportStepRegistry:
+
+ def test_IExportStepRegistry_conformance( self ):
+
+ from Products.GenericSetup.interfaces import IExportStepRegistry
+ from zope.interface.verify import verifyClass
+
+ verifyClass( IExportStepRegistry, self._getTargetClass() )
+
+class ConformsToIToolsetRegistry:
+
+ def test_IToolsetRegistry_conformance( self ):
+
+ from Products.GenericSetup.interfaces import IToolsetRegistry
+ from zope.interface.verify import verifyClass
+
+ verifyClass( IToolsetRegistry, self._getTargetClass() )
+
+class ConformsToIProfileRegistry:
+
+ def test_IProfileRegistry_conformance( self ):
+
+ from Products.GenericSetup.interfaces import IProfileRegistry
+ from zope.interface.verify import verifyClass
+
+ verifyClass( IProfileRegistry, self._getTargetClass() )
+
+class ConformsToISetupTool:
+
+ def test_ISetupTool_conformance( self ):
+
+ from Products.GenericSetup.interfaces import ISetupTool
+ from zope.interface.verify import verifyClass
+
+ verifyClass( ISetupTool, self._getTargetClass() )
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/export_steps.xml
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/export_steps.xml 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/export_steps.xml 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<export-steps>
+ <export-step id="one"
+ handler="Products.GenericSetup.tests.common.dummy_handler"
+ title="One Step">
+ One small step
+ </export-step>
+</export-steps>
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/import_steps.xml
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/import_steps.xml 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/import_steps.xml 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<import-steps>
+ <import-step id="one"
+ version="1"
+ handler="Products.GenericSetup.tests.common.dummy_handler"
+ title="One Step">
+ One small step
+ </import-step>
+</import-steps>
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/profile.ini
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/profile.ini 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/profile.ini 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,2 @@
+[Metadata]
+Title=Unit Test Profile Data
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/toolset.xml
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/toolset.xml 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tests/default_profile/toolset.xml 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<tool-setup>
+ <forbidden tool_id="doomed" />
+ <required tool_id="mandatory" class="path.to.one" />
+ <required tool_id="obligatory" class="path.to.another" />
+</tool-setup>
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/four/placeholder.txt
===================================================================
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/one/placeholder.txt
===================================================================
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/simple.png
===================================================================
(Binary files differ)
Property changes on: CMF/branches/goldegg-phase-1/GenericSetup/tests/simple.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/test_context.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tests/test_context.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tests/test_context.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,1289 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Unit tests for import / export contexts.
+
+$Id: test_context.py,v 1.2 2005/08/11 21:41:36 tseaver Exp $
+"""
+
+import unittest
+import Testing
+try:
+ import Zope2
+except ImportError: # BBB: for Zope 2.7
+ import Zope as Zope2
+Zope2.startup()
+
+import os
+import time
+from StringIO import StringIO
+from tarfile import TarFile
+from tarfile import TarInfo
+
+from DateTime.DateTime import DateTime
+from OFS.Folder import Folder
+from OFS.Image import File
+
+#from Products.CMFCore.tests.base.testcase import SecurityRequestTest
+from Testing.ZopeTestCase import ZopeTestCase
+
+from common import FilesystemTestBase
+from common import SecurityRequestTest
+from common import TarballTester
+from common import _makeTestFile
+from conformance import ConformsToISetupContext
+from conformance import ConformsToIImportContext
+from conformance import ConformsToIExportContext
+
+
+class DummySite( Folder ):
+
+ pass
+
+class DummyTool( Folder ):
+
+ pass
+
+class DirectoryImportContextTests( FilesystemTestBase
+ , ConformsToISetupContext
+ , ConformsToIImportContext
+ ):
+
+ _PROFILE_PATH = '/tmp/ICTTexts'
+
+ def _getTargetClass( self ):
+
+ from Products.GenericSetup.context import DirectoryImportContext
+ return DirectoryImportContext
+
+ def test_readDataFile_nonesuch( self ):
+
+ FILENAME = 'nonesuch.txt'
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ self.assertEqual( ctx.readDataFile( FILENAME ), None )
+
+ def test_readDataFile_simple( self ):
+
+ from string import printable
+
+ FILENAME = 'simple.txt'
+ self._makeFile( FILENAME, printable )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ self.assertEqual( ctx.readDataFile( FILENAME ), printable )
+
+ def test_readDataFile_subdir( self ):
+
+ from string import printable
+
+ FILENAME = 'subdir/nested.txt'
+ self._makeFile( FILENAME, printable )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ self.assertEqual( ctx.readDataFile( FILENAME ), printable )
+
+ def test_getLastModified_nonesuch( self ):
+
+ FILENAME = 'nonesuch.txt'
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ self.assertEqual( ctx.getLastModified( FILENAME ), None )
+
+ def test_getLastModified_simple( self ):
+
+ from string import printable
+
+ FILENAME = 'simple.txt'
+ fqpath = self._makeFile( FILENAME, printable )
+ timestamp = os.path.getmtime( fqpath )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ lm = ctx.getLastModified( FILENAME )
+ self.failUnless( isinstance( lm, DateTime ) )
+ self.assertEqual( lm, timestamp )
+
+ def test_getLastModified_subdir( self ):
+
+ from string import printable
+
+ SUBDIR = 'subdir'
+ FILENAME = os.path.join( SUBDIR, 'nested.txt' )
+ fqpath = self._makeFile( FILENAME, printable )
+ timestamp = os.path.getmtime( fqpath )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ lm = ctx.getLastModified( FILENAME )
+ self.failUnless( isinstance( lm, DateTime ) )
+ self.assertEqual( lm, timestamp )
+
+ def test_getLastModified_directory( self ):
+
+ from string import printable
+
+ SUBDIR = 'subdir'
+ FILENAME = os.path.join( SUBDIR, 'nested.txt' )
+ fqpath = self._makeFile( FILENAME, printable )
+ path, file = os.path.split( fqpath )
+ timestamp = os.path.getmtime( path )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ lm = ctx.getLastModified( SUBDIR )
+ self.failUnless( isinstance( lm, DateTime ) )
+ self.assertEqual( lm, timestamp )
+
+ def test_isDirectory_nonesuch( self ):
+
+ FILENAME = 'nonesuch.txt'
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ self.assertEqual( ctx.isDirectory( FILENAME ), None )
+
+ def test_isDirectory_simple( self ):
+
+ from string import printable
+
+ FILENAME = 'simple.txt'
+ fqpath = self._makeFile( FILENAME, printable )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ self.assertEqual( ctx.isDirectory( FILENAME ), False )
+
+ def test_isDirectory_nested( self ):
+
+ from string import printable
+
+ SUBDIR = 'subdir'
+ FILENAME = os.path.join( SUBDIR, 'nested.txt' )
+ fqpath = self._makeFile( FILENAME, printable )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ self.assertEqual( ctx.isDirectory( FILENAME ), False )
+
+ def test_isDirectory_directory( self ):
+
+ from string import printable
+
+ SUBDIR = 'subdir'
+ FILENAME = os.path.join( SUBDIR, 'nested.txt' )
+ fqpath = self._makeFile( FILENAME, printable )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ self.assertEqual( ctx.isDirectory( SUBDIR ), True )
+
+ def test_listDirectory_nonesuch( self ):
+
+ FILENAME = 'nonesuch.txt'
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ self.assertEqual( ctx.listDirectory( FILENAME ), None )
+
+ def test_listDirectory_root( self ):
+
+ from string import printable
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ FILENAME = 'simple.txt'
+ self._makeFile( FILENAME, printable )
+
+ self.assertEqual( len( ctx.listDirectory( None ) ), 1 )
+ self.failUnless( FILENAME in ctx.listDirectory( None ) )
+
+ def test_listDirectory_simple( self ):
+
+ from string import printable
+
+ FILENAME = 'simple.txt'
+ self._makeFile( FILENAME, printable )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ self.assertEqual( ctx.listDirectory( FILENAME ), None )
+
+ def test_listDirectory_nested( self ):
+
+ from string import printable
+
+ SUBDIR = 'subdir'
+ FILENAME = os.path.join( SUBDIR, 'nested.txt' )
+ self._makeFile( FILENAME, printable )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ self.assertEqual( ctx.listDirectory( FILENAME ), None )
+
+ def test_listDirectory_single( self ):
+
+ from string import printable
+
+ SUBDIR = 'subdir'
+ FILENAME = os.path.join( SUBDIR, 'nested.txt' )
+ self._makeFile( FILENAME, printable )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ names = ctx.listDirectory( SUBDIR )
+ self.assertEqual( len( names ), 1 )
+ self.failUnless( 'nested.txt' in names )
+
+ def test_listDirectory_multiple( self ):
+
+ from string import printable
+ SUBDIR = 'subdir'
+ FILENAME = os.path.join( SUBDIR, 'nested.txt' )
+ self._makeFile( FILENAME, printable )
+ self._makeFile( os.path.join( SUBDIR, 'another.txt' ), 'ABC' )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ names = ctx.listDirectory( SUBDIR )
+ self.assertEqual( len( names ), 2 )
+ self.failUnless( 'nested.txt' in names )
+ self.failUnless( 'another.txt' in names )
+
+ def test_listDirectory_skip_implicit( self ):
+
+ from string import printable
+ SUBDIR = 'subdir'
+ FILENAME = os.path.join( SUBDIR, 'nested.txt' )
+ self._makeFile( FILENAME, printable )
+ self._makeFile( os.path.join( SUBDIR, 'another.txt' ), 'ABC' )
+ self._makeFile( os.path.join( SUBDIR, 'CVS/skip.txt' ), 'DEF' )
+ self._makeFile( os.path.join( SUBDIR, '.svn/skip.txt' ), 'GHI' )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ names = ctx.listDirectory( SUBDIR )
+ self.assertEqual( len( names ), 2 )
+ self.failUnless( 'nested.txt' in names )
+ self.failUnless( 'another.txt' in names )
+ self.failIf( 'CVS' in names )
+ self.failIf( '.svn' in names )
+
+ def test_listDirectory_skip_explicit( self ):
+
+ from string import printable
+ SUBDIR = 'subdir'
+ FILENAME = os.path.join( SUBDIR, 'nested.txt' )
+ self._makeFile( FILENAME, printable )
+ self._makeFile( os.path.join( SUBDIR, 'another.txt' ), 'ABC' )
+ self._makeFile( os.path.join( SUBDIR, 'CVS/skip.txt' ), 'DEF' )
+ self._makeFile( os.path.join( SUBDIR, '.svn/skip.txt' ), 'GHI' )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ names = ctx.listDirectory( SUBDIR, ( 'nested.txt', ) )
+ self.assertEqual( len( names ), 3 )
+ self.failIf( 'nested.txt' in names )
+ self.failUnless( 'another.txt' in names )
+ self.failUnless( 'CVS' in names )
+ self.failUnless( '.svn' in names )
+
+class DirectoryExportContextTests( FilesystemTestBase
+ , ConformsToISetupContext
+ , ConformsToIExportContext
+ ):
+
+ _PROFILE_PATH = '/tmp/ECTTexts'
+
+ def _getTargetClass( self ):
+
+ from Products.GenericSetup.context import DirectoryExportContext
+ return DirectoryExportContext
+
+ def test_writeDataFile_simple( self ):
+
+ from string import printable, digits
+ FILENAME = 'simple.txt'
+ fqname = self._makeFile( FILENAME, printable )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ ctx.writeDataFile( FILENAME, digits, 'text/plain' )
+
+ self.assertEqual( open( fqname, 'rb' ).read(), digits )
+
+ def test_writeDataFile_new_subdir( self ):
+
+ from string import printable, digits
+ SUBDIR = 'subdir'
+ FILENAME = 'nested.txt'
+ fqname = os.path.join( self._PROFILE_PATH, SUBDIR, FILENAME )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ ctx.writeDataFile( FILENAME, digits, 'text/plain', SUBDIR )
+
+ self.assertEqual( open( fqname, 'rb' ).read(), digits )
+
+ def test_writeDataFile_overwrite( self ):
+
+ from string import printable, digits
+ SUBDIR = 'subdir'
+ FILENAME = 'nested.txt'
+ fqname = self._makeFile( os.path.join( SUBDIR, FILENAME )
+ , printable )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ ctx.writeDataFile( FILENAME, digits, 'text/plain', SUBDIR )
+
+ self.assertEqual( open( fqname, 'rb' ).read(), digits )
+
+ def test_writeDataFile_existing_subdir( self ):
+
+ from string import printable, digits
+ SUBDIR = 'subdir'
+ FILENAME = 'nested.txt'
+ self._makeFile( os.path.join( SUBDIR, 'another.txt' ), printable )
+ fqname = os.path.join( self._PROFILE_PATH, SUBDIR, FILENAME )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._makeOne( site, self._PROFILE_PATH )
+
+ ctx.writeDataFile( FILENAME, digits, 'text/plain', SUBDIR )
+
+ self.assertEqual( open( fqname, 'rb' ).read(), digits )
+
+
+class TarballImportContextTests( SecurityRequestTest
+ , ConformsToISetupContext
+ , ConformsToIImportContext
+ ):
+
+ def _getTargetClass( self ):
+
+ from Products.GenericSetup.context import TarballImportContext
+ return TarballImportContext
+
+ def _makeOne( self, file_dict={}, mod_time=None, *args, **kw ):
+
+ archive_stream = StringIO()
+ archive = TarFile.open('test.tar.gz', 'w:gz', archive_stream)
+
+ def _addOneMember(path, data, modtime):
+ stream = StringIO(v)
+ info = TarInfo(k)
+ info.size = len(v)
+ info.mtime = mod_time
+ archive.addfile(info, stream)
+
+ def _addMember(path, data, modtime):
+ from tarfile import DIRTYPE
+ elements = path.split('/')
+ parents = filter(None, [elements[x] for x in range(len(elements))])
+ for parent in parents:
+ info = TarInfo()
+ info.name = parent
+ info.size = 0
+ info.mtime = mod_time
+ info.type = DIRTYPE
+ archive.addfile(info, StringIO())
+ _addOneMember(path, data, modtime)
+
+ file_items = file_dict.items() or [('dummy', '')] # empty archive barfs
+
+ if mod_time is None:
+ mod_time = time.time()
+
+ for k, v in file_items:
+ _addMember(k, v, mod_time)
+
+ archive.close()
+ bits = archive_stream.getvalue()
+
+ site = DummySite( 'site' ).__of__( self.root )
+ site._setObject( 'setup_tool', Folder( 'setup_tool' ) )
+ tool = site._getOb( 'setup_tool' )
+
+ ctx = self._getTargetClass()( tool, bits, *args, **kw )
+
+ return site, tool, ctx.__of__( tool )
+
+ def test_ctorparms( self ):
+
+ ENCODING = 'latin-1'
+ site, tool, ctx = self._makeOne( encoding=ENCODING
+ , should_purge=True
+ )
+
+ self.assertEqual( ctx.getEncoding(), ENCODING )
+ self.assertEqual( ctx.shouldPurge(), True )
+
+ def test_empty( self ):
+
+ site, tool, ctx = self._makeOne()
+
+ self.assertEqual( ctx.getSite(), site )
+ self.assertEqual( ctx.getEncoding(), None )
+ self.assertEqual( ctx.shouldPurge(), False )
+
+ # These methods are all specified to return 'None' for non-existing
+ # paths / entities
+ self.assertEqual( ctx.isDirectory( 'nonesuch/path' ), None )
+ self.assertEqual( ctx.listDirectory( 'nonesuch/path' ), None )
+
+ def test_readDataFile_nonesuch( self ):
+
+ FILENAME = 'nonesuch.txt'
+
+ site, tool, ctx = self._makeOne()
+
+ self.assertEqual( ctx.readDataFile( FILENAME ), None )
+ self.assertEqual( ctx.readDataFile( FILENAME, 'subdir' ), None )
+
+ def test_readDataFile_simple( self ):
+
+ from string import printable
+
+ FILENAME = 'simple.txt'
+
+ site, tool, ctx = self._makeOne( { FILENAME: printable } )
+
+ self.assertEqual( ctx.readDataFile( FILENAME ), printable )
+
+ def test_readDataFile_subdir( self ):
+
+ from string import printable
+
+ FILENAME = 'subdir.txt'
+ SUBDIR = 'subdir'
+
+ site, tool, ctx = self._makeOne( { '%s/%s' % (SUBDIR, FILENAME):
+ printable } )
+
+ self.assertEqual( ctx.readDataFile( FILENAME, SUBDIR ), printable )
+
+ def test_getLastModified_nonesuch( self ):
+
+ FILENAME = 'nonesuch.txt'
+
+ site, tool, ctx = self._makeOne()
+
+ self.assertEqual( ctx.getLastModified( FILENAME ), None )
+
+ def test_getLastModified_simple( self ):
+
+ from string import printable
+
+ FILENAME = 'simple.txt'
+ WHEN = DateTime( '2004-01-01T00:00:00Z' )
+
+ site, tool, ctx = self._makeOne( { FILENAME : printable }
+ , mod_time=WHEN )
+
+ self.assertEqual( ctx.getLastModified( FILENAME ), WHEN )
+
+ def test_getLastModified_subdir( self ):
+
+ from string import printable
+
+ FILENAME = 'subdir.txt'
+ SUBDIR = 'subdir'
+ PATH = '%s/%s' % ( SUBDIR, FILENAME )
+ WHEN = DateTime( '2004-01-01T00:00:00Z' )
+
+ site, tool, ctx = self._makeOne( { PATH: printable }
+ , mod_time=WHEN )
+
+ self.assertEqual( ctx.getLastModified( PATH ), WHEN )
+
+ def test_getLastModified_directory( self ):
+
+ from string import printable
+
+ FILENAME = 'subdir.txt'
+ SUBDIR = 'subdir'
+ PATH = '%s/%s' % ( SUBDIR, FILENAME )
+ WHEN = DateTime( '2004-01-01T00:00:00Z' )
+
+ site, tool, ctx = self._makeOne( { PATH: printable }
+ , mod_time=WHEN
+ )
+
+ self.assertEqual( ctx.getLastModified( SUBDIR ), WHEN )
+
+ def test_isDirectory_nonesuch( self ):
+
+ FILENAME = 'nonesuch.txt'
+
+ site, tool, ctx = self._makeOne()
+
+ self.assertEqual( ctx.isDirectory( FILENAME ), None )
+
+ def test_isDirectory_simple( self ):
+
+ from string import printable
+
+ FILENAME = 'simple.txt'
+
+ site, tool, ctx = self._makeOne( { FILENAME: printable } )
+
+ self.assertEqual( ctx.isDirectory( FILENAME ), False )
+
+ def test_isDirectory_nested( self ):
+
+ from string import printable
+
+ SUBDIR = 'subdir'
+ FILENAME = 'nested.txt'
+ PATH = '%s/%s' % ( SUBDIR, FILENAME )
+
+ site, tool, ctx = self._makeOne( { PATH: printable } )
+
+ self.assertEqual( ctx.isDirectory( PATH ), False )
+
+ def test_isDirectory_subdir( self ):
+
+ from string import printable
+
+ SUBDIR = 'subdir'
+ FILENAME = 'nested.txt'
+ PATH = '%s/%s' % ( SUBDIR, FILENAME )
+
+ site, tool, ctx = self._makeOne( { PATH: printable } )
+
+ self.assertEqual( ctx.isDirectory( SUBDIR ), True )
+
+ def test_listDirectory_nonesuch( self ):
+
+ SUBDIR = 'nonesuch/path'
+
+ site, tool, ctx = self._makeOne()
+
+ self.assertEqual( ctx.listDirectory( SUBDIR ), None )
+
+ def test_listDirectory_root( self ):
+
+ from string import printable
+
+ FILENAME = 'simple.txt'
+
+ site, tool, ctx = self._makeOne( { FILENAME: printable } )
+
+ self.assertEqual( len( ctx.listDirectory( None ) ), 1 )
+ self.failUnless( FILENAME in ctx.listDirectory( None ) )
+
+ def test_listDirectory_simple( self ):
+
+ from string import printable
+
+ FILENAME = 'simple.txt'
+
+ site, tool, ctx = self._makeOne( { FILENAME: printable } )
+
+ self.assertEqual( ctx.listDirectory( FILENAME ), None )
+
+ def test_listDirectory_nested( self ):
+
+ from string import printable
+
+ SUBDIR = 'subdir'
+ FILENAME = 'nested.txt'
+ PATH = '%s/%s' % ( SUBDIR, FILENAME )
+
+ site, tool, ctx = self._makeOne( { PATH: printable } )
+
+ self.assertEqual( ctx.listDirectory( PATH ), None )
+
+ def test_listDirectory_single( self ):
+
+ from string import printable
+
+ SUBDIR = 'subdir'
+ FILENAME = 'nested.txt'
+ PATH = '%s/%s' % ( SUBDIR, FILENAME )
+
+ site, tool, ctx = self._makeOne( { PATH: printable } )
+
+ names = ctx.listDirectory( SUBDIR )
+ self.assertEqual( len( names ), 1 )
+ self.failUnless( FILENAME in names )
+
+ def test_listDirectory_multiple( self ):
+
+ from string import printable, uppercase
+
+ SUBDIR = 'subdir'
+ FILENAME1 = 'nested.txt'
+ PATH1 = '%s/%s' % ( SUBDIR, FILENAME1 )
+ FILENAME2 = 'another.txt'
+ PATH2 = '%s/%s' % ( SUBDIR, FILENAME2 )
+
+ site, tool, ctx = self._makeOne( { PATH1: printable
+ , PATH2: uppercase
+ } )
+
+ names = ctx.listDirectory( SUBDIR )
+ self.assertEqual( len( names ), 2 )
+ self.failUnless( FILENAME1 in names )
+ self.failUnless( FILENAME2 in names )
+
+ def test_listDirectory_skip( self ):
+
+ from string import printable, uppercase
+
+ SUBDIR = 'subdir'
+ FILENAME1 = 'nested.txt'
+ PATH1 = '%s/%s' % ( SUBDIR, FILENAME1 )
+ FILENAME2 = 'another.txt'
+ PATH2 = '%s/%s' % ( SUBDIR, FILENAME2 )
+
+ site, tool, ctx = self._makeOne( { PATH1: printable
+ , PATH2: uppercase
+ } )
+
+ names = ctx.listDirectory( SUBDIR, skip=( FILENAME1, ) )
+ self.assertEqual( len( names ), 1 )
+ self.failIf( FILENAME1 in names )
+ self.failUnless( FILENAME2 in names )
+
+
+class TarballExportContextTests( FilesystemTestBase
+ , TarballTester
+ , ConformsToISetupContext
+ , ConformsToIExportContext
+ ):
+
+ _PROFILE_PATH = '/tmp/TECT_tests'
+
+ def _getTargetClass( self ):
+
+ from Products.GenericSetup.context import TarballExportContext
+ return TarballExportContext
+
+ def test_writeDataFile_simple( self ):
+
+ from string import printable
+ now = long( time.time() )
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._getTargetClass()( site )
+
+ ctx.writeDataFile( 'foo.txt', printable, 'text/plain' )
+
+ fileish = StringIO( ctx.getArchive() )
+
+ self._verifyTarballContents( fileish, [ 'foo.txt' ], now )
+ self._verifyTarballEntry( fileish, 'foo.txt', printable )
+
+ def test_writeDataFile_multiple( self ):
+
+ from string import printable
+ from string import digits
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._getTargetClass()( site )
+
+ ctx.writeDataFile( 'foo.txt', printable, 'text/plain' )
+ ctx.writeDataFile( 'bar.txt', digits, 'text/plain' )
+
+ fileish = StringIO( ctx.getArchive() )
+
+ self._verifyTarballContents( fileish, [ 'foo.txt', 'bar.txt' ] )
+ self._verifyTarballEntry( fileish, 'foo.txt', printable )
+ self._verifyTarballEntry( fileish, 'bar.txt', digits )
+
+ def test_writeDataFile_subdir( self ):
+
+ from string import printable
+ from string import digits
+
+ site = DummySite( 'site' ).__of__( self.root )
+ ctx = self._getTargetClass()( site )
+
+ ctx.writeDataFile( 'foo.txt', printable, 'text/plain' )
+ ctx.writeDataFile( 'bar/baz.txt', digits, 'text/plain' )
+
+ fileish = StringIO( ctx.getArchive() )
+
+ self._verifyTarballContents( fileish, [ 'foo.txt', 'bar/baz.txt' ] )
+ self._verifyTarballEntry( fileish, 'foo.txt', printable )
+ self._verifyTarballEntry( fileish, 'bar/baz.txt', digits )
+
+
+class SnapshotExportContextTests( SecurityRequestTest
+ , ConformsToISetupContext
+ , ConformsToIExportContext
+ ):
+
+ def _getTargetClass( self ):
+
+ from Products.GenericSetup.context import SnapshotExportContext
+ return SnapshotExportContext
+
+ def _makeOne( self, *args, **kw ):
+
+ return self._getTargetClass()( *args, **kw )
+
+ def test_writeDataFile_simple_image( self ):
+
+ from OFS.Image import Image
+ FILENAME = 'simple.txt'
+ _CONTENT_TYPE = 'image/png'
+ png_filename = os.path.join( os.path.split( __file__ )[0]
+ , 'simple.png' )
+ png_file = open( png_filename, 'rb' )
+ png_data = png_file.read()
+ png_file.close()
+
+ site = DummySite( 'site' ).__of__( self.root )
+ site.setup_tool = DummyTool( 'setup_tool' )
+ tool = site.setup_tool
+ ctx = self._makeOne( tool, 'simple' )
+
+ ctx.writeDataFile( FILENAME, png_data, _CONTENT_TYPE )
+
+ snapshot = tool.snapshots._getOb( 'simple' )
+
+ self.assertEqual( len( snapshot.objectIds() ), 1 )
+ self.failUnless( FILENAME in snapshot.objectIds() )
+
+ fileobj = snapshot._getOb( FILENAME )
+
+ self.assertEqual( fileobj.getId(), FILENAME )
+ self.assertEqual( fileobj.meta_type, Image.meta_type )
+ self.assertEqual( fileobj.getContentType(), _CONTENT_TYPE )
+ self.assertEqual( fileobj.data, png_data )
+
+ def test_writeDataFile_simple_plain_text( self ):
+
+ from string import digits
+ from OFS.Image import File
+ FILENAME = 'simple.txt'
+ _CONTENT_TYPE = 'text/plain'
+
+ site = DummySite( 'site' ).__of__( self.root )
+ site.setup_tool = DummyTool( 'setup_tool' )
+ tool = site.setup_tool
+ ctx = self._makeOne( tool, 'simple' )
+
+ ctx.writeDataFile( FILENAME, digits, _CONTENT_TYPE )
+
+ snapshot = tool.snapshots._getOb( 'simple' )
+
+ self.assertEqual( len( snapshot.objectIds() ), 1 )
+ self.failUnless( FILENAME in snapshot.objectIds() )
+
+ fileobj = snapshot._getOb( FILENAME )
+
+ self.assertEqual( fileobj.getId(), FILENAME )
+ self.assertEqual( fileobj.meta_type, File.meta_type )
+ self.assertEqual( fileobj.getContentType(), _CONTENT_TYPE )
+ self.assertEqual( str( fileobj ), digits )
+
+ def test_writeDataFile_simple_xml( self ):
+
+ from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
+ FILENAME = 'simple.xml'
+ _CONTENT_TYPE = 'text/xml'
+ _XML = """<?xml version="1.0"?><simple />"""
+
+ site = DummySite( 'site' ).__of__( self.root )
+ site.setup_tool = DummyTool( 'setup_tool' )
+ tool = site.setup_tool
+ ctx = self._makeOne( tool, 'simple' )
+
+ ctx.writeDataFile( FILENAME, _XML, _CONTENT_TYPE )
+
+ snapshot = tool.snapshots._getOb( 'simple' )
+
+ self.assertEqual( len( snapshot.objectIds() ), 1 )
+ self.failUnless( FILENAME in snapshot.objectIds() )
+
+ template = snapshot._getOb( FILENAME )
+
+ self.assertEqual( template.getId(), FILENAME )
+ self.assertEqual( template.meta_type, ZopePageTemplate.meta_type )
+ self.assertEqual( template.read(), _XML )
+ self.failIf( template.html() )
+
+ def test_writeDataFile_unicode_xml( self ):
+
+ from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
+ FILENAME = 'simple.xml'
+ _CONTENT_TYPE = 'text/xml'
+ _XML = u"""<?xml version="1.0"?><simple />"""
+
+ site = DummySite( 'site' ).__of__( self.root )
+ site.setup_tool = DummyTool( 'setup_tool' )
+ tool = site.setup_tool
+ ctx = self._makeOne( tool, 'simple' )
+
+ ctx.writeDataFile( FILENAME, _XML, _CONTENT_TYPE )
+
+ snapshot = tool.snapshots._getOb( 'simple' )
+
+ self.assertEqual( len( snapshot.objectIds() ), 1 )
+ self.failUnless( FILENAME in snapshot.objectIds() )
+
+ template = snapshot._getOb( FILENAME )
+
+ self.assertEqual( template.getId(), FILENAME )
+ self.assertEqual( template.meta_type, ZopePageTemplate.meta_type )
+ self.assertEqual( template.read(), _XML )
+ self.failIf( template.html() )
+
+ def test_writeDataFile_subdir_dtml( self ):
+
+ from OFS.DTMLDocument import DTMLDocument
+ FILENAME = 'simple.dtml'
+ _CONTENT_TYPE = 'text/html'
+ _HTML = """<html><body><h1>HTML</h1></body></html>"""
+
+ site = DummySite( 'site' ).__of__( self.root )
+ site.setup_tool = DummyTool( 'setup_tool' )
+ tool = site.setup_tool
+ ctx = self._makeOne( tool, 'simple' )
+
+ ctx.writeDataFile( FILENAME, _HTML, _CONTENT_TYPE, 'sub1' )
+
+ snapshot = tool.snapshots._getOb( 'simple' )
+ sub1 = snapshot._getOb( 'sub1' )
+
+ self.assertEqual( len( sub1.objectIds() ), 1 )
+ self.failUnless( FILENAME in sub1.objectIds() )
+
+ template = sub1._getOb( FILENAME )
+
+ self.assertEqual( template.getId(), FILENAME )
+ self.assertEqual( template.meta_type, DTMLDocument.meta_type )
+ self.assertEqual( template.read(), _HTML )
+
+ def test_writeDataFile_nested_subdirs_html( self ):
+
+ from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
+ FILENAME = 'simple.html'
+ _CONTENT_TYPE = 'text/html'
+ _HTML = """<html><body><h1>HTML</h1></body></html>"""
+
+ site = DummySite( 'site' ).__of__( self.root )
+ site.setup_tool = DummyTool( 'setup_tool' )
+ tool = site.setup_tool
+ ctx = self._makeOne( tool, 'simple' )
+
+ ctx.writeDataFile( FILENAME, _HTML, _CONTENT_TYPE, 'sub1/sub2' )
+
+ snapshot = tool.snapshots._getOb( 'simple' )
+ sub1 = snapshot._getOb( 'sub1' )
+ sub2 = sub1._getOb( 'sub2' )
+
+ self.assertEqual( len( sub2.objectIds() ), 1 )
+ self.failUnless( FILENAME in sub2.objectIds() )
+
+ template = sub2._getOb( FILENAME )
+
+ self.assertEqual( template.getId(), FILENAME )
+ self.assertEqual( template.meta_type, ZopePageTemplate.meta_type )
+ self.assertEqual( template.read(), _HTML )
+ self.failUnless( template.html() )
+
+ def test_writeDataFile_multiple( self ):
+
+ from string import printable
+ from string import digits
+
+ site = DummySite( 'site' ).__of__( self.root )
+ site.setup_tool = DummyTool( 'setup_tool' )
+ tool = site.setup_tool
+ ctx = self._makeOne( tool, 'multiple' )
+
+ ctx.writeDataFile( 'foo.txt', printable, 'text/plain' )
+ ctx.writeDataFile( 'bar.txt', digits, 'text/plain' )
+
+ snapshot = tool.snapshots._getOb( 'multiple' )
+
+ self.assertEqual( len( snapshot.objectIds() ), 2 )
+
+ for id in [ 'foo.txt', 'bar.txt' ]:
+ self.failUnless( id in snapshot.objectIds() )
+
+
+class SnapshotImportContextTests( SecurityRequestTest
+ , ConformsToISetupContext
+ , ConformsToIImportContext
+ ):
+
+ def _getTargetClass( self ):
+
+ from Products.GenericSetup.context import SnapshotImportContext
+ return SnapshotImportContext
+
+ def _makeOne( self, context_id, *args, **kw ):
+
+ site = DummySite( 'site' ).__of__( self.root )
+ site._setObject( 'setup_tool', Folder( 'setup_tool' ) )
+ tool = site._getOb( 'setup_tool' )
+
+ tool._setObject( 'snapshots', Folder( 'snapshots' ) )
+ tool.snapshots._setObject( context_id, Folder( context_id ) )
+
+ ctx = self._getTargetClass()( tool, context_id, *args, **kw )
+
+ return site, tool, ctx.__of__( tool )
+
+ def _makeFile( self
+ , tool
+ , snapshot_id
+ , filename
+ , contents
+ , content_type='text/plain'
+ , mod_time=None
+ , subdir=None
+ ):
+
+ snapshots = tool._getOb( 'snapshots' )
+ folder = snapshot = snapshots._getOb( snapshot_id )
+
+ if subdir is not None:
+
+ for element in subdir.split( '/' ):
+
+ try:
+ folder = folder._getOb( element )
+ except AttributeError:
+ folder._setObject( element, Folder( element ) )
+ folder = folder._getOb( element )
+
+ file = File( filename, '', contents, content_type )
+ folder._setObject( filename, file )
+
+ if mod_time is not None:
+
+ def __faux_mod_time():
+ return mod_time
+
+ folder.bobobase_modification_time = \
+ file.bobobase_modification_time = __faux_mod_time
+
+ return folder._getOb( filename )
+
+ def test_ctorparms( self ):
+
+ SNAPSHOT_ID = 'ctorparms'
+ ENCODING = 'latin-1'
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID
+ , encoding=ENCODING
+ , should_purge=True
+ )
+
+ self.assertEqual( ctx.getEncoding(), ENCODING )
+ self.assertEqual( ctx.shouldPurge(), True )
+
+ def test_empty( self ):
+
+ SNAPSHOT_ID = 'empty'
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+
+ self.assertEqual( ctx.getSite(), site )
+ self.assertEqual( ctx.getEncoding(), None )
+ self.assertEqual( ctx.shouldPurge(), False )
+
+ # These methods are all specified to return 'None' for non-existing
+ # paths / entities
+ self.assertEqual( ctx.isDirectory( 'nonesuch/path' ), None )
+ self.assertEqual( ctx.listDirectory( 'nonesuch/path' ), None )
+
+ def test_readDataFile_nonesuch( self ):
+
+ SNAPSHOT_ID = 'readDataFile_nonesuch'
+ FILENAME = 'nonesuch.txt'
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+
+ self.assertEqual( ctx.readDataFile( FILENAME ), None )
+ self.assertEqual( ctx.readDataFile( FILENAME, 'subdir' ), None )
+
+ def test_readDataFile_simple( self ):
+
+ from string import printable
+
+ SNAPSHOT_ID = 'readDataFile_simple'
+ FILENAME = 'simple.txt'
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+ self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable )
+
+ self.assertEqual( ctx.readDataFile( FILENAME ), printable )
+
+ def test_readDataFile_subdir( self ):
+
+ from string import printable
+
+ SNAPSHOT_ID = 'readDataFile_subdir'
+ FILENAME = 'subdir.txt'
+ SUBDIR = 'subdir'
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+ self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
+ , subdir=SUBDIR )
+
+ self.assertEqual( ctx.readDataFile( FILENAME, SUBDIR ), printable )
+
+ def test_getLastModified_nonesuch( self ):
+
+ SNAPSHOT_ID = 'getLastModified_nonesuch'
+ FILENAME = 'nonesuch.txt'
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+
+ self.assertEqual( ctx.getLastModified( FILENAME ), None )
+
+ def test_getLastModified_simple( self ):
+
+ from string import printable
+
+ SNAPSHOT_ID = 'getLastModified_simple'
+ FILENAME = 'simple.txt'
+ WHEN = DateTime( '2004-01-01T00:00:00Z' )
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+ file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
+ , mod_time=WHEN )
+
+ self.assertEqual( ctx.getLastModified( FILENAME ), WHEN )
+
+ def test_getLastModified_subdir( self ):
+
+ from string import printable
+
+ SNAPSHOT_ID = 'getLastModified_subdir'
+ FILENAME = 'subdir.txt'
+ SUBDIR = 'subdir'
+ PATH = '%s/%s' % ( SUBDIR, FILENAME )
+ WHEN = DateTime( '2004-01-01T00:00:00Z' )
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+ file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
+ , mod_time=WHEN, subdir=SUBDIR )
+
+ self.assertEqual( ctx.getLastModified( PATH ), WHEN )
+
+ def test_getLastModified_directory( self ):
+
+ from string import printable
+
+ SNAPSHOT_ID = 'readDataFile_subdir'
+ FILENAME = 'subdir.txt'
+ SUBDIR = 'subdir'
+ WHEN = DateTime( '2004-01-01T00:00:00Z' )
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+ file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
+ , mod_time=WHEN, subdir=SUBDIR )
+
+ self.assertEqual( ctx.getLastModified( SUBDIR ), WHEN )
+
+ def test_isDirectory_nonesuch( self ):
+
+ SNAPSHOT_ID = 'isDirectory_nonesuch'
+ FILENAME = 'nonesuch.txt'
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+
+ self.assertEqual( ctx.isDirectory( FILENAME ), None )
+
+ def test_isDirectory_simple( self ):
+
+ from string import printable
+
+ SNAPSHOT_ID = 'isDirectory_simple'
+ FILENAME = 'simple.txt'
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+ file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable )
+
+ self.assertEqual( ctx.isDirectory( FILENAME ), False )
+
+ def test_isDirectory_nested( self ):
+
+ from string import printable
+
+ SNAPSHOT_ID = 'isDirectory_nested'
+ SUBDIR = 'subdir'
+ FILENAME = 'nested.txt'
+ PATH = '%s/%s' % ( SUBDIR, FILENAME )
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+ file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
+ , subdir=SUBDIR )
+
+ self.assertEqual( ctx.isDirectory( PATH ), False )
+
+ def test_isDirectory_subdir( self ):
+
+ from string import printable
+
+ SNAPSHOT_ID = 'isDirectory_subdir'
+ SUBDIR = 'subdir'
+ FILENAME = 'nested.txt'
+ PATH = '%s/%s' % ( SUBDIR, FILENAME )
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+ file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
+ , subdir=SUBDIR )
+
+ self.assertEqual( ctx.isDirectory( SUBDIR ), True )
+
+ def test_listDirectory_nonesuch( self ):
+
+ SNAPSHOT_ID = 'listDirectory_nonesuch'
+ SUBDIR = 'nonesuch/path'
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+
+ self.assertEqual( ctx.listDirectory( SUBDIR ), None )
+
+ def test_listDirectory_root( self ):
+
+ from string import printable
+
+ SNAPSHOT_ID = 'listDirectory_root'
+ FILENAME = 'simple.txt'
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+ file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable )
+
+ self.assertEqual( len( ctx.listDirectory( None ) ), 1 )
+ self.failUnless( FILENAME in ctx.listDirectory( None ) )
+
+ def test_listDirectory_simple( self ):
+
+ from string import printable
+
+ SNAPSHOT_ID = 'listDirectory_simple'
+ FILENAME = 'simple.txt'
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+ file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable )
+
+ self.assertEqual( ctx.listDirectory( FILENAME ), None )
+
+ def test_listDirectory_nested( self ):
+
+ from string import printable
+
+ SNAPSHOT_ID = 'listDirectory_nested'
+ SUBDIR = 'subdir'
+ FILENAME = 'nested.txt'
+ PATH = '%s/%s' % ( SUBDIR, FILENAME )
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+ file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
+ , subdir=SUBDIR )
+
+ self.assertEqual( ctx.listDirectory( PATH ), None )
+
+ def test_listDirectory_single( self ):
+
+ from string import printable
+
+ SNAPSHOT_ID = 'listDirectory_nested'
+ SUBDIR = 'subdir'
+ FILENAME = 'nested.txt'
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+ file = self._makeFile( tool, SNAPSHOT_ID, FILENAME, printable
+ , subdir=SUBDIR )
+
+ names = ctx.listDirectory( SUBDIR )
+ self.assertEqual( len( names ), 1 )
+ self.failUnless( FILENAME in names )
+
+ def test_listDirectory_multiple( self ):
+
+ from string import printable, uppercase
+
+ SNAPSHOT_ID = 'listDirectory_nested'
+ SUBDIR = 'subdir'
+ FILENAME1 = 'nested.txt'
+ FILENAME2 = 'another.txt'
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+ file1 = self._makeFile( tool, SNAPSHOT_ID, FILENAME1, printable
+ , subdir=SUBDIR )
+ file2 = self._makeFile( tool, SNAPSHOT_ID, FILENAME2, uppercase
+ , subdir=SUBDIR )
+
+ names = ctx.listDirectory( SUBDIR )
+ self.assertEqual( len( names ), 2 )
+ self.failUnless( FILENAME1 in names )
+ self.failUnless( FILENAME2 in names )
+
+ def test_listDirectory_skip( self ):
+
+ from string import printable, uppercase
+
+ SNAPSHOT_ID = 'listDirectory_nested'
+ SUBDIR = 'subdir'
+ FILENAME1 = 'nested.txt'
+ FILENAME2 = 'another.txt'
+
+ site, tool, ctx = self._makeOne( SNAPSHOT_ID )
+ file1 = self._makeFile( tool, SNAPSHOT_ID, FILENAME1, printable
+ , subdir=SUBDIR )
+ file2 = self._makeFile( tool, SNAPSHOT_ID, FILENAME2, uppercase
+ , subdir=SUBDIR )
+
+ names = ctx.listDirectory( SUBDIR, skip=( FILENAME1, ) )
+ self.assertEqual( len( names ), 1 )
+ self.failIf( FILENAME1 in names )
+ self.failUnless( FILENAME2 in names )
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite( DirectoryImportContextTests ),
+ unittest.makeSuite( DirectoryExportContextTests ),
+ unittest.makeSuite( TarballImportContextTests ),
+ unittest.makeSuite( TarballExportContextTests ),
+ unittest.makeSuite( SnapshotExportContextTests ),
+ unittest.makeSuite( SnapshotImportContextTests ),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/test_differ.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tests/test_differ.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tests/test_differ.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,412 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Unit tests for differ module.
+
+$Id: test_differ.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+import unittest
+import Testing
+try:
+ import Zope2
+except ImportError: # BBB: for Zope 2.7
+ import Zope as Zope2
+Zope2.startup()
+
+from OFS.Folder import Folder
+from OFS.Image import File
+
+from DateTime.DateTime import DateTime
+
+#from Products.CMFCore.tests.base.testcase import SecurityRequestTest
+from Testing.ZopeTestCase import ZopeTestCase
+from common import SecurityRequestTest
+
+
+class DummySite( Folder ):
+
+ pass
+
+
+class Test_unidiff( unittest.TestCase ):
+
+ def test_unidiff_both_text( self ):
+
+ from Products.GenericSetup.differ import unidiff
+
+ diff_lines = unidiff( ONE_FOUR, ZERO_FOUR )
+ diff_text = '\n'.join( diff_lines )
+ self.assertEqual( diff_text, DIFF_TEXT )
+
+ def test_unidiff_both_lines( self ):
+
+ from Products.GenericSetup.differ import unidiff
+
+ diff_lines = unidiff( ONE_FOUR.splitlines(), ZERO_FOUR.splitlines() )
+ diff_text = '\n'.join( diff_lines )
+ self.assertEqual( diff_text, DIFF_TEXT )
+
+ def test_unidiff_mixed( self ):
+
+ from Products.GenericSetup.differ import unidiff
+
+ diff_lines = unidiff( ONE_FOUR, ZERO_FOUR.splitlines() )
+ diff_text = '\n'.join( diff_lines )
+ self.assertEqual( diff_text, DIFF_TEXT )
+
+ def test_unidiff_ignore_blanks( self ):
+
+ from Products.GenericSetup.differ import unidiff
+
+ double_spaced = ONE_FOUR.replace( '\n', '\n\n' )
+ diff_lines = unidiff( double_spaced
+ , ZERO_FOUR.splitlines()
+ , ignore_blanks=True
+ )
+
+ diff_text = '\n'.join( diff_lines )
+ self.assertEqual( diff_text, DIFF_TEXT )
+
+ZERO_FOUR = """\
+zero
+one
+tree
+four
+"""
+
+ONE_FOUR = """\
+one
+two
+three
+four
+"""
+
+DIFF_TEXT = """\
+--- original None
++++ modified None
+@@ -1,4 +1,4 @@
++zero
+ one
+-two
+-three
++tree
+ four\
+"""
+
+class ConfigDiffTests( SecurityRequestTest ):
+
+ site = None
+ tool = None
+
+ def _getTargetClass( self ):
+
+ from Products.GenericSetup.differ import ConfigDiff
+ return ConfigDiff
+
+ def _makeOne( self, lhs, rhs, *args, **kw ):
+
+ return self._getTargetClass()( lhs, rhs, *args, **kw )
+
+ def _makeSite( self ):
+
+ if self.site is not None:
+ return
+
+ site = self.site = DummySite( 'site' ).__of__( self.root )
+ site._setObject( 'setup_tool', Folder( 'setup_tool' ) )
+ self.tool = tool = site._getOb( 'setup_tool' )
+
+ tool._setObject( 'snapshots', Folder( 'snapshots' ) )
+
+ def _makeContext( self, context_id ):
+
+ from Products.GenericSetup.context import SnapshotImportContext
+
+ self._makeSite()
+
+ if context_id not in self.tool.snapshots.objectIds():
+ self.tool.snapshots._setObject( context_id, Folder( context_id ) )
+
+ ctx = SnapshotImportContext( self.tool, context_id )
+
+ return ctx.__of__( self.tool )
+
+ def _makeDirectory( self, snapshot_id, subdir ):
+
+ self._makeSite()
+ folder = self.tool.snapshots._getOb( snapshot_id )
+
+ for element in subdir.split( '/' ):
+
+ try:
+ folder = folder._getOb( element )
+ except AttributeError:
+ folder._setObject( element, Folder( element ) )
+ folder = folder._getOb( element )
+
+ return folder
+
+ def _makeFile( self
+ , snapshot_id
+ , filename
+ , contents
+ , content_type='text/plain'
+ , mod_time=None
+ , subdir=None
+ ):
+
+ self._makeSite()
+ snapshots = self.tool.snapshots
+ snapshot = snapshots._getOb( snapshot_id )
+
+ if subdir is not None:
+ folder = self._makeDirectory( snapshot_id, subdir )
+ else:
+ folder = snapshot
+
+ file = File( filename, '', contents, content_type )
+ folder._setObject( filename, file )
+
+ if mod_time is not None:
+
+ def __faux_mod_time():
+ return mod_time
+
+ folder.bobobase_modification_time = \
+ file.bobobase_modification_time = __faux_mod_time
+
+ return folder._getOb( filename )
+
+ def test_compare_empties( self ):
+
+ lhs = self._makeContext( 'lhs' )
+ rhs = self._makeContext( 'rhs' )
+
+ cd = self._makeOne( lhs, rhs )
+
+ diffs = cd.compare()
+
+ self.assertEqual( diffs, '' )
+
+ def test_compare_identical( self ):
+
+ lhs = self._makeContext( 'lhs' )
+ rhs = self._makeContext( 'rhs' )
+
+ self._makeFile( 'lhs', 'test.txt', 'ABCDEF' )
+ self._makeFile( 'lhs', 'again.txt', 'GHIJKL', subdir='sub' )
+ self._makeFile( 'rhs', 'test.txt', 'ABCDEF' )
+ self._makeFile( 'rhs', 'again.txt', 'GHIJKL', subdir='sub' )
+
+ cd = self._makeOne( lhs, rhs )
+
+ diffs = cd.compare()
+
+ self.assertEqual( diffs, '' )
+
+ def test_compare_changed_file( self ):
+
+ BEFORE = DateTime( '2004-01-01T00:00:00Z' )
+ AFTER = DateTime( '2004-02-29T23:59:59Z' )
+
+ lhs = self._makeContext( 'lhs' )
+ rhs = self._makeContext( 'rhs' )
+
+ self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ', mod_time=BEFORE )
+ self._makeFile( 'lhs', 'again.txt', 'GHIJKL', subdir='sub' )
+ self._makeFile( 'rhs', 'test.txt', 'ABCDEF\nQRST', mod_time=AFTER )
+ self._makeFile( 'rhs', 'again.txt', 'GHIJKL', subdir='sub' )
+
+ cd = self._makeOne( lhs, rhs )
+
+ diffs = cd.compare()
+
+ self.assertEqual( diffs, TEST_TXT_DIFFS % ( BEFORE, AFTER ) )
+
+ def test_compare_changed_file_ignore_blanks( self ):
+
+ BEFORE = DateTime( '2004-01-01T00:00:00Z' )
+ AFTER = DateTime( '2004-02-29T23:59:59Z' )
+
+ lhs = self._makeContext( 'lhs' )
+ rhs = self._makeContext( 'rhs' )
+
+ self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ', mod_time=BEFORE )
+ self._makeFile( 'rhs', 'test.txt', 'ABCDEF\n\n\nWXYZ', mod_time=AFTER )
+
+ cd = self._makeOne( lhs, rhs, ignore_blanks=True )
+
+ diffs = cd.compare()
+
+ self.assertEqual( diffs, '' )
+
+ def test_compare_changed_file_explicit_skip( self ):
+
+ BEFORE = DateTime( '2004-01-01T00:00:00Z' )
+ AFTER = DateTime( '2004-02-29T23:59:59Z' )
+
+ lhs = self._makeContext( 'lhs' )
+ rhs = self._makeContext( 'rhs' )
+
+ self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ', subdir='skipme'
+ , mod_time=BEFORE )
+ self._makeFile( 'lhs', 'again.txt', 'GHIJKL', subdir='sub' )
+ self._makeFile( 'rhs', 'test.txt', 'ABCDEF\nQRST', subdir='skipme'
+ , mod_time=AFTER )
+ self._makeFile( 'rhs', 'again.txt', 'GHIJKL', subdir='sub' )
+
+ cd = self._makeOne( lhs, rhs, skip=[ 'skipme' ] )
+
+ diffs = cd.compare()
+
+ self.assertEqual( diffs, '' )
+
+ def test_compare_changed_file_implicit_skip( self ):
+
+ BEFORE = DateTime( '2004-01-01T00:00:00Z' )
+ AFTER = DateTime( '2004-02-29T23:59:59Z' )
+
+ lhs = self._makeContext( 'lhs' )
+ rhs = self._makeContext( 'rhs' )
+
+ self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ', subdir='CVS'
+ , mod_time=BEFORE )
+ self._makeFile( 'lhs', 'again.txt', 'GHIJKL', subdir='.svn'
+ , mod_time=BEFORE )
+
+ self._makeFile( 'rhs', 'test.txt', 'ABCDEF\nQRST', subdir='CVS'
+ , mod_time=AFTER )
+ self._makeFile( 'rhs', 'again.txt', 'MNOPQR', subdir='.svn'
+ , mod_time=AFTER )
+
+ cd = self._makeOne( lhs, rhs )
+
+ diffs = cd.compare()
+
+ self.assertEqual( diffs, '' )
+
+ def test_compare_added_file_no_missing_as_empty( self ):
+
+ lhs = self._makeContext( 'lhs' )
+ rhs = self._makeContext( 'rhs' )
+
+ self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ' )
+ self._makeDirectory( 'lhs', subdir='sub' )
+ self._makeFile( 'rhs', 'test.txt', 'ABCDEF\nWXYZ' )
+ self._makeFile( 'rhs', 'again.txt', 'GHIJKL', subdir='sub' )
+
+ cd = self._makeOne( lhs, rhs )
+
+ diffs = cd.compare()
+
+ self.assertEqual( diffs, ADDED_FILE_DIFFS_NO_MAE )
+
+ def test_compare_added_file_missing_as_empty( self ):
+
+ AFTER = DateTime( '2004-02-29T23:59:59Z' )
+ lhs = self._makeContext( 'lhs' )
+ rhs = self._makeContext( 'rhs' )
+
+ self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ' )
+ self._makeDirectory( 'lhs', subdir='sub' )
+ self._makeFile( 'rhs', 'test.txt', 'ABCDEF\nWXYZ' )
+ self._makeFile( 'rhs', 'again.txt', 'GHIJKL', subdir='sub'
+ , mod_time=AFTER )
+
+ cd = self._makeOne( lhs, rhs, missing_as_empty=True )
+
+ diffs = cd.compare()
+
+ self.assertEqual( diffs, ADDED_FILE_DIFFS_MAE % AFTER )
+
+ def test_compare_removed_file_no_missing_as_empty( self ):
+
+ lhs = self._makeContext( 'lhs' )
+ rhs = self._makeContext( 'rhs' )
+
+ self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ' )
+ self._makeFile( 'lhs', 'again.txt', 'GHIJKL', subdir='sub' )
+ self._makeFile( 'rhs', 'test.txt', 'ABCDEF\nWXYZ' )
+ self._makeDirectory( 'rhs', subdir='sub' )
+
+ cd = self._makeOne( lhs, rhs )
+
+ diffs = cd.compare()
+
+ self.assertEqual( diffs, REMOVED_FILE_DIFFS_NO_MAE )
+
+ def test_compare_removed_file_missing_as_empty( self ):
+
+ BEFORE = DateTime( '2004-01-01T00:00:00Z' )
+ lhs = self._makeContext( 'lhs' )
+ rhs = self._makeContext( 'rhs' )
+
+ self._makeFile( 'lhs', 'test.txt', 'ABCDEF\nWXYZ' )
+ self._makeFile( 'lhs', 'again.txt', 'GHIJKL', subdir='sub'
+ , mod_time=BEFORE )
+ self._makeFile( 'rhs', 'test.txt', 'ABCDEF\nWXYZ' )
+ self._makeDirectory( 'rhs', subdir='sub' )
+
+ cd = self._makeOne( lhs, rhs, missing_as_empty=True )
+
+ diffs = cd.compare()
+
+ self.assertEqual( diffs, REMOVED_FILE_DIFFS_MAE % BEFORE )
+
+
+TEST_TXT_DIFFS = """\
+Index: test.txt
+===================================================================
+--- test.txt %s
++++ test.txt %s
+@@ -1,2 +1,2 @@
+ ABCDEF
+-WXYZ
++QRST\
+"""
+
+ADDED_FILE_DIFFS_NO_MAE = """\
+** File sub/again.txt added
+"""
+
+ADDED_FILE_DIFFS_MAE = """\
+Index: sub/again.txt
+===================================================================
+--- sub/again.txt 0
++++ sub/again.txt %s
+@@ -1,0 +1,1 @@
++GHIJKL\
+"""
+
+REMOVED_FILE_DIFFS_NO_MAE = """\
+** File sub/again.txt removed
+"""
+
+REMOVED_FILE_DIFFS_MAE = """\
+Index: sub/again.txt
+===================================================================
+--- sub/again.txt %s
++++ sub/again.txt 0
+@@ -1,1 +1,0 @@
+-GHIJKL\
+"""
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite( Test_unidiff ),
+ unittest.makeSuite( ConfigDiffTests ),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/test_properties.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tests/test_properties.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tests/test_properties.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,291 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Site properties export / import unit tests.
+
+$Id: test_properties.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+import unittest
+import Testing
+try:
+ import Zope2
+except ImportError: # BBB: for Zope 2.7
+ import Zope as Zope2
+Zope2.startup()
+
+from OFS.Folder import Folder
+
+from common import BaseRegistryTests
+from common import DummyExportContext
+from common import DummyImportContext
+
+
+_EMPTY_EXPORT = """\
+<?xml version="1.0"?>
+<site>
+</site>
+"""
+
+_NORMAL_EXPORT = """\
+<?xml version="1.0"?>
+<site>
+ <property name="foo" type="string">Foo</property>
+ <property name="bar" type="tokens">
+ <element value="Bar"/></property>
+ <property name="moo" type="tokens">
+ <element value="Moo"/></property>
+</site>
+"""
+
+
+class DummySite(Folder):
+
+ _properties = ()
+
+
+class _SitePropertiesSetup(BaseRegistryTests):
+
+ def _initSite(self, foo=2, bar=2):
+
+ self.root.site = DummySite()
+ site = self.root.site
+
+ if foo > 0:
+ site._setProperty('foo', '', 'string')
+ if foo > 1:
+ site._updateProperty('foo', 'Foo')
+
+ if bar > 0:
+ site._setProperty( 'bar', (), 'tokens' )
+ site._setProperty( 'moo', (), 'tokens' )
+ if bar > 1:
+ site._updateProperty( 'bar', ('Bar',) )
+ site.moo = ['Moo']
+
+ return site
+
+
+class SitePropertiesConfiguratorTests(_SitePropertiesSetup):
+
+ def _getTargetClass(self):
+
+ from Products.GenericSetup.properties import SitePropertiesConfigurator
+ return SitePropertiesConfigurator
+
+ def test_listSiteInfos_normal(self):
+
+ site = self._initSite()
+
+ EXPECTED = [ { 'id': 'foo',
+ 'value': 'Foo',
+ 'elements': (),
+ 'type': 'string',
+ 'select_variable': None },
+ { 'id': 'bar',
+ 'value': '',
+ 'elements': ('Bar',),
+ 'type': 'tokens',
+ 'select_variable': None },
+ { 'id': 'moo',
+ 'value': '',
+ 'elements': ('Moo',),
+ 'type': 'tokens',
+ 'select_variable': None } ]
+
+ configurator = self._makeOne(site)
+
+ site_info = configurator.listSiteInfos()
+ self.assertEqual( len(site_info), len(EXPECTED) )
+
+ for found, expected in zip(site_info, EXPECTED):
+ self.assertEqual(found, expected)
+
+ def test_generateXML_empty(self):
+
+ site = self._initSite(0, 0)
+ configurator = self._makeOne(site).__of__(site)
+
+ self._compareDOM(configurator.generateXML(), _EMPTY_EXPORT)
+
+ def test_generateXML_normal(self):
+
+ site = self._initSite()
+ configurator = self._makeOne(site).__of__(site)
+
+ self._compareDOM( configurator.generateXML(), _NORMAL_EXPORT )
+
+ def test_parseXML_empty(self):
+
+ site = self._initSite(0, 0)
+ configurator = self._makeOne(site)
+ site_info = configurator.parseXML(_EMPTY_EXPORT)
+
+ self.assertEqual( len( site_info['properties'] ), 0 )
+
+ def test_parseXML_normal(self):
+
+ site = self._initSite()
+ configurator = self._makeOne(site)
+ site_info = configurator.parseXML(_NORMAL_EXPORT)
+
+ self.assertEqual( len( site_info['properties'] ), 3 )
+
+ info = site_info['properties'][0]
+ self.assertEqual( info['id'], 'foo' )
+ self.assertEqual( info['value'], 'Foo' )
+ self.assertEqual( len( info['elements'] ), 0 )
+
+ info = site_info['properties'][1]
+ self.assertEqual( info['id'], 'bar' )
+ self.assertEqual( info['value'], '' )
+ self.assertEqual( len( info['elements'] ), 1 )
+ self.assertEqual( info['elements'][0], 'Bar' )
+
+
+class Test_exportSiteProperties(_SitePropertiesSetup):
+
+ def test_empty(self):
+
+ site = self._initSite(0, 0)
+ context = DummyExportContext(site)
+
+ from Products.GenericSetup.properties import exportSiteProperties
+ exportSiteProperties(context)
+
+ self.assertEqual( len(context._wrote), 1 )
+ filename, text, content_type = context._wrote[0]
+ self.assertEqual(filename, 'properties.xml')
+ self._compareDOM(text, _EMPTY_EXPORT)
+ self.assertEqual(content_type, 'text/xml')
+
+ def test_normal(self):
+
+ site = self._initSite()
+ context = DummyExportContext( site )
+
+ from Products.GenericSetup.properties import exportSiteProperties
+ exportSiteProperties(context)
+
+ self.assertEqual( len(context._wrote), 1 )
+ filename, text, content_type = context._wrote[0]
+ self.assertEqual(filename, 'properties.xml')
+ self._compareDOM(text, _NORMAL_EXPORT)
+ self.assertEqual(content_type, 'text/xml')
+
+
+class Test_importSiteProperties(_SitePropertiesSetup):
+
+ def test_empty_default_purge(self):
+
+ site = self._initSite()
+
+ self.assertEqual( len( site.propertyIds() ), 3 )
+ self.failUnless( 'foo' in site.propertyIds() )
+ self.assertEqual( site.getProperty('foo'), 'Foo' )
+ self.failUnless( 'bar' in site.propertyIds() )
+ self.assertEqual( site.getProperty('bar'), ('Bar',) )
+
+ context = DummyImportContext(site)
+ context._files['properties.xml'] = _EMPTY_EXPORT
+
+ from Products.GenericSetup.properties import importSiteProperties
+ importSiteProperties(context)
+
+ self.assertEqual( len( site.propertyIds() ), 0 )
+
+ def test_empty_explicit_purge(self):
+
+ site = self._initSite()
+
+ self.assertEqual( len( site.propertyIds() ), 3 )
+ self.failUnless( 'foo' in site.propertyIds() )
+ self.assertEqual( site.getProperty('foo'), 'Foo' )
+ self.failUnless( 'bar' in site.propertyIds() )
+ self.assertEqual( site.getProperty('bar'), ('Bar',) )
+
+ context = DummyImportContext(site, True)
+ context._files['properties.xml'] = _EMPTY_EXPORT
+
+ from Products.GenericSetup.properties import importSiteProperties
+ importSiteProperties(context)
+
+ self.assertEqual( len( site.propertyIds() ), 0 )
+
+ def test_empty_skip_purge(self):
+
+ site = self._initSite()
+
+ self.assertEqual( len( site.propertyIds() ), 3 )
+ self.failUnless( 'foo' in site.propertyIds() )
+ self.assertEqual( site.getProperty('foo'), 'Foo' )
+ self.failUnless( 'bar' in site.propertyIds() )
+ self.assertEqual( site.getProperty('bar'), ('Bar',) )
+
+ context = DummyImportContext(site, False)
+ context._files['properties.xml'] = _EMPTY_EXPORT
+
+ from Products.GenericSetup.properties import importSiteProperties
+ importSiteProperties(context)
+
+ self.assertEqual( len( site.propertyIds() ), 3 )
+ self.failUnless( 'foo' in site.propertyIds() )
+ self.assertEqual( site.getProperty('foo'), 'Foo' )
+ self.failUnless( 'bar' in site.propertyIds() )
+ self.assertEqual( site.getProperty('bar'), ('Bar',) )
+
+ def test_normal(self):
+
+ site = self._initSite(0,0)
+
+ self.assertEqual( len( site.propertyIds() ), 0 )
+
+ context = DummyImportContext(site)
+ context._files['properties.xml'] = _NORMAL_EXPORT
+
+ from Products.GenericSetup.properties import importSiteProperties
+ importSiteProperties(context)
+
+ self.assertEqual( len( site.propertyIds() ), 3 )
+ self.failUnless( 'foo' in site.propertyIds() )
+ self.assertEqual( site.getProperty('foo'), 'Foo' )
+ self.failUnless( 'bar' in site.propertyIds() )
+ self.assertEqual( site.getProperty('bar'), ('Bar',) )
+
+ def test_normal_encode_as_ascii(self):
+
+ site = self._initSite(0,0)
+
+ self.assertEqual( len( site.propertyIds() ), 0 )
+
+ context = DummyImportContext(site, encoding='ascii')
+ context._files['properties.xml'] = _NORMAL_EXPORT
+
+ from Products.GenericSetup.properties import importSiteProperties
+ importSiteProperties(context)
+
+ self.assertEqual( len( site.propertyIds() ), 3 )
+ self.failUnless( 'foo' in site.propertyIds() )
+ self.assertEqual( site.getProperty('foo'), 'Foo' )
+ self.failUnless( 'bar' in site.propertyIds() )
+ self.assertEqual( site.getProperty('bar'), ('Bar',) )
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(SitePropertiesConfiguratorTests),
+ unittest.makeSuite(Test_exportSiteProperties),
+ unittest.makeSuite(Test_importSiteProperties),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/test_registry.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tests/test_registry.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tests/test_registry.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,1101 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Registry unit tests.
+
+$Id: test_registry.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+import unittest
+import Testing
+try:
+ import Zope2
+except ImportError: # BBB: for Zope 2.7
+ import Zope as Zope2
+Zope2.startup()
+
+from OFS.Folder import Folder
+from Products.GenericSetup.tests.common import BaseRegistryTests
+from Products.GenericSetup import EXTENSION
+
+from conformance import ConformsToIStepRegistry
+from conformance import ConformsToIImportStepRegistry
+from conformance import ConformsToIExportStepRegistry
+from conformance import ConformsToIToolsetRegistry
+from conformance import ConformsToIProfileRegistry
+
+
+#==============================================================================
+# Dummy handlers
+#==============================================================================
+def ONE_FUNC( context ): pass
+def TWO_FUNC( context ): pass
+def THREE_FUNC( context ): pass
+def FOUR_FUNC( context ): pass
+
+ONE_FUNC_NAME = '%s.%s' % ( __name__, ONE_FUNC.__name__ )
+TWO_FUNC_NAME = '%s.%s' % ( __name__, TWO_FUNC.__name__ )
+THREE_FUNC_NAME = '%s.%s' % ( __name__, THREE_FUNC.__name__ )
+FOUR_FUNC_NAME = '%s.%s' % ( __name__, FOUR_FUNC.__name__ )
+
+
+#==============================================================================
+# SSR tests
+#==============================================================================
+class ImportStepRegistryTests( BaseRegistryTests
+ , ConformsToIStepRegistry
+ , ConformsToIImportStepRegistry
+ ):
+
+ def _getTargetClass( self ):
+
+ from Products.GenericSetup.registry import ImportStepRegistry
+ return ImportStepRegistry
+
+ def test_empty( self ):
+
+ registry = self._makeOne()
+
+ self.assertEqual( len( registry.listSteps() ), 0 )
+ self.assertEqual( len( registry.listStepMetadata() ), 0 )
+ self.assertEqual( len( registry.sortSteps() ), 0 )
+
+ def test_getStep_nonesuch( self ):
+
+ registry = self._makeOne()
+
+ self.assertEqual( registry.getStep( 'nonesuch' ), None )
+ self.assertEqual( registry.getStep( 'nonesuch' ), None )
+ default = object()
+ self.failUnless( registry.getStepMetadata( 'nonesuch'
+ , default ) is default )
+ self.failUnless( registry.getStep( 'nonesuch', default ) is default )
+ self.failUnless( registry.getStepMetadata( 'nonesuch'
+ , default ) is default )
+
+ def test_getStep_defaulted( self ):
+
+ registry = self._makeOne()
+ default = object()
+
+ self.failUnless( registry.getStep( 'nonesuch', default ) is default )
+ self.assertEqual( registry.getStepMetadata( 'nonesuch', {} ), {} )
+
+ def test_registerStep_docstring( self ):
+
+ def func_with_doc( site ):
+ """This is the first line.
+
+ This is the second line.
+ """
+ FUNC_NAME = '%s.%s' % ( __name__, func_with_doc.__name__ )
+
+ registry = self._makeOne()
+
+ registry.registerStep( id='docstring'
+ , version='1'
+ , handler=func_with_doc
+ , dependencies=()
+ )
+
+ info = registry.getStepMetadata( 'docstring' )
+ self.assertEqual( info[ 'id' ], 'docstring' )
+ self.assertEqual( info[ 'handler' ], FUNC_NAME )
+ self.assertEqual( info[ 'dependencies' ], () )
+ self.assertEqual( info[ 'title' ], 'This is the first line.' )
+ self.assertEqual( info[ 'description' ] , 'This is the second line.' )
+
+ def test_registerStep_docstring_override( self ):
+
+ def func_with_doc( site ):
+ """This is the first line.
+
+ This is the second line.
+ """
+ FUNC_NAME = '%s.%s' % ( __name__, func_with_doc.__name__ )
+
+ registry = self._makeOne()
+
+ registry.registerStep( id='docstring'
+ , version='1'
+ , handler=func_with_doc
+ , dependencies=()
+ , title='Title'
+ )
+
+ info = registry.getStepMetadata( 'docstring' )
+ self.assertEqual( info[ 'id' ], 'docstring' )
+ self.assertEqual( info[ 'handler' ], FUNC_NAME )
+ self.assertEqual( info[ 'dependencies' ], () )
+ self.assertEqual( info[ 'title' ], 'Title' )
+ self.assertEqual( info[ 'description' ] , 'This is the second line.' )
+
+ def test_registerStep_single( self ):
+
+ registry = self._makeOne()
+
+ registry.registerStep( id='one'
+ , version='1'
+ , handler=ONE_FUNC
+ , dependencies=( 'two', 'three' )
+ , title='One Step'
+ , description='One small step'
+ )
+
+ steps = registry.listSteps()
+ self.assertEqual( len( steps ), 1 )
+ self.failUnless( 'one' in steps )
+
+ sorted = registry.sortSteps()
+ self.assertEqual( len( sorted ), 1 )
+ self.assertEqual( sorted[ 0 ], 'one' )
+
+ self.assertEqual( registry.getStep( 'one' ), ONE_FUNC )
+
+ info = registry.getStepMetadata( 'one' )
+ self.assertEqual( info[ 'id' ], 'one' )
+ self.assertEqual( info[ 'version' ], '1' )
+ self.assertEqual( info[ 'handler' ], ONE_FUNC_NAME )
+ self.assertEqual( info[ 'dependencies' ], ( 'two', 'three' ) )
+ self.assertEqual( info[ 'title' ], 'One Step' )
+ self.assertEqual( info[ 'description' ], 'One small step' )
+
+ info_list = registry.listStepMetadata()
+ self.assertEqual( len( info_list ), 1 )
+ self.assertEqual( info, info_list[ 0 ] )
+
+ def test_registerStep_conflict( self ):
+
+ registry = self._makeOne()
+
+ registry.registerStep( id='one', version='1', handler=ONE_FUNC )
+
+ self.assertRaises( KeyError
+ , registry.registerStep
+ , id='one'
+ , version='0'
+ , handler=ONE_FUNC
+ )
+
+ registry.registerStep( id='one', version='1', handler=ONE_FUNC )
+
+ info_list = registry.listStepMetadata()
+ self.assertEqual( len( info_list ), 1 )
+
+ def test_registerStep_replacement( self ):
+
+ registry = self._makeOne()
+
+ registry.registerStep( id='one'
+ , version='1'
+ , handler=ONE_FUNC
+ , dependencies=( 'two', 'three' )
+ , title='One Step'
+ , description='One small step'
+ )
+
+ registry.registerStep( id='one'
+ , version='1.1'
+ , handler=ONE_FUNC
+ , dependencies=()
+ , title='Leads to Another'
+ , description='Another small step'
+ )
+
+ info = registry.getStepMetadata( 'one' )
+ self.assertEqual( info[ 'id' ], 'one' )
+ self.assertEqual( info[ 'version' ], '1.1' )
+ self.assertEqual( info[ 'dependencies' ], () )
+ self.assertEqual( info[ 'title' ], 'Leads to Another' )
+ self.assertEqual( info[ 'description' ], 'Another small step' )
+
+ def test_registerStep_multiple( self ):
+
+ registry = self._makeOne()
+
+ registry.registerStep( id='one'
+ , version='1'
+ , handler=ONE_FUNC
+ , dependencies=()
+ )
+
+ registry.registerStep( id='two'
+ , version='2'
+ , handler=TWO_FUNC
+ , dependencies=()
+ )
+
+ registry.registerStep( id='three'
+ , version='3'
+ , handler=THREE_FUNC
+ , dependencies=()
+ )
+
+ steps = registry.listSteps()
+ self.assertEqual( len( steps ), 3 )
+ self.failUnless( 'one' in steps )
+ self.failUnless( 'two' in steps )
+ self.failUnless( 'three' in steps )
+
+ def test_sortStep_simple( self ):
+
+ registry = self._makeOne()
+
+ registry.registerStep( id='one'
+ , version='1'
+ , handler=ONE_FUNC
+ , dependencies=( 'two', )
+ )
+
+ registry.registerStep( id='two'
+ , version='2'
+ , handler=TWO_FUNC
+ , dependencies=()
+ )
+
+ steps = registry.sortSteps()
+ self.assertEqual( len( steps ), 2 )
+ one = steps.index( 'one' )
+ two = steps.index( 'two' )
+
+ self.failUnless( 0 <= two < one )
+
+ def test_sortStep_chained( self ):
+
+ registry = self._makeOne()
+
+ registry.registerStep( id='one'
+ , version='1'
+ , handler=ONE_FUNC
+ , dependencies=( 'two', )
+ , title='One small step'
+ )
+
+ registry.registerStep( id='two'
+ , version='2'
+ , handler=TWO_FUNC
+ , dependencies=( 'three', )
+ , title='Texas two step'
+ )
+
+ registry.registerStep( id='three'
+ , version='3'
+ , handler=THREE_FUNC
+ , dependencies=()
+ , title='Gimme three steps'
+ )
+
+ steps = registry.sortSteps()
+ self.assertEqual( len( steps ), 3 )
+ one = steps.index( 'one' )
+ two = steps.index( 'two' )
+ three = steps.index( 'three' )
+
+ self.failUnless( 0 <= three < two < one )
+
+ def test_sortStep_complex( self ):
+
+ registry = self._makeOne()
+
+ registry.registerStep( id='one'
+ , version='1'
+ , handler=ONE_FUNC
+ , dependencies=( 'two', )
+ , title='One small step'
+ )
+
+ registry.registerStep( id='two'
+ , version='2'
+ , handler=TWO_FUNC
+ , dependencies=( 'four', )
+ , title='Texas two step'
+ )
+
+ registry.registerStep( id='three'
+ , version='3'
+ , handler=THREE_FUNC
+ , dependencies=( 'four', )
+ , title='Gimme three steps'
+ )
+
+ registry.registerStep( id='four'
+ , version='4'
+ , handler=FOUR_FUNC
+ , dependencies=()
+ , title='Four step program'
+ )
+
+ steps = registry.sortSteps()
+ self.assertEqual( len( steps ), 4 )
+ one = steps.index( 'one' )
+ two = steps.index( 'two' )
+ three = steps.index( 'three' )
+ four = steps.index( 'four' )
+
+ self.failUnless( 0 <= four < two < one )
+ self.failUnless( 0 <= four < three )
+
+ def test_sortStep_equivalence( self ):
+
+ registry = self._makeOne()
+
+ registry.registerStep( id='one'
+ , version='1'
+ , handler=ONE_FUNC
+ , dependencies=( 'two', 'three' )
+ , title='One small step'
+ )
+
+ registry.registerStep( id='two'
+ , version='2'
+ , handler=TWO_FUNC
+ , dependencies=( 'four', )
+ , title='Texas two step'
+ )
+
+ registry.registerStep( id='three'
+ , version='3'
+ , handler=THREE_FUNC
+ , dependencies=( 'four', )
+ , title='Gimme three steps'
+ )
+
+ registry.registerStep( id='four'
+ , version='4'
+ , handler=FOUR_FUNC
+ , dependencies=()
+ , title='Four step program'
+ )
+
+ steps = registry.sortSteps()
+ self.assertEqual( len( steps ), 4 )
+ one = steps.index( 'one' )
+ two = steps.index( 'two' )
+ three = steps.index( 'three' )
+ four = steps.index( 'four' )
+
+ self.failUnless( 0 <= four < two < one )
+ self.failUnless( 0 <= four < three < one )
+
+ def test_checkComplete_simple( self ):
+
+ registry = self._makeOne()
+
+ registry.registerStep( id='one'
+ , version='1'
+ , handler=ONE_FUNC
+ , dependencies=( 'two', )
+ )
+
+ incomplete = registry.checkComplete()
+ self.assertEqual( len( incomplete ), 1 )
+ self.failUnless( ( 'one', 'two' ) in incomplete )
+
+ registry.registerStep( id='two'
+ , version='2'
+ , handler=TWO_FUNC
+ , dependencies=()
+ )
+
+ self.assertEqual( len( registry.checkComplete() ), 0 )
+
+ def test_checkComplete_double( self ):
+
+ registry = self._makeOne()
+
+ registry.registerStep( id='one'
+ , version='1'
+ , handler=ONE_FUNC
+ , dependencies=( 'two', 'three' )
+ )
+
+ incomplete = registry.checkComplete()
+ self.assertEqual( len( incomplete ), 2 )
+ self.failUnless( ( 'one', 'two' ) in incomplete )
+ self.failUnless( ( 'one', 'three' ) in incomplete )
+
+ registry.registerStep( id='two'
+ , version='2'
+ , handler=TWO_FUNC
+ , dependencies=()
+ )
+
+ incomplete = registry.checkComplete()
+ self.assertEqual( len( incomplete ), 1 )
+ self.failUnless( ( 'one', 'three' ) in incomplete )
+
+ registry.registerStep( id='three'
+ , version='3'
+ , handler=THREE_FUNC
+ , dependencies=()
+ )
+
+ self.assertEqual( len( registry.checkComplete() ), 0 )
+
+ registry.registerStep( id='two'
+ , version='2.1'
+ , handler=TWO_FUNC
+ , dependencies=( 'four', )
+ )
+
+ incomplete = registry.checkComplete()
+ self.assertEqual( len( incomplete ), 1 )
+ self.failUnless( ( 'two', 'four' ) in incomplete )
+
+ def test_generateXML_empty( self ):
+
+ registry = self._makeOne().__of__( self.root )
+
+ xml = registry.generateXML()
+
+ self._compareDOM( registry.generateXML(), _EMPTY_IMPORT_XML )
+
+ def test_generateXML_single( self ):
+
+ registry = self._makeOne().__of__( self.root )
+
+ registry.registerStep( id='one'
+ , version='1'
+ , handler=ONE_FUNC
+ , dependencies=()
+ , title='One Step'
+ , description='One small step'
+ )
+
+ self._compareDOM( registry.generateXML(), _SINGLE_IMPORT_XML )
+
+ def test_generateXML_ordered( self ):
+
+ registry = self._makeOne().__of__( self.root )
+
+ registry.registerStep( id='one'
+ , version='1'
+ , handler=ONE_FUNC
+ , dependencies=( 'two', )
+ , title='One Step'
+ , description='One small step'
+ )
+
+ registry.registerStep( id='two'
+ , version='2'
+ , handler=TWO_FUNC
+ , dependencies=( 'three', )
+ , title='Two Steps'
+ , description='Texas two step'
+ )
+
+ registry.registerStep( id='three'
+ , version='3'
+ , handler=THREE_FUNC
+ , dependencies=()
+ , title='Three Steps'
+ , description='Gimme three steps'
+ )
+
+ self._compareDOM( registry.generateXML(), _ORDERED_IMPORT_XML )
+
+ def test_parseXML_empty( self ):
+
+ registry = self._makeOne().__of__( self.root )
+
+ registry.registerStep( id='one'
+ , version='1'
+ , handler=ONE_FUNC
+ , dependencies=()
+ , description='One small step'
+ )
+
+ info_list = registry.parseXML( _EMPTY_IMPORT_XML )
+
+ self.assertEqual( len( info_list ), 0 )
+
+ def test_parseXML_single( self ):
+
+ registry = self._makeOne().__of__( self.root )
+
+ registry.registerStep( id='two'
+ , version='2'
+ , handler=TWO_FUNC
+ , dependencies=()
+ , title='Two Steps'
+ , description='Texas two step'
+ )
+
+ info_list = registry.parseXML( _SINGLE_IMPORT_XML )
+
+ self.assertEqual( len( info_list ), 1 )
+
+ info = info_list[ 0 ]
+ self.assertEqual( info[ 'id' ], 'one' )
+ self.assertEqual( info[ 'version' ], '1' )
+ self.assertEqual( info[ 'handler' ], ONE_FUNC_NAME )
+ self.assertEqual( info[ 'dependencies' ], () )
+ self.assertEqual( info[ 'title' ], 'One Step' )
+ self.failUnless( 'One small step' in info[ 'description' ] )
+
+
+_EMPTY_IMPORT_XML = """\
+<?xml version="1.0"?>
+<import-steps>
+</import-steps>
+"""
+
+_SINGLE_IMPORT_XML = """\
+<?xml version="1.0"?>
+<import-steps>
+ <import-step id="one"
+ version="1"
+ handler="%s"
+ title="One Step">
+ One small step
+ </import-step>
+</import-steps>
+""" % ( ONE_FUNC_NAME, )
+
+_ORDERED_IMPORT_XML = """\
+<?xml version="1.0"?>
+<import-steps>
+ <import-step id="one"
+ version="1"
+ handler="%s"
+ title="One Step">
+ <dependency step="two" />
+ One small step
+ </import-step>
+ <import-step id="three"
+ version="3"
+ handler="%s"
+ title="Three Steps">
+ Gimme three steps
+ </import-step>
+ <import-step id="two"
+ version="2"
+ handler="%s"
+ title="Two Steps">
+ <dependency step="three" />
+ Texas two step
+ </import-step>
+</import-steps>
+""" % ( ONE_FUNC_NAME, THREE_FUNC_NAME, TWO_FUNC_NAME )
+
+
+#==============================================================================
+# ESR tests
+#==============================================================================
+class ExportStepRegistryTests( BaseRegistryTests
+ , ConformsToIStepRegistry
+ , ConformsToIExportStepRegistry
+ ):
+
+ def _getTargetClass( self ):
+
+ from Products.GenericSetup.registry import ExportStepRegistry
+ return ExportStepRegistry
+
+ def _makeOne( self, *args, **kw ):
+
+ return self._getTargetClass()( *args, **kw )
+
+ def test_empty( self ):
+
+ registry = self._makeOne()
+ self.assertEqual( len( registry.listSteps() ), 0 )
+ self.assertEqual( len( registry.listStepMetadata() ), 0 )
+
+ def test_getStep_nonesuch( self ):
+
+ registry = self._makeOne()
+ self.assertEqual( registry.getStep( 'nonesuch' ), None )
+
+ def test_getStep_defaulted( self ):
+
+ registry = self._makeOne()
+ default = lambda x: false
+ self.assertEqual( registry.getStep( 'nonesuch', default ), default )
+
+ def test_getStepMetadata_nonesuch( self ):
+
+ registry = self._makeOne()
+ self.assertEqual( registry.getStepMetadata( 'nonesuch' ), None )
+
+ def test_getStepMetadata_defaulted( self ):
+
+ registry = self._makeOne()
+ self.assertEqual( registry.getStepMetadata( 'nonesuch', {} ), {} )
+
+ def test_registerStep_simple( self ):
+
+ registry = self._makeOne()
+ registry.registerStep( 'one', ONE_FUNC )
+ info = registry.getStepMetadata( 'one', {} )
+
+ self.assertEqual( info[ 'id' ], 'one' )
+ self.assertEqual( info[ 'handler' ], ONE_FUNC_NAME )
+ self.assertEqual( info[ 'title' ], 'one' )
+ self.assertEqual( info[ 'description' ], '' )
+
+ def test_registerStep_docstring( self ):
+
+ def func_with_doc( site ):
+ """This is the first line.
+
+ This is the second line.
+ """
+ FUNC_NAME = '%s.%s' % ( __name__, func_with_doc.__name__ )
+
+ registry = self._makeOne()
+ registry.registerStep( 'one', func_with_doc )
+ info = registry.getStepMetadata( 'one', {} )
+
+ self.assertEqual( info[ 'id' ], 'one' )
+ self.assertEqual( info[ 'handler' ], FUNC_NAME )
+ self.assertEqual( info[ 'title' ], 'This is the first line.' )
+ self.assertEqual( info[ 'description' ] , 'This is the second line.' )
+
+ def test_registerStep_docstring_with_override( self ):
+
+ def func_with_doc( site ):
+ """This is the first line.
+
+ This is the second line.
+ """
+ FUNC_NAME = '%s.%s' % ( __name__, func_with_doc.__name__ )
+
+ registry = self._makeOne()
+ registry.registerStep( 'one', func_with_doc
+ , description='Description' )
+ info = registry.getStepMetadata( 'one', {} )
+
+ self.assertEqual( info[ 'id' ], 'one' )
+ self.assertEqual( info[ 'handler' ], FUNC_NAME )
+ self.assertEqual( info[ 'title' ], 'This is the first line.' )
+ self.assertEqual( info[ 'description' ], 'Description' )
+
+ def test_registerStep_collision( self ):
+
+ registry = self._makeOne()
+ registry.registerStep( 'one', ONE_FUNC )
+ registry.registerStep( 'one', TWO_FUNC )
+ info = registry.getStepMetadata( 'one', {} )
+
+ self.assertEqual( info[ 'id' ], 'one' )
+ self.assertEqual( info[ 'handler' ], TWO_FUNC_NAME )
+ self.assertEqual( info[ 'title' ], 'one' )
+ self.assertEqual( info[ 'description' ], '' )
+
+ def test_generateXML_empty( self ):
+
+ registry = self._makeOne().__of__( self.root )
+
+ xml = registry.generateXML()
+
+ self._compareDOM( registry.generateXML(), _EMPTY_EXPORT_XML )
+
+ def test_generateXML_single( self ):
+
+ registry = self._makeOne().__of__( self.root )
+
+ registry.registerStep( id='one'
+ , handler=ONE_FUNC
+ , title='One Step'
+ , description='One small step'
+ )
+
+ self._compareDOM( registry.generateXML(), _SINGLE_EXPORT_XML )
+
+ def test_generateXML_ordered( self ):
+
+ registry = self._makeOne().__of__( self.root )
+
+ registry.registerStep( id='one'
+ , handler=ONE_FUNC
+ , title='One Step'
+ , description='One small step'
+ )
+
+ registry.registerStep( id='two'
+ , handler=TWO_FUNC
+ , title='Two Steps'
+ , description='Texas two step'
+ )
+
+ registry.registerStep( id='three'
+ , handler=THREE_FUNC
+ , title='Three Steps'
+ , description='Gimme three steps'
+ )
+
+ self._compareDOM( registry.generateXML(), _ORDERED_EXPORT_XML )
+
+ def test_parseXML_empty( self ):
+
+ registry = self._makeOne().__of__( self.root )
+
+ registry.registerStep( id='one'
+ , handler=ONE_FUNC
+ , description='One small step'
+ )
+
+ info_list = registry.parseXML( _EMPTY_EXPORT_XML )
+
+ self.assertEqual( len( info_list ), 0 )
+
+ def test_parseXML_single( self ):
+
+ registry = self._makeOne().__of__( self.root )
+
+ registry.registerStep( id='two'
+ , handler=TWO_FUNC
+ , title='Two Steps'
+ , description='Texas two step'
+ )
+
+ info_list = registry.parseXML( _SINGLE_EXPORT_XML )
+
+ self.assertEqual( len( info_list ), 1 )
+
+ info = info_list[ 0 ]
+ self.assertEqual( info[ 'id' ], 'one' )
+ self.assertEqual( info[ 'handler' ], ONE_FUNC_NAME )
+ self.assertEqual( info[ 'title' ], 'One Step' )
+ self.failUnless( 'One small step' in info[ 'description' ] )
+
+ def test_parseXML_single_as_ascii( self ):
+
+ registry = self._makeOne().__of__( self.root )
+
+ registry.registerStep( id='two'
+ , handler=TWO_FUNC
+ , title='Two Steps'
+ , description='Texas two step'
+ )
+
+ info_list = registry.parseXML( _SINGLE_EXPORT_XML, encoding='ascii' )
+
+ self.assertEqual( len( info_list ), 1 )
+
+ info = info_list[ 0 ]
+ self.assertEqual( info[ 'id' ], 'one' )
+ self.assertEqual( info[ 'handler' ], ONE_FUNC_NAME )
+ self.assertEqual( info[ 'title' ], 'One Step' )
+ self.failUnless( 'One small step' in info[ 'description' ] )
+
+
+_EMPTY_EXPORT_XML = """\
+<?xml version="1.0"?>
+<export-steps>
+</export-steps>
+"""
+
+_SINGLE_EXPORT_XML = """\
+<?xml version="1.0"?>
+<export-steps>
+ <export-step id="one"
+ handler="%s"
+ title="One Step">
+ One small step
+ </export-step>
+</export-steps>
+""" % ( ONE_FUNC_NAME, )
+
+_ORDERED_EXPORT_XML = """\
+<?xml version="1.0"?>
+<export-steps>
+ <export-step id="one"
+ handler="%s"
+ title="One Step">
+ One small step
+ </export-step>
+ <export-step id="three"
+ handler="%s"
+ title="Three Steps">
+ Gimme three steps
+ </export-step>
+ <export-step id="two"
+ handler="%s"
+ title="Two Steps">
+ Texas two step
+ </export-step>
+</export-steps>
+""" % ( ONE_FUNC_NAME, THREE_FUNC_NAME, TWO_FUNC_NAME )
+
+#==============================================================================
+# ToolsetRegistry tests
+#==============================================================================
+class ToolsetRegistryTests( BaseRegistryTests
+ , ConformsToIToolsetRegistry
+ ):
+
+ def _getTargetClass( self ):
+
+ from Products.GenericSetup.registry import ToolsetRegistry
+ return ToolsetRegistry
+
+ def _initSite( self ):
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+
+ return site
+
+ def test_empty( self ):
+
+ site = self._initSite()
+ configurator = self._makeOne().__of__( site )
+
+ self.assertEqual( len( configurator.listForbiddenTools() ), 0 )
+ self.assertEqual( len( configurator.listRequiredTools() ), 0 )
+ self.assertEqual( len( configurator.listRequiredToolInfo() ), 0 )
+
+ self.assertRaises( KeyError
+ , configurator.getRequiredToolInfo, 'nonesuch' )
+
+ def test_addForbiddenTool_multiple( self ):
+
+ VERBOTTEN = ( 'foo', 'bar', 'bam' )
+
+ site = self._initSite()
+ configurator = self._makeOne().__of__( site )
+
+ for verbotten in VERBOTTEN:
+ configurator.addForbiddenTool( verbotten )
+
+ self.assertEqual( len( configurator.listForbiddenTools() )
+ , len( VERBOTTEN ) )
+
+ for verbotten in configurator.listForbiddenTools():
+ self.failUnless( verbotten in VERBOTTEN )
+
+ def test_addForbiddenTool_duplicate( self ):
+
+ site = self._initSite()
+ configurator = self._makeOne().__of__( site )
+
+ configurator.addForbiddenTool( 'once' )
+ configurator.addForbiddenTool( 'once' )
+
+ self.assertEqual( len( configurator.listForbiddenTools() ), 1 )
+
+ def test_addForbiddenTool_but_required( self ):
+
+ site = self._initSite()
+ configurator = self._makeOne().__of__( site )
+
+ configurator.addRequiredTool( 'required', 'some.dotted.name' )
+
+ self.assertRaises( ValueError
+ , configurator.addForbiddenTool, 'required' )
+
+ def test_addRequiredTool_multiple( self ):
+
+ REQUIRED = ( ( 'one', 'path.to.one' )
+ , ( 'two', 'path.to.two' )
+ , ( 'three', 'path.to.three' )
+ )
+
+ site = self._initSite()
+ configurator = self._makeOne().__of__( site )
+
+ for tool_id, dotted_name in REQUIRED:
+ configurator.addRequiredTool( tool_id, dotted_name )
+
+ self.assertEqual( len( configurator.listRequiredTools() )
+ , len( REQUIRED ) )
+
+ for id in [ x[0] for x in REQUIRED ]:
+ self.failUnless( id in configurator.listRequiredTools() )
+
+ self.assertEqual( len( configurator.listRequiredToolInfo() )
+ , len( REQUIRED ) )
+
+ for tool_id, dotted_name in REQUIRED:
+ info = configurator.getRequiredToolInfo( tool_id )
+ self.assertEqual( info[ 'id' ], tool_id )
+ self.assertEqual( info[ 'class' ], dotted_name )
+
+ def test_addRequiredTool_duplicate( self ):
+
+ site = self._initSite()
+ configurator = self._makeOne().__of__( site )
+
+ configurator.addRequiredTool( 'required', 'some.dotted.name' )
+ configurator.addRequiredTool( 'required', 'another.name' )
+
+ info = configurator.getRequiredToolInfo( 'required' )
+ self.assertEqual( info[ 'id' ], 'required' )
+ self.assertEqual( info[ 'class' ], 'another.name' )
+
+ def test_addRequiredTool_but_forbidden( self ):
+
+ site = self._initSite()
+ configurator = self._makeOne().__of__( site )
+
+ configurator.addForbiddenTool( 'forbidden' )
+
+ self.assertRaises( ValueError
+ , configurator.addRequiredTool
+ , 'forbidden'
+ , 'a.name'
+ )
+
+ def test_generateXML_empty( self ):
+
+ site = self._initSite()
+ configurator = self._makeOne().__of__( site )
+
+ self._compareDOM( configurator.generateXML(), _EMPTY_TOOLSET_XML )
+
+ def test_generateXML_normal( self ):
+
+ site = self._initSite()
+ configurator = self._makeOne().__of__( site )
+
+ configurator.addForbiddenTool( 'doomed' )
+ configurator.addRequiredTool( 'mandatory', 'path.to.one' )
+ configurator.addRequiredTool( 'obligatory', 'path.to.another' )
+
+ configurator.parseXML( _NORMAL_TOOLSET_XML )
+
+ def test_parseXML_empty( self ):
+
+ site = self._initSite()
+ configurator = self._makeOne().__of__( site )
+
+ configurator.parseXML( _EMPTY_TOOLSET_XML )
+
+ self.assertEqual( len( configurator.listForbiddenTools() ), 0 )
+ self.assertEqual( len( configurator.listRequiredTools() ), 0 )
+
+ def test_parseXML_normal( self ):
+
+ site = self._initSite()
+ configurator = self._makeOne().__of__( site )
+
+ configurator.parseXML( _NORMAL_TOOLSET_XML )
+
+ self.assertEqual( len( configurator.listForbiddenTools() ), 1 )
+ self.failUnless( 'doomed' in configurator.listForbiddenTools() )
+
+ self.assertEqual( len( configurator.listRequiredTools() ), 2 )
+
+ self.failUnless( 'mandatory' in configurator.listRequiredTools() )
+ info = configurator.getRequiredToolInfo( 'mandatory' )
+ self.assertEqual( info[ 'class' ], 'path.to.one' )
+
+ self.failUnless( 'obligatory' in configurator.listRequiredTools() )
+ info = configurator.getRequiredToolInfo( 'obligatory' )
+ self.assertEqual( info[ 'class' ], 'path.to.another' )
+
+ def test_parseXML_confused( self ):
+
+ site = self._initSite()
+ configurator = self._makeOne().__of__( site )
+
+ self.assertRaises( ValueError
+ , configurator.parseXML, _CONFUSED_TOOLSET_XML )
+
+
+_EMPTY_TOOLSET_XML = """\
+<?xml version="1.0"?>
+<tool-setup>
+</tool-setup>
+"""
+
+_NORMAL_TOOLSET_XML = """\
+<?xml version="1.0"?>
+<tool-setup>
+ <forbidden tool_id="doomed" />
+ <required tool_id="mandatory" class="path.to.one" />
+ <required tool_id="obligatory" class="path.to.another" />
+</tool-setup>
+"""
+
+_CONFUSED_TOOLSET_XML = """\
+<?xml version="1.0"?>
+<tool-setup>
+ <forbidden tool_id="confused" />
+ <required tool_id="confused" class="path.to.one" />
+</tool-setup>
+"""
+
+class ProfileRegistryTests( BaseRegistryTests
+ , ConformsToIProfileRegistry
+ ):
+
+ def _getTargetClass( self ):
+
+ from Products.GenericSetup.registry import ProfileRegistry
+ return ProfileRegistry
+
+ def test_empty( self ):
+
+ registry = self._makeOne()
+
+ self.assertEqual( len( registry.listProfiles() ), 0 )
+ self.assertEqual( len( registry.listProfiles() ), 0 )
+ self.assertRaises( KeyError, registry.getProfileInfo, 'nonesuch' )
+
+ def test_registerProfile_normal( self ):
+
+ NAME = 'one'
+ TITLE = 'One'
+ DESCRIPTION = 'One profile'
+ PATH = '/path/to/one'
+ PRODUCT = 'TestProduct'
+ PROFILE_TYPE = EXTENSION
+ PROFILE_ID = 'TestProduct:one'
+
+ registry = self._makeOne()
+ registry.registerProfile( NAME
+ , TITLE
+ , DESCRIPTION
+ , PATH
+ , PRODUCT
+ , PROFILE_TYPE
+ )
+
+ self.assertEqual( len( registry.listProfiles() ), 1 )
+ self.assertEqual( len( registry.listProfileInfo() ), 1 )
+
+ info = registry.getProfileInfo( PROFILE_ID )
+
+ self.assertEqual( info[ 'id' ], PROFILE_ID )
+ self.assertEqual( info[ 'title' ], TITLE )
+ self.assertEqual( info[ 'description' ], DESCRIPTION )
+ self.assertEqual( info[ 'path' ], PATH )
+ self.assertEqual( info[ 'product' ], PRODUCT )
+ self.assertEqual( info[ 'type' ], PROFILE_TYPE )
+
+ def test_registerProfile_duplicate( self ):
+
+ PROFILE_ID = 'one'
+ TITLE = 'One'
+ DESCRIPTION = 'One profile'
+ PATH = '/path/to/one'
+
+ registry = self._makeOne()
+ registry.registerProfile( PROFILE_ID, TITLE, DESCRIPTION, PATH )
+ self.assertRaises( KeyError
+ , registry.registerProfile
+ , PROFILE_ID, TITLE, DESCRIPTION, PATH )
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite( ImportStepRegistryTests ),
+ unittest.makeSuite( ExportStepRegistryTests ),
+ unittest.makeSuite( ToolsetRegistryTests ),
+ unittest.makeSuite( ProfileRegistryTests ),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/test_rolemap.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tests/test_rolemap.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tests/test_rolemap.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,787 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" GenericSetup rolemap export / import unit tests
+
+$Id: test_rolemap.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+import unittest
+import Testing
+try:
+ import Zope2
+except ImportError: # BBB: for Zope 2.7
+ import Zope as Zope2
+Zope2.startup()
+
+from OFS.Folder import Folder
+
+from common import BaseRegistryTests
+from common import DummyExportContext
+from common import DummyImportContext
+
+class RolemapConfiguratorTests( BaseRegistryTests ):
+
+ def _getTargetClass( self ):
+
+ from Products.GenericSetup.rolemap import RolemapConfigurator
+ return RolemapConfigurator
+
+ def test_listRoles_normal( self ):
+
+ EXPECTED = [ 'Anonymous', 'Authenticated', 'Manager', 'Owner' ]
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ configurator = self._makeOne( site )
+
+ roles = list( configurator.listRoles() )
+ self.assertEqual( len( roles ), len( EXPECTED ) )
+
+ roles.sort()
+
+ for found, expected in zip( roles, EXPECTED ):
+ self.assertEqual( found, expected )
+
+ def test_listRoles_added( self ):
+
+ EXPECTED = [ 'Anonymous', 'Authenticated', 'Manager', 'Owner', 'ZZZ' ]
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ existing_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
+ existing_roles.append( 'ZZZ' )
+ site.__ac_roles__ = existing_roles
+
+ configurator = self._makeOne( site )
+
+ roles = list( configurator.listRoles() )
+ self.assertEqual( len( roles ), len( EXPECTED ) )
+
+ roles.sort()
+
+ for found, expected in zip( roles, EXPECTED ):
+ self.assertEqual( found, expected )
+
+ def test_listPermissions_nooverrides( self ):
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ configurator = self._makeOne( site )
+
+ self.assertEqual( len( configurator.listPermissions() ), 0 )
+
+ def test_listPermissions_nooverrides( self ):
+
+ site = Folder( id='site' ).__of__( self.root )
+ configurator = self._makeOne( site )
+
+ self.assertEqual( len( configurator.listPermissions() ), 0 )
+
+ def test_listPermissions_acquire( self ):
+
+ ACI = 'Access contents information'
+ ROLES = [ 'Manager', 'Owner' ]
+
+ site = Folder( id='site' ).__of__( self.root )
+ site.manage_permission( ACI, ROLES, acquire=1 )
+ configurator = self._makeOne( site )
+
+ self.assertEqual( len( configurator.listPermissions() ), 1 )
+ info = configurator.listPermissions()[ 0 ]
+ self.assertEqual( info[ 'name' ], ACI )
+ self.assertEqual( info[ 'roles' ], ROLES )
+ self.failUnless( info[ 'acquire' ] )
+
+ def test_listPermissions_no_acquire( self ):
+
+ ACI = 'Access contents information'
+ ROLES = [ 'Manager', 'Owner' ]
+
+ site = Folder( id='site' ).__of__( self.root )
+ site.manage_permission( ACI, ROLES )
+ configurator = self._makeOne( site )
+
+ self.assertEqual( len( configurator.listPermissions() ), 1 )
+ info = configurator.listPermissions()[ 0 ]
+ self.assertEqual( info[ 'name' ], ACI )
+ self.assertEqual( info[ 'roles' ], ROLES )
+ self.failIf( info[ 'acquire' ] )
+
+ def test_generateXML_empty( self ):
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ configurator = self._makeOne( site ).__of__( site )
+
+ self._compareDOM( configurator.generateXML(), _EMPTY_EXPORT )
+
+ def test_generateXML_added_role( self ):
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ existing_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
+ existing_roles.append( 'ZZZ' )
+ site.__ac_roles__ = existing_roles
+ configurator = self._makeOne( site ).__of__( site )
+
+ self._compareDOM( configurator.generateXML(), _ADDED_ROLE_EXPORT )
+
+ def test_generateEXML_acquired_perm( self ):
+
+ ACI = 'Access contents information'
+ ROLES = [ 'Manager', 'Owner' ]
+
+ site = Folder( id='site' ).__of__( self.root )
+ site.manage_permission( ACI, ROLES, acquire=1 )
+ configurator = self._makeOne( site ).__of__( site )
+
+ self._compareDOM( configurator.generateXML(), _ACQUIRED_EXPORT )
+
+ def test_generateEXML_unacquired_perm( self ):
+
+ ACI = 'Access contents information'
+ ROLES = [ 'Manager', 'Owner', 'ZZZ' ]
+
+ site = Folder( id='site' ).__of__( self.root )
+ existing_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
+ existing_roles.append( 'ZZZ' )
+ site.__ac_roles__ = existing_roles
+ site.manage_permission( ACI, ROLES )
+ configurator = self._makeOne( site ).__of__( site )
+
+ self._compareDOM( configurator.generateXML(), _COMBINED_EXPORT )
+
+ def test_generateEXML_unacquired_perm_added_role( self ):
+
+ ACI = 'Access contents information'
+ ROLES = [ 'Manager', 'Owner' ]
+
+ site = Folder( id='site' ).__of__( self.root )
+ site.manage_permission( ACI, ROLES )
+ configurator = self._makeOne( site ).__of__( site )
+
+ self._compareDOM( configurator.generateXML(), _UNACQUIRED_EXPORT )
+
+ def test_parseXML_empty( self ):
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ existing_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
+ configurator = self._makeOne( site )
+
+ rolemap_info = configurator.parseXML( _EMPTY_EXPORT )
+
+ self.assertEqual( len( rolemap_info[ 'roles' ] ), 4 )
+ self.assertEqual( len( rolemap_info[ 'permissions' ] ), 0 )
+
+ def test_parseXML_added_role( self ):
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ configurator = self._makeOne( site )
+
+ rolemap_info = configurator.parseXML( _ADDED_ROLE_EXPORT )
+ roles = rolemap_info[ 'roles' ]
+
+ self.assertEqual( len( roles ), 5 )
+ self.failUnless( 'Anonymous' in roles )
+ self.failUnless( 'Authenticated' in roles )
+ self.failUnless( 'Manager' in roles )
+ self.failUnless( 'Owner' in roles )
+ self.failUnless( 'ZZZ' in roles )
+
+ def test_parseXML_acquired_permission( self ):
+
+ ACI = 'Access contents information'
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ configurator = self._makeOne( site )
+
+ rolemap_info = configurator.parseXML( _ACQUIRED_EXPORT )
+
+ self.assertEqual( len( rolemap_info[ 'permissions' ] ), 1 )
+ permission = rolemap_info[ 'permissions' ][ 0 ]
+
+ self.assertEqual( permission[ 'name' ], ACI )
+ self.failUnless( permission[ 'acquire' ] )
+
+ p_roles = permission[ 'roles' ]
+ self.assertEqual( len( p_roles ), 2 )
+ self.failUnless( 'Manager' in p_roles )
+ self.failUnless( 'Owner' in p_roles )
+
+ def test_parseXML_unacquired_permission( self ):
+
+ ACI = 'Access contents information'
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ configurator = self._makeOne( site )
+
+ rolemap_info = configurator.parseXML( _UNACQUIRED_EXPORT )
+
+ self.assertEqual( len( rolemap_info[ 'permissions' ] ), 1 )
+ permission = rolemap_info[ 'permissions' ][ 0 ]
+
+ self.assertEqual( permission[ 'name' ], ACI )
+ self.failIf( permission[ 'acquire' ] )
+
+ p_roles = permission[ 'roles' ]
+ self.assertEqual( len( p_roles ), 2 )
+ self.failUnless( 'Manager' in p_roles )
+ self.failUnless( 'Owner' in p_roles )
+
+ def test_parseXML_unacquired_permission_added_role( self ):
+
+ ACI = 'Access contents information'
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ configurator = self._makeOne( site )
+
+ rolemap_info = configurator.parseXML( _COMBINED_EXPORT )
+ roles = rolemap_info[ 'roles' ]
+
+ self.assertEqual( len( roles ), 5 )
+ self.failUnless( 'Anonymous' in roles )
+ self.failUnless( 'Authenticated' in roles )
+ self.failUnless( 'Manager' in roles )
+ self.failUnless( 'Owner' in roles )
+ self.failUnless( 'ZZZ' in roles )
+
+ self.assertEqual( len( rolemap_info[ 'permissions' ] ), 1 )
+ permission = rolemap_info[ 'permissions' ][ 0 ]
+
+ self.assertEqual( permission[ 'name' ], ACI )
+ self.failIf( permission[ 'acquire' ] )
+
+ p_roles = permission[ 'roles' ]
+ self.assertEqual( len( p_roles ), 3 )
+ self.failUnless( 'Manager' in p_roles )
+ self.failUnless( 'Owner' in p_roles )
+ self.failUnless( 'ZZZ' in p_roles )
+
+
+
+_EMPTY_EXPORT = """\
+<?xml version="1.0"?>
+<rolemap>
+ <roles>
+ <role name="Anonymous"/>
+ <role name="Authenticated"/>
+ <role name="Manager"/>
+ <role name="Owner"/>
+ </roles>
+ <permissions>
+ </permissions>
+</rolemap>
+"""
+
+_ADDED_ROLE_EXPORT = """\
+<?xml version="1.0"?>
+<rolemap>
+ <roles>
+ <role name="Anonymous"/>
+ <role name="Authenticated"/>
+ <role name="Manager"/>
+ <role name="Owner"/>
+ <role name="ZZZ"/>
+ </roles>
+ <permissions>
+ </permissions>
+</rolemap>
+"""
+
+_ACQUIRED_EXPORT = """\
+<?xml version="1.0"?>
+<rolemap>
+ <roles>
+ <role name="Anonymous"/>
+ <role name="Authenticated"/>
+ <role name="Manager"/>
+ <role name="Owner"/>
+ </roles>
+ <permissions>
+ <permission name="Access contents information"
+ acquire="True">
+ <role name="Manager"/>
+ <role name="Owner"/>
+ </permission>
+ </permissions>
+</rolemap>
+"""
+
+_UNACQUIRED_EXPORT = """\
+<?xml version="1.0"?>
+<rolemap>
+ <roles>
+ <role name="Anonymous"/>
+ <role name="Authenticated"/>
+ <role name="Manager"/>
+ <role name="Owner"/>
+ </roles>
+ <permissions>
+ <permission name="Access contents information"
+ acquire="False">
+ <role name="Manager"/>
+ <role name="Owner"/>
+ </permission>
+ </permissions>
+</rolemap>
+"""
+
+_COMBINED_EXPORT = """\
+<?xml version="1.0"?>
+<rolemap>
+ <roles>
+ <role name="Anonymous"/>
+ <role name="Authenticated"/>
+ <role name="Manager"/>
+ <role name="Owner"/>
+ <role name="ZZZ"/>
+ </roles>
+ <permissions>
+ <permission name="Access contents information"
+ acquire="False">
+ <role name="Manager"/>
+ <role name="Owner"/>
+ <role name="ZZZ"/>
+ </permission>
+ </permissions>
+</rolemap>
+"""
+
+class Test_exportRolemap( BaseRegistryTests ):
+
+ def test_unchanged( self ):
+
+ self.root.site = Folder( 'site' )
+ site = self.root.site
+
+ context = DummyExportContext( site )
+
+ from Products.GenericSetup.rolemap import exportRolemap
+ exportRolemap( context )
+
+ self.assertEqual( len( context._wrote ), 1 )
+ filename, text, content_type = context._wrote[ 0 ]
+ self.assertEqual( filename, 'rolemap.xml' )
+ self._compareDOM( text, _EMPTY_EXPORT )
+ self.assertEqual( content_type, 'text/xml' )
+
+ def test_added_role( self ):
+
+ self.root.site = Folder( 'site' )
+ site = self.root.site
+ existing_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
+ existing_roles.append( 'ZZZ' )
+ site.__ac_roles__ = existing_roles
+
+ context = DummyExportContext( site )
+
+ from Products.GenericSetup.rolemap import exportRolemap
+ exportRolemap( context )
+
+ self.assertEqual( len( context._wrote ), 1 )
+ filename, text, content_type = context._wrote[ 0 ]
+ self.assertEqual( filename, 'rolemap.xml' )
+ self._compareDOM( text, _ADDED_ROLE_EXPORT )
+ self.assertEqual( content_type, 'text/xml' )
+
+
+ def test_acquired_perm( self ):
+
+ ACI = 'Access contents information'
+ ROLES = [ 'Manager', 'Owner' ]
+
+ self.root.site = Folder( 'site' )
+ site = self.root.site
+ site.manage_permission( ACI, ROLES, acquire=1 )
+
+ context = DummyExportContext( site )
+
+ from Products.GenericSetup.rolemap import exportRolemap
+ exportRolemap( context )
+
+ self.assertEqual( len( context._wrote ), 1 )
+ filename, text, content_type = context._wrote[ 0 ]
+ self.assertEqual( filename, 'rolemap.xml' )
+ self._compareDOM( text, _ACQUIRED_EXPORT )
+ self.assertEqual( content_type, 'text/xml' )
+
+ def test_unacquired_perm( self ):
+
+ ACI = 'Access contents information'
+ ROLES = [ 'Manager', 'Owner', 'ZZZ' ]
+
+ self.root.site = Folder( 'site' )
+ site = self.root.site
+ existing_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
+ existing_roles.append( 'ZZZ' )
+ site.__ac_roles__ = existing_roles
+ site.manage_permission( ACI, ROLES )
+
+ context = DummyExportContext( site )
+
+ from Products.GenericSetup.rolemap import exportRolemap
+ exportRolemap( context )
+
+ self.assertEqual( len( context._wrote ), 1 )
+ filename, text, content_type = context._wrote[ 0 ]
+ self.assertEqual( filename, 'rolemap.xml' )
+ self._compareDOM( text, _COMBINED_EXPORT )
+ self.assertEqual( content_type, 'text/xml' )
+
+ def test_unacquired_perm_added_role( self ):
+
+ ACI = 'Access contents information'
+ ROLES = [ 'Manager', 'Owner' ]
+
+ self.root.site = Folder( 'site' )
+ site = self.root.site
+ site.manage_permission( ACI, ROLES )
+
+ context = DummyExportContext( site )
+
+ from Products.GenericSetup.rolemap import exportRolemap
+ exportRolemap( context )
+
+ self.assertEqual( len( context._wrote ), 1 )
+ filename, text, content_type = context._wrote[ 0 ]
+ self.assertEqual( filename, 'rolemap.xml' )
+ self._compareDOM( text, _UNACQUIRED_EXPORT )
+ self.assertEqual( content_type, 'text/xml' )
+
+class Test_importRolemap( BaseRegistryTests ):
+
+ def test_empty_default_purge( self ):
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ original_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
+ modified_roles = original_roles[:]
+ modified_roles.append( 'ZZZ' )
+ site.__ac_roles__ = modified_roles
+
+ context = DummyImportContext( site )
+ context._files[ 'rolemap.xml' ] = _EMPTY_EXPORT
+
+ from Products.GenericSetup.rolemap import importRolemap
+ importRolemap( context )
+
+ new_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
+
+ original_roles.sort()
+ new_roles.sort()
+
+ self.assertEqual( original_roles, new_roles )
+
+ def test_empty_explicit_purge( self ):
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ original_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
+ modified_roles = original_roles[:]
+ modified_roles.append( 'ZZZ' )
+ site.__ac_roles__ = modified_roles
+
+ context = DummyImportContext( site, True )
+ context._files[ 'rolemap.xml' ] = _EMPTY_EXPORT
+
+ from Products.GenericSetup.rolemap import importRolemap
+ importRolemap( context )
+
+ new_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
+
+ original_roles.sort()
+ new_roles.sort()
+
+ self.assertEqual( original_roles, new_roles )
+
+ def test_empty_skip_purge( self ):
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ original_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
+ modified_roles = original_roles[:]
+ modified_roles.append( 'ZZZ' )
+ site.__ac_roles__ = modified_roles
+
+ context = DummyImportContext( site, False )
+ context._files[ 'rolemap.xml' ] = _EMPTY_EXPORT
+
+ from Products.GenericSetup.rolemap import importRolemap
+ importRolemap( context )
+
+ new_roles = list( getattr( site, '__ac_roles__', [] ) )[:]
+
+ modified_roles.sort()
+ new_roles.sort()
+
+ self.assertEqual( modified_roles, new_roles )
+
+ def test_acquired_permission_explicit_purge( self ):
+
+ ACI = 'Access contents information'
+ VIEW = 'View'
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ site.manage_permission( ACI, () )
+ site.manage_permission( VIEW, () )
+
+ existing_allowed = [ x[ 'name' ]
+ for x in site.rolesOfPermission( ACI )
+ if x[ 'selected' ] ]
+
+ self.assertEqual( existing_allowed, [] )
+
+ self.failIf( site.acquiredRolesAreUsedBy( ACI ) )
+ self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
+
+ context = DummyImportContext( site, True )
+ context._files[ 'rolemap.xml' ] = _ACQUIRED_EXPORT
+
+ from Products.GenericSetup.rolemap import importRolemap
+ importRolemap( context )
+
+ new_allowed = [ x[ 'name' ]
+ for x in site.rolesOfPermission( ACI )
+ if x[ 'selected' ] ]
+
+ self.assertEqual( new_allowed, [ 'Manager', 'Owner' ] )
+
+ # ACI is overwritten by XML, but VIEW was purged
+ self.failUnless( site.acquiredRolesAreUsedBy( ACI ) )
+ self.failUnless( site.acquiredRolesAreUsedBy( VIEW ) )
+
+ def test_acquired_permission_no_purge( self ):
+
+ ACI = 'Access contents information'
+ VIEW = 'View'
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ site.manage_permission( ACI, () )
+ site.manage_permission( VIEW, () )
+
+ existing_allowed = [ x[ 'name' ]
+ for x in site.rolesOfPermission( ACI )
+ if x[ 'selected' ] ]
+
+ self.assertEqual( existing_allowed, [] )
+
+ self.failIf( site.acquiredRolesAreUsedBy( ACI ) )
+
+ context = DummyImportContext( site, False )
+ context._files[ 'rolemap.xml' ] = _ACQUIRED_EXPORT
+
+ from Products.GenericSetup.rolemap import importRolemap
+ importRolemap( context )
+
+ new_allowed = [ x[ 'name' ]
+ for x in site.rolesOfPermission( ACI )
+ if x[ 'selected' ] ]
+
+ self.assertEqual( new_allowed, [ 'Manager', 'Owner' ] )
+
+ # ACI is overwritten by XML, but VIEW is not
+ self.failUnless( site.acquiredRolesAreUsedBy( ACI ) )
+ self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
+
+ def test_unacquired_permission_explicit_purge( self ):
+
+ ACI = 'Access contents information'
+ VIEW = 'View'
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ site.manage_permission( VIEW, () )
+
+ existing_allowed = [ x[ 'name' ]
+ for x in site.rolesOfPermission( ACI )
+ if x[ 'selected' ] ]
+
+ self.assertEqual( existing_allowed, [ 'Manager' ] )
+
+ self.failUnless( site.acquiredRolesAreUsedBy( ACI ) )
+ self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
+
+ context = DummyImportContext( site, True )
+ context._files[ 'rolemap.xml' ] = _UNACQUIRED_EXPORT
+
+ from Products.GenericSetup.rolemap import importRolemap
+ importRolemap( context )
+
+ new_allowed = [ x[ 'name' ]
+ for x in site.rolesOfPermission( ACI )
+ if x[ 'selected' ] ]
+
+ self.assertEqual( new_allowed, [ 'Manager', 'Owner' ] )
+
+ self.failIf( site.acquiredRolesAreUsedBy( ACI ) )
+ self.failUnless( site.acquiredRolesAreUsedBy( VIEW ) )
+
+ def test_unacquired_permission_skip_purge( self ):
+
+ ACI = 'Access contents information'
+ VIEW = 'View'
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ site.manage_permission( VIEW, () )
+
+ existing_allowed = [ x[ 'name' ]
+ for x in site.rolesOfPermission( ACI )
+ if x[ 'selected' ] ]
+
+ self.assertEqual( existing_allowed, [ 'Manager' ] )
+
+ self.failUnless( site.acquiredRolesAreUsedBy( ACI ) )
+ self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
+
+ context = DummyImportContext( site, False )
+ context._files[ 'rolemap.xml' ] = _UNACQUIRED_EXPORT
+
+ from Products.GenericSetup.rolemap import importRolemap
+ importRolemap( context )
+
+ new_allowed = [ x[ 'name' ]
+ for x in site.rolesOfPermission( ACI )
+ if x[ 'selected' ] ]
+
+ self.assertEqual( new_allowed, [ 'Manager', 'Owner' ] )
+
+ self.failIf( site.acquiredRolesAreUsedBy( ACI ) )
+ self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
+
+ def test_unacquired_permission_added_role_explicit_purge( self ):
+
+ ACI = 'Access contents information'
+ VIEW = 'View'
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ site.manage_permission( VIEW, () )
+
+ existing_allowed = [ x[ 'name' ]
+ for x in site.rolesOfPermission( ACI )
+ if x[ 'selected' ] ]
+
+ self.assertEqual( existing_allowed, [ 'Manager' ] )
+
+ self.failUnless( site.acquiredRolesAreUsedBy( ACI ) )
+ self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
+
+ self.failIf( site._has_user_defined_role( 'ZZZ' ) )
+
+ context = DummyImportContext( site, True )
+ context._files[ 'rolemap.xml' ] = _COMBINED_EXPORT
+
+ from Products.GenericSetup.rolemap import importRolemap
+ importRolemap( context )
+
+ self.failUnless( site._has_user_defined_role( 'ZZZ' ) )
+
+ new_allowed = [ x[ 'name' ]
+ for x in site.rolesOfPermission( ACI )
+ if x[ 'selected' ] ]
+
+ self.assertEqual( new_allowed, [ 'Manager', 'Owner', 'ZZZ' ] )
+
+ self.failIf( site.acquiredRolesAreUsedBy( ACI ) )
+ self.failUnless( site.acquiredRolesAreUsedBy( VIEW ) )
+
+ def test_unacquired_permission_added_role_skip_purge( self ):
+
+ ACI = 'Access contents information'
+ VIEW = 'View'
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ site.manage_permission( VIEW, () )
+
+ existing_allowed = [ x[ 'name' ]
+ for x in site.rolesOfPermission( ACI )
+ if x[ 'selected' ] ]
+
+ self.assertEqual( existing_allowed, [ 'Manager' ] )
+
+ self.failUnless( site.acquiredRolesAreUsedBy( ACI ) )
+ self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
+
+ self.failIf( site._has_user_defined_role( 'ZZZ' ) )
+
+ context = DummyImportContext( site, False )
+ context._files[ 'rolemap.xml' ] = _COMBINED_EXPORT
+
+ from Products.GenericSetup.rolemap import importRolemap
+ importRolemap( context )
+
+ self.failUnless( site._has_user_defined_role( 'ZZZ' ) )
+
+ new_allowed = [ x[ 'name' ]
+ for x in site.rolesOfPermission( ACI )
+ if x[ 'selected' ] ]
+
+ self.assertEqual( new_allowed, [ 'Manager', 'Owner', 'ZZZ' ] )
+
+ self.failIf( site.acquiredRolesAreUsedBy( ACI ) )
+ self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
+
+ def test_unacquired_permission_added_role_skip_purge_encode_ascii( self ):
+
+ ACI = 'Access contents information'
+ VIEW = 'View'
+
+ self.root.site = Folder( id='site' )
+ site = self.root.site
+ site.manage_permission( VIEW, () )
+
+ existing_allowed = [ x[ 'name' ]
+ for x in site.rolesOfPermission( ACI )
+ if x[ 'selected' ] ]
+
+ self.assertEqual( existing_allowed, [ 'Manager' ] )
+
+ self.failUnless( site.acquiredRolesAreUsedBy( ACI ) )
+ self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
+
+ self.failIf( site._has_user_defined_role( 'ZZZ' ) )
+
+ context = DummyImportContext( site, False, encoding='ascii' )
+ context._files[ 'rolemap.xml' ] = _COMBINED_EXPORT
+
+ from Products.GenericSetup.rolemap import importRolemap
+ importRolemap( context )
+
+ self.failUnless( site._has_user_defined_role( 'ZZZ' ) )
+
+ new_allowed = [ x[ 'name' ]
+ for x in site.rolesOfPermission( ACI )
+ if x[ 'selected' ] ]
+
+ self.assertEqual( new_allowed, [ 'Manager', 'Owner', 'ZZZ' ] )
+
+ self.failIf( site.acquiredRolesAreUsedBy( ACI ) )
+ self.failIf( site.acquiredRolesAreUsedBy( VIEW ) )
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite( RolemapConfiguratorTests ),
+ unittest.makeSuite( Test_exportRolemap ),
+ unittest.makeSuite( Test_importRolemap ),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/test_tool.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tests/test_tool.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tests/test_tool.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,921 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Unit tests for GenericSetup tool.
+
+$Id: test_tool.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+import unittest
+import Testing
+try:
+ import Zope2
+except ImportError: # BBB: for Zope 2.7
+ import Zope as Zope2
+Zope2.startup()
+
+from StringIO import StringIO
+
+from Acquisition import aq_base
+from OFS.Folder import Folder
+
+from Products.GenericSetup import profile_registry
+
+from common import DOMComparator
+from common import DummyExportContext
+from common import DummyImportContext
+from common import FilesystemTestBase
+
+#from Products.CMFCore.tests.base.testcase import SecurityRequestTest
+from Testing.ZopeTestCase import ZopeTestCase
+from common import SecurityRequestTest
+from common import TarballTester
+from conformance import ConformsToISetupTool
+
+
+class SetupToolTests( FilesystemTestBase
+ , TarballTester
+ , ConformsToISetupTool
+ ):
+
+ _PROFILE_PATH = '/tmp/STT_test'
+
+ def setUp( self ):
+
+ FilesystemTestBase.setUp( self )
+ self._profile_registry_info = profile_registry._profile_info
+ self._profile_registry_ids = profile_registry._profile_ids
+ profile_registry.clear()
+
+ def tearDown( self ):
+
+ profile_registry._profile_info = self._profile_registry_info
+ profile_registry._profile_ids = self._profile_registry_ids
+ FilesystemTestBase.tearDown( self )
+
+ def _getTargetClass( self ):
+
+ from Products.GenericSetup.tool import SetupTool
+ return SetupTool
+
+ def _makeOne( self, *args, **kw ):
+
+ return self._getTargetClass()( *args, **kw )
+
+ def _makeSite( self, title="Don't care" ):
+
+ site = Folder()
+ site._setId( 'site' )
+ site.title = title
+
+ self.root._setObject( 'site', site )
+ return self.root._getOb( 'site' )
+
+ def test_empty( self ):
+
+ tool = self._makeOne()
+
+ self.assertEqual( tool.getImportContextID(), '' )
+
+ import_registry = tool.getImportStepRegistry()
+ self.assertEqual( len( import_registry.listSteps() ), 0 )
+
+ export_registry = tool.getExportStepRegistry()
+ export_steps = export_registry.listSteps()
+ self.assertEqual( len( export_steps ), 1 )
+ self.assertEqual( export_steps[ 0 ], 'step_registries' )
+
+ toolset_registry = tool.getToolsetRegistry()
+ self.assertEqual( len( toolset_registry.listForbiddenTools() ), 0 )
+ self.assertEqual( len( toolset_registry.listRequiredTools() ), 0 )
+
+ def test_getImportContextID( self ):
+
+ from Products.GenericSetup.tool import IMPORT_STEPS_XML
+ from Products.GenericSetup.tool import EXPORT_STEPS_XML
+ from Products.GenericSetup.tool import TOOLSET_XML
+ from test_registry import _EMPTY_IMPORT_XML
+ from test_registry import _EMPTY_EXPORT_XML
+ from test_registry import _EMPTY_TOOLSET_XML
+ from common import _makeTestFile
+
+ tool = self._makeOne()
+
+ _makeTestFile( IMPORT_STEPS_XML
+ , self._PROFILE_PATH
+ , _EMPTY_IMPORT_XML
+ )
+
+ _makeTestFile( EXPORT_STEPS_XML
+ , self._PROFILE_PATH
+ , _EMPTY_EXPORT_XML
+ )
+
+ _makeTestFile( TOOLSET_XML
+ , self._PROFILE_PATH
+ , _EMPTY_TOOLSET_XML
+ )
+
+ profile_registry.registerProfile('foo', 'Foo', '', self._PROFILE_PATH)
+ tool.setImportContext('profile-other:foo')
+
+ self.assertEqual( tool.getImportContextID(), 'profile-other:foo' )
+
+ def test_setImportContext_invalid( self ):
+
+ tool = self._makeOne()
+
+ self.assertRaises( KeyError
+ , tool.setImportContext
+ , 'profile-foo'
+ )
+
+ def test_setImportContext( self ):
+
+ from Products.GenericSetup.tool import IMPORT_STEPS_XML
+ from Products.GenericSetup.tool import EXPORT_STEPS_XML
+ from Products.GenericSetup.tool import TOOLSET_XML
+ from test_registry import _SINGLE_IMPORT_XML
+ from test_registry import _SINGLE_EXPORT_XML
+ from test_registry import _NORMAL_TOOLSET_XML
+ from test_registry import ONE_FUNC
+ from common import _makeTestFile
+
+ tool = self._makeOne()
+ tool.getExportStepRegistry().clear()
+
+ _makeTestFile( IMPORT_STEPS_XML
+ , self._PROFILE_PATH
+ , _SINGLE_IMPORT_XML
+ )
+
+ _makeTestFile( EXPORT_STEPS_XML
+ , self._PROFILE_PATH
+ , _SINGLE_EXPORT_XML
+ )
+
+ _makeTestFile( TOOLSET_XML
+ , self._PROFILE_PATH
+ , _NORMAL_TOOLSET_XML
+ )
+
+ profile_registry.registerProfile('foo', 'Foo', '', self._PROFILE_PATH)
+ tool.setImportContext('profile-other:foo')
+
+ self.assertEqual( tool.getImportContextID(), 'profile-other:foo' )
+
+ import_registry = tool.getImportStepRegistry()
+ self.assertEqual( len( import_registry.listSteps() ), 1 )
+ self.failUnless( 'one' in import_registry.listSteps() )
+ info = import_registry.getStepMetadata( 'one' )
+ self.assertEqual( info[ 'id' ], 'one' )
+ self.assertEqual( info[ 'title' ], 'One Step' )
+ self.assertEqual( info[ 'version' ], '1' )
+ self.failUnless( 'One small step' in info[ 'description' ] )
+ self.assertEqual( info[ 'handler' ]
+ , 'Products.GenericSetup.tests.test_registry.ONE_FUNC' )
+
+ self.assertEqual( import_registry.getStep( 'one' ), ONE_FUNC )
+
+ export_registry = tool.getExportStepRegistry()
+ self.assertEqual( len( export_registry.listSteps() ), 1 )
+ self.failUnless( 'one' in import_registry.listSteps() )
+ info = export_registry.getStepMetadata( 'one' )
+ self.assertEqual( info[ 'id' ], 'one' )
+ self.assertEqual( info[ 'title' ], 'One Step' )
+ self.failUnless( 'One small step' in info[ 'description' ] )
+ self.assertEqual( info[ 'handler' ]
+ , 'Products.GenericSetup.tests.test_registry.ONE_FUNC' )
+
+ self.assertEqual( export_registry.getStep( 'one' ), ONE_FUNC )
+
+ toolset = tool.getToolsetRegistry()
+ self.assertEqual( len( toolset.listForbiddenTools() ), 1 )
+ self.failUnless( 'doomed' in toolset.listForbiddenTools() )
+ self.assertEqual( len( toolset.listRequiredTools() ), 2 )
+ self.failUnless( 'mandatory' in toolset.listRequiredTools() )
+ info = toolset.getRequiredToolInfo( 'mandatory' )
+ self.assertEqual( info[ 'class' ], 'path.to.one' )
+ self.failUnless( 'obligatory' in toolset.listRequiredTools() )
+ info = toolset.getRequiredToolInfo( 'obligatory' )
+ self.assertEqual( info[ 'class' ], 'path.to.another' )
+
+ def test_runImportStep_nonesuch( self ):
+
+ site = self._makeSite()
+
+ tool = self._makeOne().__of__( site )
+
+ self.assertRaises( ValueError, tool.runImportStep, 'nonesuch' )
+
+ def test_runImportStep_simple( self ):
+
+ TITLE = 'original title'
+ site = self._makeSite( TITLE )
+
+ tool = self._makeOne().__of__( site )
+
+ registry = tool.getImportStepRegistry()
+ registry.registerStep( 'simple', '1', _uppercaseSiteTitle )
+
+ result = tool.runImportStep( 'simple' )
+
+ self.assertEqual( len( result[ 'steps' ] ), 1 )
+
+ self.assertEqual( result[ 'steps' ][ 0 ], 'simple' )
+ self.assertEqual( result[ 'messages' ][ 'simple' ]
+ , 'Uppercased title' )
+
+ self.assertEqual( site.title, TITLE.upper() )
+
+ def test_runImportStep_dependencies( self ):
+
+ TITLE = 'original title'
+ site = self._makeSite( TITLE )
+
+ tool = self._makeOne().__of__( site )
+
+ registry = tool.getImportStepRegistry()
+ registry.registerStep( 'dependable', '1', _underscoreSiteTitle )
+ registry.registerStep( 'dependent', '1'
+ , _uppercaseSiteTitle, ( 'dependable', ) )
+
+ result = tool.runImportStep( 'dependent' )
+
+ self.assertEqual( len( result[ 'steps' ] ), 2 )
+
+ self.assertEqual( result[ 'steps' ][ 0 ], 'dependable' )
+ self.assertEqual( result[ 'messages' ][ 'dependable' ]
+ , 'Underscored title' )
+
+ self.assertEqual( result[ 'steps' ][ 1 ], 'dependent' )
+ self.assertEqual( result[ 'messages' ][ 'dependent' ]
+ , 'Uppercased title' )
+ self.assertEqual( site.title, TITLE.replace( ' ', '_' ).upper() )
+
+ def test_runImportStep_skip_dependencies( self ):
+
+ TITLE = 'original title'
+ site = self._makeSite( TITLE )
+
+ tool = self._makeOne().__of__( site )
+
+ registry = tool.getImportStepRegistry()
+ registry.registerStep( 'dependable', '1', _underscoreSiteTitle )
+ registry.registerStep( 'dependent', '1'
+ , _uppercaseSiteTitle, ( 'dependable', ) )
+
+ result = tool.runImportStep( 'dependent', run_dependencies=False )
+
+ self.assertEqual( len( result[ 'steps' ] ), 1 )
+
+ self.assertEqual( result[ 'steps' ][ 0 ], 'dependent' )
+ self.assertEqual( result[ 'messages' ][ 'dependent' ]
+ , 'Uppercased title' )
+
+ self.assertEqual( site.title, TITLE.upper() )
+
+ def test_runImportStep_default_purge( self ):
+
+ site = self._makeSite()
+
+ tool = self._makeOne().__of__( site )
+ registry = tool.getImportStepRegistry()
+ registry.registerStep( 'purging', '1', _purgeIfRequired )
+
+ result = tool.runImportStep( 'purging' )
+
+ self.assertEqual( len( result[ 'steps' ] ), 1 )
+ self.assertEqual( result[ 'steps' ][ 0 ], 'purging' )
+ self.assertEqual( result[ 'messages' ][ 'purging' ], 'Purged' )
+ self.failUnless( site.purged )
+
+ def test_runImportStep_explicit_purge( self ):
+
+ site = self._makeSite()
+
+ tool = self._makeOne().__of__( site )
+ registry = tool.getImportStepRegistry()
+ registry.registerStep( 'purging', '1', _purgeIfRequired )
+
+ result = tool.runImportStep( 'purging', purge_old=True )
+
+ self.assertEqual( len( result[ 'steps' ] ), 1 )
+ self.assertEqual( result[ 'steps' ][ 0 ], 'purging' )
+ self.assertEqual( result[ 'messages' ][ 'purging' ], 'Purged' )
+ self.failUnless( site.purged )
+
+ def test_runImportStep_skip_purge( self ):
+
+ site = self._makeSite()
+
+ tool = self._makeOne().__of__( site )
+ registry = tool.getImportStepRegistry()
+ registry.registerStep( 'purging', '1', _purgeIfRequired )
+
+ result = tool.runImportStep( 'purging', purge_old=False )
+
+ self.assertEqual( len( result[ 'steps' ] ), 1 )
+ self.assertEqual( result[ 'steps' ][ 0 ], 'purging' )
+ self.assertEqual( result[ 'messages' ][ 'purging' ], 'Unpurged' )
+ self.failIf( site.purged )
+
+ def test_runImportStep_consistent_context( self ):
+
+ site = self._makeSite()
+
+ tool = self._makeOne().__of__( site )
+
+ registry = tool.getImportStepRegistry()
+ registry.registerStep( 'purging', '1', _purgeIfRequired )
+ registry.registerStep( 'dependent', '1'
+ , _uppercaseSiteTitle, ( 'purging', ) )
+
+ result = tool.runImportStep( 'dependent', purge_old=False )
+ self.failIf( site.purged )
+
+ def test_runAllImportSteps_empty( self ):
+
+ site = self._makeSite()
+ tool = self._makeOne().__of__( site )
+
+ result = tool.runAllImportSteps()
+
+ self.assertEqual( len( result[ 'steps' ] ), 0 )
+
+ def test_runAllImportSteps_sorted_default_purge( self ):
+
+ TITLE = 'original title'
+ site = self._makeSite( TITLE )
+ tool = self._makeOne().__of__( site )
+
+ registry = tool.getImportStepRegistry()
+ registry.registerStep( 'dependable', '1'
+ , _underscoreSiteTitle, ( 'purging', ) )
+ registry.registerStep( 'dependent', '1'
+ , _uppercaseSiteTitle, ( 'dependable', ) )
+ registry.registerStep( 'purging', '1'
+ , _purgeIfRequired )
+
+ result = tool.runAllImportSteps()
+
+ self.assertEqual( len( result[ 'steps' ] ), 3 )
+
+ self.assertEqual( result[ 'steps' ][ 0 ], 'purging' )
+ self.assertEqual( result[ 'messages' ][ 'purging' ]
+ , 'Purged' )
+
+ self.assertEqual( result[ 'steps' ][ 1 ], 'dependable' )
+ self.assertEqual( result[ 'messages' ][ 'dependable' ]
+ , 'Underscored title' )
+
+ self.assertEqual( result[ 'steps' ][ 2 ], 'dependent' )
+ self.assertEqual( result[ 'messages' ][ 'dependent' ]
+ , 'Uppercased title' )
+
+ self.assertEqual( site.title, TITLE.replace( ' ', '_' ).upper() )
+ self.failUnless( site.purged )
+
+ def test_runAllImportSteps_sorted_explicit_purge( self ):
+
+ site = self._makeSite()
+ tool = self._makeOne().__of__( site )
+
+ registry = tool.getImportStepRegistry()
+ registry.registerStep( 'dependable', '1'
+ , _underscoreSiteTitle, ( 'purging', ) )
+ registry.registerStep( 'dependent', '1'
+ , _uppercaseSiteTitle, ( 'dependable', ) )
+ registry.registerStep( 'purging', '1'
+ , _purgeIfRequired )
+
+ result = tool.runAllImportSteps( purge_old=True )
+
+ self.assertEqual( len( result[ 'steps' ] ), 3 )
+
+ self.assertEqual( result[ 'steps' ][ 0 ], 'purging' )
+ self.assertEqual( result[ 'messages' ][ 'purging' ]
+ , 'Purged' )
+
+ self.assertEqual( result[ 'steps' ][ 1 ], 'dependable' )
+ self.assertEqual( result[ 'steps' ][ 2 ], 'dependent' )
+ self.failUnless( site.purged )
+
+ def test_runAllImportSteps_sorted_skip_purge( self ):
+
+ site = self._makeSite()
+ tool = self._makeOne().__of__( site )
+
+ registry = tool.getImportStepRegistry()
+ registry.registerStep( 'dependable', '1'
+ , _underscoreSiteTitle, ( 'purging', ) )
+ registry.registerStep( 'dependent', '1'
+ , _uppercaseSiteTitle, ( 'dependable', ) )
+ registry.registerStep( 'purging', '1'
+ , _purgeIfRequired )
+
+ result = tool.runAllImportSteps( purge_old=False )
+
+ self.assertEqual( len( result[ 'steps' ] ), 3 )
+
+ self.assertEqual( result[ 'steps' ][ 0 ], 'purging' )
+ self.assertEqual( result[ 'messages' ][ 'purging' ]
+ , 'Unpurged' )
+
+ self.assertEqual( result[ 'steps' ][ 1 ], 'dependable' )
+ self.assertEqual( result[ 'steps' ][ 2 ], 'dependent' )
+ self.failIf( site.purged )
+
+ def test_runExportStep_nonesuch( self ):
+
+ site = self._makeSite()
+ tool = self._makeOne().__of__( site )
+
+ self.assertRaises( ValueError, tool.runExportStep, 'nonesuch' )
+
+ def test_runExportStep_step_registry( self ):
+
+ from test_registry import _EMPTY_IMPORT_XML
+
+ site = self._makeSite()
+ site.setup_tool = self._makeOne()
+ tool = site.setup_tool
+
+ result = tool.runExportStep( 'step_registries' )
+
+ self.assertEqual( len( result[ 'steps' ] ), 1 )
+ self.assertEqual( result[ 'steps' ][ 0 ], 'step_registries' )
+ self.assertEqual( result[ 'messages' ][ 'step_registries' ]
+ , 'Step registries exported'
+ )
+ fileish = StringIO( result[ 'tarball' ] )
+
+ self._verifyTarballContents( fileish, [ 'import_steps.xml'
+ , 'export_steps.xml'
+ ] )
+ self._verifyTarballEntryXML( fileish, 'import_steps.xml'
+ , _EMPTY_IMPORT_XML )
+ self._verifyTarballEntryXML( fileish, 'export_steps.xml'
+ , _DEFAULT_STEP_REGISTRIES_EXPORT_XML )
+
+ def test_runAllExportSteps_default( self ):
+
+ from test_registry import _EMPTY_IMPORT_XML
+
+ site = self._makeSite()
+ site.setup_tool = self._makeOne()
+ tool = site.setup_tool
+
+ result = tool.runAllExportSteps()
+
+ self.assertEqual( len( result[ 'steps' ] ), 1 )
+ self.assertEqual( result[ 'steps' ][ 0 ], 'step_registries' )
+ self.assertEqual( result[ 'messages' ][ 'step_registries' ]
+ , 'Step registries exported'
+ )
+ fileish = StringIO( result[ 'tarball' ] )
+
+ self._verifyTarballContents( fileish, [ 'import_steps.xml'
+ , 'export_steps.xml'
+ ] )
+ self._verifyTarballEntryXML( fileish, 'import_steps.xml'
+ , _EMPTY_IMPORT_XML )
+ self._verifyTarballEntryXML( fileish, 'export_steps.xml'
+ , _DEFAULT_STEP_REGISTRIES_EXPORT_XML )
+
+ def test_runAllExportSteps_extras( self ):
+
+ from test_registry import _EMPTY_IMPORT_XML
+
+ site = self._makeSite()
+ site.setup_tool = self._makeOne()
+ tool = site.setup_tool
+
+ import_reg = tool.getImportStepRegistry()
+ import_reg.registerStep( 'dependable', '1'
+ , _underscoreSiteTitle, ( 'purging', ) )
+ import_reg.registerStep( 'dependent', '1'
+ , _uppercaseSiteTitle, ( 'dependable', ) )
+ import_reg.registerStep( 'purging', '1'
+ , _purgeIfRequired )
+
+ export_reg = tool.getExportStepRegistry()
+ export_reg.registerStep( 'properties'
+ , _exportPropertiesINI )
+
+ result = tool.runAllExportSteps()
+
+ self.assertEqual( len( result[ 'steps' ] ), 2 )
+
+ self.failUnless( 'properties' in result[ 'steps' ] )
+ self.assertEqual( result[ 'messages' ][ 'properties' ]
+ , 'Exported properties'
+ )
+
+ self.failUnless( 'step_registries' in result[ 'steps' ] )
+ self.assertEqual( result[ 'messages' ][ 'step_registries' ]
+ , 'Step registries exported'
+ )
+
+ fileish = StringIO( result[ 'tarball' ] )
+
+ self._verifyTarballContents( fileish, [ 'import_steps.xml'
+ , 'export_steps.xml'
+ , 'properties.ini'
+ ] )
+ self._verifyTarballEntryXML( fileish, 'import_steps.xml'
+ , _EXTRAS_STEP_REGISTRIES_IMPORT_XML )
+ self._verifyTarballEntryXML( fileish, 'export_steps.xml'
+ , _EXTRAS_STEP_REGISTRIES_EXPORT_XML )
+ self._verifyTarballEntry( fileish, 'properties.ini'
+ , _PROPERTIES_INI % site.title )
+
+ def test_createSnapshot_default( self ):
+
+ from test_registry import _EMPTY_IMPORT_XML
+
+ _EXPECTED = [ ( 'import_steps.xml', _EMPTY_IMPORT_XML )
+ , ( 'export_steps.xml'
+ , _DEFAULT_STEP_REGISTRIES_EXPORT_XML
+ )
+ ]
+
+ site = self._makeSite()
+ site.setup_tool = self._makeOne()
+ tool = site.setup_tool
+
+ self.assertEqual( len( tool.listSnapshotInfo() ), 0 )
+
+ result = tool.createSnapshot( 'default' )
+
+ self.assertEqual( len( result[ 'steps' ] ), 1 )
+ self.assertEqual( result[ 'steps' ][ 0 ], 'step_registries' )
+ self.assertEqual( result[ 'messages' ][ 'step_registries' ]
+ , 'Step registries exported'
+ )
+
+ snapshot = result[ 'snapshot' ]
+
+ self.assertEqual( len( snapshot.objectIds() ), len( _EXPECTED ) )
+
+ for id in [ x[0] for x in _EXPECTED ]:
+ self.failUnless( id in snapshot.objectIds() )
+
+ def normalize_xml(xml):
+ # using this might mask a real problem on windows, but so far the
+ # different newlines just caused problems in this test
+ lines = [ line for line in xml.splitlines() if line ]
+ return '\n'.join(lines) + '\n'
+
+ fileobj = snapshot._getOb( 'import_steps.xml' )
+ self.assertEqual( normalize_xml( fileobj.read() ),
+ _EMPTY_IMPORT_XML )
+
+ fileobj = snapshot._getOb( 'export_steps.xml' )
+
+ self.assertEqual( normalize_xml( fileobj.read() ),
+ _DEFAULT_STEP_REGISTRIES_EXPORT_XML )
+
+ self.assertEqual( len( tool.listSnapshotInfo() ), 1 )
+
+ info = tool.listSnapshotInfo()[ 0 ]
+
+ self.assertEqual( info[ 'id' ], 'default' )
+ self.assertEqual( info[ 'title' ], 'default' )
+
+
+_DEFAULT_STEP_REGISTRIES_EXPORT_XML = """\
+<?xml version="1.0"?>
+<export-steps>
+ <export-step id="step_registries"
+ handler="Products.GenericSetup.tool.exportStepRegistries"
+ title="Export import / export steps.">
+
+ </export-step>
+</export-steps>
+"""
+
+_EXTRAS_STEP_REGISTRIES_EXPORT_XML = """\
+<?xml version="1.0"?>
+<export-steps>
+ <export-step
+ id="properties"
+ handler="Products.GenericSetup.tests.test_tool._exportPropertiesINI"
+ title="properties">
+
+ </export-step>
+ <export-step
+ id="step_registries"
+ handler="Products.GenericSetup.tool.exportStepRegistries"
+ title="Export import / export steps.">
+
+ </export-step>
+</export-steps>
+"""
+
+_EXTRAS_STEP_REGISTRIES_IMPORT_XML = """\
+<?xml version="1.0"?>
+<import-steps>
+ <import-step
+ id="dependable"
+ version="1"
+ handler="Products.GenericSetup.tests.test_tool._underscoreSiteTitle"
+ title="dependable">
+ <dependency step="purging" />
+
+ </import-step>
+ <import-step
+ id="dependent"
+ version="1"
+ handler="Products.GenericSetup.tests.test_tool._uppercaseSiteTitle"
+ title="dependent">
+ <dependency step="dependable" />
+
+ </import-step>
+ <import-step
+ id="purging"
+ version="1"
+ handler="Products.GenericSetup.tests.test_tool._purgeIfRequired"
+ title="purging">
+
+ </import-step>
+</import-steps>
+"""
+
+_PROPERTIES_INI = """\
+[Default]
+Title=%s
+"""
+
+def _underscoreSiteTitle( context ):
+
+ site = context.getSite()
+ site.title = site.title.replace( ' ', '_' )
+ return 'Underscored title'
+
+def _uppercaseSiteTitle( context ):
+
+ site = context.getSite()
+ site.title = site.title.upper()
+ return 'Uppercased title'
+
+def _purgeIfRequired( context ):
+
+ site = context.getSite()
+ purged = site.purged = context.shouldPurge()
+ return purged and 'Purged' or 'Unpurged'
+
+def _exportPropertiesINI( context ):
+
+ site = context.getSite()
+ text = _PROPERTIES_INI % site.title
+
+ context.writeDataFile( 'properties.ini', text, 'text/plain' )
+
+ return 'Exported properties'
+
+class _ToolsetSetup( SecurityRequestTest ):
+
+ def _initSite( self ):
+
+ from Products.GenericSetup.tool import SetupTool
+ site = Folder()
+ site._setId( 'site' )
+ self.root._setObject( 'site', site )
+ site = self.root._getOb( 'site' )
+ site._setObject( 'setup_tool', SetupTool() )
+ return site
+
+class Test_exportToolset( _ToolsetSetup
+ , DOMComparator
+ ):
+
+ def test_empty( self ):
+
+ from Products.GenericSetup.tool import TOOLSET_XML
+ from Products.GenericSetup.tool import exportToolset
+
+ site = self._initSite()
+ context = DummyExportContext( site )
+
+ exportToolset( context )
+
+ self.assertEqual( len( context._wrote ), 1 )
+ filename, text, content_type = context._wrote[ 0 ]
+ self.assertEqual( filename, TOOLSET_XML )
+ self._compareDOM( text, _EMPTY_TOOLSET_XML )
+ self.assertEqual( content_type, 'text/xml' )
+
+ def test_normal( self ):
+
+ from Products.GenericSetup.tool import TOOLSET_XML
+ from Products.GenericSetup.tool import exportToolset
+
+ site = self._initSite()
+ toolset = site.setup_tool.getToolsetRegistry()
+ toolset.addForbiddenTool( 'doomed' )
+ toolset.addRequiredTool( 'mandatory', 'path.to.one' )
+ toolset.addRequiredTool( 'obligatory', 'path.to.another' )
+
+ context = DummyExportContext( site )
+
+ exportToolset( context )
+
+ self.assertEqual( len( context._wrote ), 1 )
+ filename, text, content_type = context._wrote[ 0 ]
+ self.assertEqual( filename, TOOLSET_XML )
+ self._compareDOM( text, _NORMAL_TOOLSET_XML )
+ self.assertEqual( content_type, 'text/xml' )
+
+class Test_importToolset( _ToolsetSetup ):
+
+ def test_tool_ids( self ):
+ # The tool import mechanism used to rely on the fact that all tools
+ # have unique IDs set at the class level and that you can call their
+ # constructor with no arguments. However, there might be tools
+ # that need IDs set.
+ from Products.GenericSetup.tool import TOOLSET_XML
+ from Products.GenericSetup.tool import importToolset
+
+ site = self._initSite()
+ context = DummyImportContext( site )
+ context._files[ TOOLSET_XML ] = _REQUIRED_TOOLSET_XML
+
+ importToolset( context )
+
+ for tool_id in ( 'mandatory', 'obligatory' ):
+ tool = getattr( site, tool_id )
+ self.assertEqual( tool.getId(), tool_id )
+
+ def test_forbidden_tools( self ):
+
+ from Products.GenericSetup.tool import TOOLSET_XML
+ from Products.GenericSetup.tool import importToolset
+ TOOL_IDS = ( 'doomed', 'blasted', 'saved' )
+
+ site = self._initSite()
+
+ for tool_id in TOOL_IDS:
+ pseudo = Folder()
+ pseudo._setId( tool_id )
+ site._setObject( tool_id, pseudo )
+
+ self.assertEqual( len( site.objectIds() ), len( TOOL_IDS ) + 1 )
+
+ for tool_id in TOOL_IDS:
+ self.failUnless( tool_id in site.objectIds() )
+
+ context = DummyImportContext( site )
+ context._files[ TOOLSET_XML ] = _FORBIDDEN_TOOLSET_XML
+
+ importToolset( context )
+
+ self.assertEqual( len( site.objectIds() ), 2 )
+ self.failUnless( 'setup_tool' in site.objectIds() )
+ self.failUnless( 'saved' in site.objectIds() )
+
+ def test_required_tools_missing( self ):
+
+ from Products.GenericSetup.tool import TOOLSET_XML
+ from Products.GenericSetup.tool import importToolset
+
+ site = self._initSite()
+ self.assertEqual( len( site.objectIds() ), 1 )
+
+ context = DummyImportContext( site )
+ context._files[ TOOLSET_XML ] = _REQUIRED_TOOLSET_XML
+
+ importToolset( context )
+
+ self.assertEqual( len( site.objectIds() ), 3 )
+ self.failUnless( isinstance( aq_base( site._getOb( 'mandatory' ) )
+ , DummyTool ) )
+ self.failUnless( isinstance( aq_base( site._getOb( 'obligatory' ) )
+ , DummyTool ) )
+
+ def test_required_tools_no_replacement( self ):
+
+ from Products.GenericSetup.tool import TOOLSET_XML
+ from Products.GenericSetup.tool import importToolset
+
+ site = self._initSite()
+
+ mandatory = DummyTool()
+ mandatory._setId( 'mandatory' )
+ site._setObject( 'mandatory', mandatory )
+
+ obligatory = DummyTool()
+ obligatory._setId( 'obligatory' )
+ site._setObject( 'obligatory', obligatory )
+
+ self.assertEqual( len( site.objectIds() ), 3 )
+
+ context = DummyImportContext( site )
+ context._files[ TOOLSET_XML ] = _REQUIRED_TOOLSET_XML
+
+ importToolset( context )
+
+ self.assertEqual( len( site.objectIds() ), 3 )
+ self.failUnless( aq_base( site._getOb( 'mandatory' ) ) is mandatory )
+ self.failUnless( aq_base( site._getOb( 'obligatory' ) ) is obligatory )
+
+ def test_required_tools_with_replacement( self ):
+
+ from Products.GenericSetup.tool import TOOLSET_XML
+ from Products.GenericSetup.tool import importToolset
+
+ site = self._initSite()
+
+ mandatory = AnotherDummyTool()
+ mandatory._setId( 'mandatory' )
+ site._setObject( 'mandatory', mandatory )
+
+ obligatory = AnotherDummyTool()
+ obligatory._setId( 'obligatory' )
+ site._setObject( 'obligatory', obligatory )
+
+ self.assertEqual( len( site.objectIds() ), 3 )
+
+ context = DummyImportContext( site )
+ context._files[ TOOLSET_XML ] = _REQUIRED_TOOLSET_XML
+
+ importToolset( context )
+
+ self.assertEqual( len( site.objectIds() ), 3 )
+
+ self.failIf( aq_base( site._getOb( 'mandatory' ) ) is mandatory )
+ self.failUnless( isinstance( aq_base( site._getOb( 'mandatory' ) )
+ , DummyTool ) )
+
+ self.failIf( aq_base( site._getOb( 'obligatory' ) ) is obligatory )
+ self.failUnless( isinstance( aq_base( site._getOb( 'obligatory' ) )
+ , DummyTool ) )
+
+
+class DummyTool( Folder ):
+
+ pass
+
+class AnotherDummyTool( Folder ):
+
+ pass
+
+_EMPTY_TOOLSET_XML = """\
+<?xml version="1.0"?>
+<tool-setup>
+</tool-setup>
+"""
+
+_NORMAL_TOOLSET_XML = """\
+<?xml version="1.0" ?>
+<tool-setup>
+<forbidden tool_id="doomed"/>
+<required class="path.to.one" tool_id="mandatory"/>
+<required class="path.to.another" tool_id="obligatory"/>
+</tool-setup>
+"""
+
+_FORBIDDEN_TOOLSET_XML = """\
+<?xml version="1.0"?>
+<tool-setup>
+ <forbidden tool_id="doomed" />
+ <forbidden tool_id="damned" />
+ <forbidden tool_id="blasted" />
+</tool-setup>
+"""
+
+_REQUIRED_TOOLSET_XML = """\
+<?xml version="1.0"?>
+<tool-setup>
+ <required
+ tool_id="mandatory"
+ class="Products.GenericSetup.tests.test_tool.DummyTool" />
+ <required
+ tool_id="obligatory"
+ class="Products.GenericSetup.tests.test_tool.DummyTool" />
+</tool-setup>
+"""
+
+def test_suite():
+ # reimport to make sure tests are run from Products
+ from Products.GenericSetup.tests.test_tool import SetupToolTests
+ from Products.GenericSetup.tests.test_tool import Test_exportToolset
+ from Products.GenericSetup.tests.test_tool import Test_importToolset
+
+ return unittest.TestSuite((
+ unittest.makeSuite( SetupToolTests ),
+ unittest.makeSuite( Test_exportToolset ),
+ unittest.makeSuite( Test_importToolset ),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/test_utils.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tests/test_utils.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tests/test_utils.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,526 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" GenericSetup.utils unit tests
+
+$Id: test_utils.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+import unittest
+import Testing
+try:
+ import Zope2
+except ImportError: # BBB: for Zope 2.7
+ import Zope as Zope2
+Zope2.startup()
+
+from DateTime.DateTime import DateTime
+from OFS.Folder import Folder
+
+from common import BaseRegistryTests
+
+
+_NORMAL_PROPERTY_NODES = """\
+ <property name="foo_boolean" type="boolean">True</property>
+ <property name="foo_date" type="date">2000/01/01</property>
+ <property name="foo_float" type="float">1.1</property>
+ <property name="foo_int" type="int">1</property>
+ <property name="foo_lines" type="lines">
+ <element value="Foo"/>
+ <element value="Lines"/></property>
+ <property name="foo_long" type="long">1</property>
+ <property name="foo_string" type="string">Foo String</property>
+ <property name="foo_text" type="text">Foo
+Text</property>
+ <property name="foo_tokens" type="tokens">
+ <element value="Foo"/>
+ <element value="Tokens"/></property>
+ <property name="foo_selection" type="selection"
+ select_variable="foobarbaz">Foo</property>
+ <property name="foo_mselection" type="multiple selection"
+ select_variable="foobarbaz">
+ <element value="Foo"/>
+ <element value="Baz"/></property>
+ <property name="foo_boolean0" type="boolean">0</property>
+"""
+
+_FIXED_PROPERTY_NODES = """\
+ <property name="foo_boolean">True</property>
+ <property name="foo_date">2000/01/01</property>
+ <property name="foo_float">1.1</property>
+ <property name="foo_int">1</property>
+ <property name="foo_lines">
+ <element value="Foo"/>
+ <element value="Lines"/></property>
+ <property name="foo_long">1</property>
+ <property name="foo_string">Foo String</property>
+ <property name="foo_text">Foo
+Text</property>
+ <property name="foo_tokens">
+ <element value="Foo"/>
+ <element value="Tokens"/></property>
+ <property name="foo_selection" type="selection"
+ select_variable="foobarbaz">Foo</property>
+ <property name="foo_mselection">
+ <element value="Foo"/>
+ <element value="Baz"/></property>
+ <property name="foo_boolean0">0</property>
+"""
+
+_NORMAL_PROPERTY_INFO = ( { 'id': 'foo_boolean',
+ 'value': True,
+ 'elements': (),
+ 'type': 'boolean',
+ 'select_variable': None },
+ { 'id': 'foo_date',
+ 'value': DateTime('2000/01/01'),
+ 'elements': (),
+ 'type': 'date',
+ 'select_variable': None },
+ { 'id': 'foo_float',
+ 'value': 1.1,
+ 'elements': (),
+ 'type': 'float',
+ 'select_variable': None },
+ { 'id': 'foo_int',
+ 'value': 1,
+ 'elements': (),
+ 'type': 'int',
+ 'select_variable': None },
+ { 'id': 'foo_lines',
+ 'value': '',
+ 'elements': ('Foo', 'Lines'),
+ 'type': 'lines',
+ 'select_variable': None },
+ { 'id': 'foo_long',
+ 'value': 1,
+ 'elements': (),
+ 'type': 'long',
+ 'select_variable': None },
+ { 'id': 'foo_string',
+ 'value': 'Foo String',
+ 'elements': (),
+ 'type': 'string',
+ 'select_variable': None },
+ { 'id': 'foo_text',
+ 'value': 'Foo\nText',
+ 'elements': (),
+ 'type': 'text',
+ 'select_variable': None },
+ { 'id': 'foo_tokens',
+ 'value': '',
+ 'elements': ('Foo', 'Tokens'),
+ 'type': 'tokens',
+ 'select_variable': None },
+ { 'id': 'foo_selection',
+ 'value': 'Foo',
+ 'elements': (),
+ 'type': 'selection',
+ 'select_variable': 'foobarbaz' },
+ { 'id': 'foo_mselection',
+ 'value': '',
+ 'elements': ('Foo', 'Baz'),
+ 'type': 'multiple selection',
+ 'select_variable': 'foobarbaz' },
+ { 'id': 'foo_boolean0',
+ 'value': False, # 0 imports as False
+ 'elements': (),
+ 'type': 'boolean',
+ 'select_variable': None },
+ )
+
+_NORMAL_PROPERTY_EXPORT = """\
+<?xml version="1.0"?>
+<dummy>
+%s
+</dummy>
+""" % _NORMAL_PROPERTY_NODES
+
+_FIXED_PROPERTY_EXPORT = """\
+<?xml version="1.0"?>
+<dummy>
+%s
+</dummy>
+""" % _FIXED_PROPERTY_NODES
+
+_NORMAL_OBJECT_EXPORT = """\
+<?xml version="1.0"?>
+<dummy>
+ <object meta_type="Dummy Type" name="dummy">
+%s
+ </object>
+</dummy>
+""" % _NORMAL_PROPERTY_NODES
+
+_SPECIAL_IMPORT = """\
+<?xml version="1.0"?>
+<dummy>
+ <!-- ignore comment, allow empty description -->
+ <description></description>
+</dummy>
+"""
+
+def _testFunc( *args, **kw ):
+
+ """ This is a test.
+
+ This is only a test.
+ """
+
+_TEST_FUNC_NAME = 'Products.GenericSetup.tests.test_utils._testFunc'
+
+class Whatever:
+ pass
+
+_WHATEVER_NAME = 'Products.GenericSetup.tests.test_utils.Whatever'
+
+whatever_inst = Whatever()
+whatever_inst.__name__ = 'whatever_inst'
+
+_WHATEVER_INST_NAME = 'Products.GenericSetup.tests.test_utils.whatever_inst'
+
+class UtilsTests( unittest.TestCase ):
+
+ def test__getDottedName_simple( self ):
+
+ from Products.GenericSetup.utils import _getDottedName
+
+ self.assertEqual( _getDottedName( _testFunc ), _TEST_FUNC_NAME )
+
+ def test__getDottedName_string( self ):
+
+ from Products.GenericSetup.utils import _getDottedName
+
+ self.assertEqual( _getDottedName( _TEST_FUNC_NAME ), _TEST_FUNC_NAME )
+
+ def test__getDottedName_unicode( self ):
+
+ from Products.GenericSetup.utils import _getDottedName
+
+ dotted = u'%s' % _TEST_FUNC_NAME
+ self.assertEqual( _getDottedName( dotted ), _TEST_FUNC_NAME )
+ self.assertEqual( type( _getDottedName( dotted ) ), str )
+
+ def test__getDottedName_class( self ):
+
+ from Products.GenericSetup.utils import _getDottedName
+
+ self.assertEqual( _getDottedName( Whatever ), _WHATEVER_NAME )
+
+ def test__getDottedName_inst( self ):
+
+ from Products.GenericSetup.utils import _getDottedName
+
+ self.assertEqual( _getDottedName( whatever_inst )
+ , _WHATEVER_INST_NAME )
+
+ def test__getDottedName_noname( self ):
+
+ from Products.GenericSetup.utils import _getDottedName
+
+ class Doh:
+ pass
+
+ doh = Doh()
+ self.assertRaises( ValueError, _getDottedName, doh )
+
+
+class DummyObject(Folder):
+
+ meta_type = 'Dummy Type'
+ _properties = ()
+
+
+class _ConfiguratorBaseTests(BaseRegistryTests):
+
+ def _initSite(self, foo=2):
+
+ self.root.site = Folder(id='site')
+ site = self.root.site
+
+ site.dummy = DummyObject(id='dummy')
+ site.dummy.foobarbaz = ('Foo', 'Bar', 'Baz')
+
+ if foo > 0:
+ site.dummy._setProperty('foo_boolean', '', 'boolean')
+ site.dummy._setProperty('foo_date', '', 'date')
+ site.dummy._setProperty('foo_float', '', 'float')
+ site.dummy._setProperty('foo_int', '', 'int')
+ site.dummy._setProperty('foo_lines', '', 'lines')
+ site.dummy._setProperty('foo_long', '', 'long')
+ site.dummy._setProperty('foo_string', '', 'string')
+ site.dummy._setProperty('foo_text', '', 'text')
+ site.dummy._setProperty('foo_tokens', (), 'tokens')
+ site.dummy._setProperty('foo_selection', 'foobarbaz', 'selection')
+ site.dummy._setProperty('foo_mselection', 'foobarbaz',
+ 'multiple selection')
+ site.dummy._setProperty('foo_boolean0', '', 'boolean')
+
+ if foo > 1:
+ site.dummy._updateProperty('foo_boolean', 'True')
+ site.dummy._updateProperty('foo_date', '2000/01/01')
+ site.dummy._updateProperty('foo_float', '1.1')
+ site.dummy._updateProperty('foo_int', '1')
+ site.dummy._updateProperty('foo_lines', 'Foo\nLines')
+ site.dummy._updateProperty('foo_long', '1')
+ site.dummy._updateProperty('foo_string', 'Foo String')
+ site.dummy._updateProperty('foo_text', 'Foo\nText')
+ site.dummy._updateProperty( 'foo_tokens', ('Foo', 'Tokens') )
+ site.dummy._updateProperty('foo_selection', 'Foo')
+ site.dummy._updateProperty( 'foo_mselection', ('Foo', 'Baz') )
+ site.dummy.foo_boolean0 = 0
+
+ return site
+
+
+class ExportConfiguratorBaseTests(_ConfiguratorBaseTests):
+
+ def _getTargetClass(self):
+
+ from Products.GenericSetup.utils import ExportConfiguratorBase
+
+ class Configurator(ExportConfiguratorBase):
+ def _getExportTemplate(self):
+ return None
+
+ return Configurator
+
+ def test__extractProperty_normal(self):
+
+ site = self._initSite()
+
+ EXPECTED = _NORMAL_PROPERTY_INFO
+
+ configurator = self._makeOne(site)
+ prop_infos = [ configurator._extractProperty(site.dummy, prop_def)
+ for prop_def in site.dummy._propertyMap() ]
+
+ self.assertEqual( len(prop_infos), len(EXPECTED) )
+
+ for found, expected in zip(prop_infos, EXPECTED):
+ self.assertEqual(found, expected)
+
+ def test__extractObject_normal(self):
+
+ site = self._initSite()
+
+ EXPECTED = { 'id': 'dummy',
+ 'meta_type': 'Dummy Type',
+ 'properties': _NORMAL_PROPERTY_INFO,
+ 'subobjects': (),
+ 'i18n_domain' : None,
+ }
+
+ configurator = self._makeOne(site)
+ obj_info = configurator._extractObject(site.dummy)
+
+ self.assertEqual( len(obj_info), len(EXPECTED) )
+ self.assertEqual(obj_info, EXPECTED)
+
+ def test_generatePropertyNodes_normal(self):
+
+ site = self._initSite()
+ configurator = self._makeOne(site).__of__(site)
+ prop_infos = [ configurator._extractProperty(site.dummy, prop_def)
+ for prop_def in site.dummy._propertyMap() ]
+ nodes = configurator.generatePropertyNodes(prop_infos)
+ xml = '<?xml version="1.0"?><dummy>%s\n</dummy>' % nodes
+
+ self._compareDOM(xml, _NORMAL_PROPERTY_EXPORT)
+
+ def test_generateObjectNodes_normal(self):
+
+ site = self._initSite()
+ configurator = self._makeOne(site).__of__(site)
+ obj_infos = ( configurator._extractObject(site.dummy), )
+ nodes = configurator.generateObjectNodes(obj_infos)
+ xml = '<?xml version="1.0"?><dummy>%s\n</dummy>' % nodes
+
+ self._compareDOM(xml, _NORMAL_OBJECT_EXPORT)
+
+
+class ImportConfiguratorBaseTests(_ConfiguratorBaseTests):
+
+ def _getTargetClass(self):
+
+ from Products.GenericSetup.utils import ImportConfiguratorBase
+ from Products.GenericSetup.utils import CONVERTER, DEFAULT, KEY
+
+ class Configurator(ImportConfiguratorBase):
+ def _getImportMapping(self):
+ return {
+ 'dummy':
+ { 'property': {KEY: 'properties', DEFAULT: ()},
+ 'description': {CONVERTER: self._convertToUnique} } }
+
+ return Configurator
+
+
+ def test_parseXML_normal(self):
+
+ site = self._initSite()
+ configurator = self._makeOne(site)
+ site_info = configurator.parseXML(_NORMAL_PROPERTY_EXPORT)
+
+ self.assertEqual( len( site_info['properties'] ), 12 )
+
+ info = site_info['properties'][0]
+ self.assertEqual( info['id'], 'foo_boolean' )
+ self.assertEqual( info['value'], 'True' )
+ self.assertEqual( len( info['elements'] ), 0 )
+ self.assertEqual( info['type'], 'boolean' )
+
+ info = site_info['properties'][1]
+ self.assertEqual( info['id'], 'foo_date' )
+ self.assertEqual( info['value'], '2000/01/01' )
+ self.assertEqual( len( info['elements'] ), 0 )
+ self.assertEqual( info['type'], 'date' )
+
+ info = site_info['properties'][2]
+ self.assertEqual( info['id'], 'foo_float' )
+ self.assertEqual( info['value'], '1.1' )
+ self.assertEqual( len( info['elements'] ), 0 )
+ self.assertEqual( info['type'], 'float' )
+
+ info = site_info['properties'][3]
+ self.assertEqual( info['id'], 'foo_int' )
+ self.assertEqual( info['value'], '1' )
+ self.assertEqual( len( info['elements'] ), 0 )
+ self.assertEqual( info['type'], 'int' )
+
+ info = site_info['properties'][4]
+ self.assertEqual( info['id'], 'foo_lines' )
+ self.assertEqual( info['value'], '' )
+ self.assertEqual( len( info['elements'] ), 2 )
+ self.assertEqual( info['elements'][0], 'Foo' )
+ self.assertEqual( info['elements'][1], 'Lines' )
+ self.assertEqual( info['type'], 'lines' )
+
+ info = site_info['properties'][5]
+ self.assertEqual( info['id'], 'foo_long' )
+ self.assertEqual( info['value'], '1' )
+ self.assertEqual( len( info['elements'] ), 0 )
+ self.assertEqual( info['type'], 'long' )
+
+ info = site_info['properties'][6]
+ self.assertEqual( info['id'], 'foo_string' )
+ self.assertEqual( info['value'], 'Foo String' )
+ self.assertEqual( len( info['elements'] ), 0 )
+ self.assertEqual( info['type'], 'string' )
+
+ info = site_info['properties'][7]
+ self.assertEqual( info['id'], 'foo_text' )
+ self.assertEqual( info['value'], 'Foo\nText' )
+ self.assertEqual( len( info['elements'] ), 0 )
+ self.assertEqual( info['type'], 'text' )
+
+ info = site_info['properties'][8]
+ self.assertEqual( info['id'], 'foo_tokens' )
+ self.assertEqual( info['value'], '' )
+ self.assertEqual( len( info['elements'] ), 2 )
+ self.assertEqual( info['elements'][0], 'Foo' )
+ self.assertEqual( info['elements'][1], 'Tokens' )
+ self.assertEqual( info['type'], 'tokens' )
+
+ info = site_info['properties'][9]
+ self.assertEqual( info['id'], 'foo_selection' )
+ self.assertEqual( info['value'], 'Foo' )
+ self.assertEqual( len( info['elements'] ), 0 )
+ self.assertEqual( info['type'], 'selection' )
+ self.assertEqual( info['select_variable'], 'foobarbaz' )
+
+ info = site_info['properties'][10]
+ self.assertEqual( info['id'], 'foo_mselection' )
+ self.assertEqual( info['value'], '' )
+ self.assertEqual( len( info['elements'] ), 2 )
+ self.assertEqual( info['elements'][0], 'Foo' )
+ self.assertEqual( info['elements'][1], 'Baz' )
+ self.assertEqual( info['type'], 'multiple selection' )
+ self.assertEqual( info['select_variable'], 'foobarbaz' )
+
+ info = site_info['properties'][11]
+ self.assertEqual( info['id'], 'foo_boolean0' )
+ self.assertEqual( info['value'], '0' )
+ self.assertEqual( len( info['elements'] ), 0 )
+ self.assertEqual( info['type'], 'boolean' )
+
+ def test_parseXML_special(self):
+
+ site = self._initSite()
+ configurator = self._makeOne(site)
+ try:
+ site_info = configurator.parseXML(_SPECIAL_IMPORT)
+ except KeyError:
+ self.fail('CMF Collector issue #352 (comment or empty '
+ 'description bug): KeyError raised')
+
+ self.assertEqual( len(site_info), 2 )
+ self.assertEqual( site_info['description'], '' )
+ self.assertEqual( len(site_info['properties']), 0 )
+
+ def test_initProperty_normal(self):
+
+ EXPECTED = _NORMAL_PROPERTY_INFO
+
+ site = self._initSite(0)
+ dummy = site.dummy
+ configurator = self._makeOne(site)
+ site_info = configurator.parseXML(_NORMAL_PROPERTY_EXPORT)
+
+ self.assertEqual( len( dummy.propertyIds() ), 0 )
+
+ for prop_info in site_info['properties']:
+ configurator.initProperty(dummy, prop_info)
+
+ self.assertEqual( len( dummy.propertyIds() ), len(EXPECTED) )
+
+ for exp_info in EXPECTED:
+ exp_id = exp_info['id']
+ exp_value = exp_info['elements'] or exp_info['value']
+ self.failUnless( exp_id in dummy.propertyIds() )
+ self.assertEqual( dummy.getProperty(exp_id), exp_value )
+
+ def test_initProperty_fixed(self):
+
+ EXPECTED = _NORMAL_PROPERTY_INFO
+
+ site = self._initSite(1)
+ dummy = site.dummy
+ configurator = self._makeOne(site)
+ site_info = configurator.parseXML(_FIXED_PROPERTY_EXPORT)
+
+ self.assertEqual( len( dummy.propertyIds() ), 12 )
+
+ for prop_info in site_info['properties']:
+ configurator.initProperty(dummy, prop_info)
+
+ self.assertEqual( len( dummy.propertyIds() ), len(EXPECTED) )
+
+ for exp_info in EXPECTED:
+ exp_id = exp_info['id']
+ exp_value = exp_info['elements'] or exp_info['value']
+ self.failUnless( exp_id in dummy.propertyIds() )
+ self.assertEqual( dummy.getProperty(exp_id), exp_value )
+
+
+def test_suite():
+ # reimport to make sure tests are run from Products
+ from Products.GenericSetup.tests.test_utils import UtilsTests
+
+ return unittest.TestSuite((
+ unittest.makeSuite( UtilsTests ),
+ unittest.makeSuite( ImportConfiguratorBaseTests ),
+ unittest.makeSuite( ExportConfiguratorBaseTests ),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/three/placeholder.txt
===================================================================
Added: CMF/branches/goldegg-phase-1/GenericSetup/tests/two/placeholder.txt
===================================================================
Added: CMF/branches/goldegg-phase-1/GenericSetup/tool.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/tool.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/tool.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,733 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Classes: SetupTool
+
+$Id: tool.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+import os
+import time
+from cgi import escape
+
+from AccessControl import ClassSecurityInfo
+from Acquisition import aq_base
+from Globals import InitializeClass
+from OFS.Folder import Folder
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from zope.interface import implements
+from zope.interface import implementedBy
+
+from interfaces import EXTENSION
+from interfaces import ISetupTool
+from permissions import ManagePortal
+from context import DirectoryImportContext
+from context import SnapshotImportContext
+from context import TarballExportContext
+from context import SnapshotExportContext
+from differ import ConfigDiff
+from registry import ImportStepRegistry
+from registry import ExportStepRegistry
+from registry import ToolsetRegistry
+from registry import _profile_registry
+
+from utils import _resolveDottedName
+from utils import _wwwdir
+
+IMPORT_STEPS_XML = 'import_steps.xml'
+EXPORT_STEPS_XML = 'export_steps.xml'
+TOOLSET_XML = 'toolset.xml'
+
+def exportStepRegistries(context):
+
+ """ Built-in handler for exporting import / export step registries.
+ """
+ site = context.getSite()
+ setup_tool = getattr(site, 'setup_tool')
+
+ import_steps_xml = setup_tool.getImportStepRegistry().generateXML()
+ context.writeDataFile('import_steps.xml', import_steps_xml, 'text/xml')
+
+ export_steps_xml = setup_tool.getExportStepRegistry().generateXML()
+ context.writeDataFile('export_steps.xml', export_steps_xml, 'text/xml')
+
+ return 'Step registries exported'
+
+def importToolset(context):
+
+ """ Import required / forbidden tools from XML file.
+ """
+ site = context.getSite()
+ encoding = context.getEncoding()
+
+ xml = context.readDataFile(TOOLSET_XML)
+ if xml is None:
+ return 'Toolset: Nothing to import.'
+
+ setup_tool = getattr(site, 'setup_tool')
+ toolset = setup_tool.getToolsetRegistry()
+
+ toolset.parseXML(xml, encoding)
+
+ existing_ids = site.objectIds()
+ existing_values = site.objectValues()
+
+ for tool_id in toolset.listForbiddenTools():
+
+ if tool_id in existing_ids:
+ site._delObject(tool_id)
+
+ for info in toolset.listRequiredToolInfo():
+
+ tool_id = str(info['id'])
+ tool_class = _resolveDottedName(info['class'])
+
+ existing = getattr(site, tool_id, None)
+ new_tool = tool_class()
+
+ try:
+ new_tool._setId(tool_id)
+ except: # XXX: ImmutableId raises result of calling MessageDialog
+ pass
+
+ if existing is None:
+ site._setObject(tool_id, new_tool)
+
+ else:
+ unwrapped = aq_base(existing)
+ if not isinstance(unwrapped, tool_class):
+ site._delObject(tool_id)
+ site._setObject(tool_id, tool_class())
+
+ return 'Toolset imported.'
+
+def exportToolset(context):
+
+ """ Export required / forbidden tools to XML file.
+ """
+ site = context.getSite()
+ setup_tool = getattr(site, 'setup_tool')
+ toolset = setup_tool.getToolsetRegistry()
+
+ xml = toolset.generateXML()
+ context.writeDataFile(TOOLSET_XML, xml, 'text/xml')
+
+ return 'Toolset exported.'
+
+
+class SetupTool(Folder):
+
+ """ Profile-based site configuration manager.
+ """
+ implements(ISetupTool, implementedBy(Folder))
+
+ id = 'setup_tool'
+ meta_type = 'Generic Setup Tool'
+
+ _import_context_id = ''
+
+ security = ClassSecurityInfo()
+
+ def __init__(self):
+
+ self._import_registry = ImportStepRegistry()
+ self._export_registry = ExportStepRegistry()
+ self._export_registry.registerStep('step_registries',
+ exportStepRegistries,
+ 'Export import / export steps.',
+ )
+ self._toolset_registry = ToolsetRegistry()
+
+ #
+ # ISetupTool API
+ #
+ security.declareProtected(ManagePortal, 'getEncoding')
+ def getEncoding(self):
+
+ """ See ISetupTool.
+ """
+ return 'ascii'
+
+ security.declareProtected(ManagePortal, 'getImportContextId')
+ def getImportContextID(self):
+
+ """ See ISetupTool.
+ """
+ return self._import_context_id
+
+ security.declareProtected(ManagePortal, 'setImportContext')
+ def setImportContext(self, context_id, encoding=None):
+
+ """ See ISetupTool.
+ """
+ self._import_context_id = context_id
+
+ self._updateImportStepsRegistry(encoding)
+ self._updateExportStepsRegistry(encoding)
+ self._updateToolsetRegistry(encoding)
+
+ security.declareProtected(ManagePortal, 'getImportStepRegistry')
+ def getImportStepRegistry(self):
+
+ """ See ISetupTool.
+ """
+ return self._import_registry
+
+ security.declareProtected(ManagePortal, 'getImportStepRegistry')
+ def getExportStepRegistry(self):
+
+ """ See ISetupTool.
+ """
+ return self._export_registry
+
+ security.declareProtected(ManagePortal, 'getToolsetRegistry')
+ def getToolsetRegistry(self):
+
+ """ See ISetupTool.
+ """
+ return self._toolset_registry
+
+ security.declareProtected(ManagePortal, 'executeStep')
+ def runImportStep(self, step_id, run_dependencies=True, purge_old=None):
+
+ """ See ISetupTool.
+ """
+ context = self._getImportContext(self._import_context_id, purge_old)
+
+ info = self._import_registry.getStepMetadata(step_id)
+
+ if info is None:
+ raise ValueError, 'No such import step: %s' % step_id
+
+ dependencies = info.get('dependencies', ())
+
+ messages = {}
+ steps = []
+ if run_dependencies:
+ for dependency in dependencies:
+
+ if dependency not in steps:
+ message = self._doRunImportStep(dependency, context)
+ messages[dependency] = message
+ steps.append(dependency)
+
+ message = self._doRunImportStep(step_id, context)
+ messages[step_id] = message
+ steps.append(step_id)
+
+ return { 'steps' : steps, 'messages' : messages }
+
+ security.declareProtected(ManagePortal, 'runAllSetupSteps')
+ def runAllImportSteps(self, purge_old=None):
+
+ """ See ISetupTool.
+ """
+ context = self._getImportContext(self._import_context_id, purge_old)
+
+ steps = self._import_registry.sortSteps()
+ messages = {}
+
+ for step in steps:
+ message = self._doRunImportStep(step, context)
+ messages[step] = message
+
+ return { 'steps' : steps, 'messages' : messages }
+
+ security.declareProtected(ManagePortal, 'runExportStep')
+ def runExportStep(self, step_id):
+
+ """ See ISetupTool.
+ """
+ return self._doRunExportSteps([step_id])
+
+ security.declareProtected(ManagePortal, 'runAllExportSteps')
+ def runAllExportSteps(self):
+
+ """ See ISetupTool.
+ """
+ return self._doRunExportSteps(self._export_registry.listSteps())
+
+ security.declareProtected(ManagePortal, 'createSnapshot')
+ def createSnapshot(self, snapshot_id):
+
+ """ See ISetupTool.
+ """
+ context = SnapshotExportContext(self, snapshot_id)
+ messages = {}
+ steps = self._export_registry.listSteps()
+
+ for step_id in steps:
+
+ handler = self._export_registry.getStep(step_id)
+
+ if handler is None:
+ raise ValueError('Invalid export step: %s' % step_id)
+
+ messages[step_id] = handler(context)
+
+
+ return { 'steps' : steps
+ , 'messages' : messages
+ , 'url' : context.getSnapshotURL()
+ , 'snapshot' : context.getSnapshotFolder()
+ }
+
+ security.declareProtected(ManagePortal, 'compareConfigurations')
+ def compareConfigurations(self,
+ lhs_context,
+ rhs_context,
+ missing_as_empty=False,
+ ignore_blanks=False,
+ skip=('CVS', '.svn'),
+ ):
+ """ See ISetupTool.
+ """
+ differ = ConfigDiff(lhs_context,
+ rhs_context,
+ missing_as_empty,
+ ignore_blanks,
+ skip,
+ )
+
+ return differ.compare()
+
+ security.declareProtected(ManagePortal, 'markupComparison')
+ def markupComparison(self, lines):
+
+ """ See ISetupTool.
+ """
+ result = []
+
+ for line in lines.splitlines():
+
+ if line.startswith('** '):
+
+ if line.find('File') > -1:
+ if line.find('replaced') > -1:
+ result.append(('file-to-dir', line))
+ elif line.find('added') > -1:
+ result.append(('file-added', line))
+ else:
+ result.append(('file-removed', line))
+ else:
+ if line.find('replaced') > -1:
+ result.append(('dir-to-file', line))
+ elif line.find('added') > -1:
+ result.append(('dir-added', line))
+ else:
+ result.append(('dir-removed', line))
+
+ elif line.startswith('@@'):
+ result.append(('diff-range', line))
+
+ elif line.startswith(' '):
+ result.append(('diff-context', line))
+
+ elif line.startswith('+'):
+ result.append(('diff-added', line))
+
+ elif line.startswith('-'):
+ result.append(('diff-removed', line))
+
+ elif line == '\ No newline at end of file':
+ result.append(('diff-context', line))
+
+ else:
+ result.append(('diff-header', line))
+
+ return '<pre>\n%s\n</pre>' % (
+ '\n'.join([('<span class="%s">%s</span>' % (cl, escape(l)))
+ for cl, l in result]))
+
+ #
+ # ZMI
+ #
+ manage_options = (Folder.manage_options[:1]
+ + ({'label' : 'Properties',
+ 'action' : 'manage_tool'
+ },
+ {'label' : 'Import',
+ 'action' : 'manage_importSteps'
+ },
+ {'label' : 'Export',
+ 'action' : 'manage_exportSteps'
+ },
+ {'label' : 'Snapshots',
+ 'action' : 'manage_snapshots'
+ },
+ {'label' : 'Comparison',
+ 'action' : 'manage_showDiff'
+ },
+ )
+ + Folder.manage_options[3:] # skip "View", "Properties"
+ )
+
+ security.declareProtected(ManagePortal, 'manage_tool')
+ manage_tool = PageTemplateFile('sutProperties', _wwwdir)
+
+ security.declareProtected(ManagePortal, 'manage_updateToolProperties')
+ def manage_updateToolProperties(self, context_id, RESPONSE):
+ """ Update the tool's settings.
+ """
+ self.setImportContext(context_id)
+
+ RESPONSE.redirect('%s/manage_tool?manage_tabs_message=%s'
+ % (self.absolute_url(), 'Properties+updated.'))
+
+ security.declareProtected(ManagePortal, 'manage_importSteps')
+ manage_importSteps = PageTemplateFile('sutImportSteps', _wwwdir)
+
+ security.declareProtected(ManagePortal, 'manage_importSelectedSteps')
+ def manage_importSelectedSteps(self,
+ ids,
+ run_dependencies,
+ RESPONSE,
+ ):
+ """ Import the steps selected by the user.
+ """
+ if not ids:
+ message = 'No+steps+selected.'
+
+ else:
+ steps_run = []
+ for step_id in ids:
+ result = self.runImportStep(step_id, run_dependencies)
+ steps_run.extend(result['steps'])
+
+ message = 'Steps+run:%s' % '+,'.join(steps_run)
+
+ RESPONSE.redirect('%s/manage_importSteps?manage_tabs_message=%s'
+ % (self.absolute_url(), message))
+
+ security.declareProtected(ManagePortal, 'manage_importSelectedSteps')
+ def manage_importAllSteps(self, RESPONSE):
+
+ """ Import all steps.
+ """
+ result = self.runAllImportSteps()
+ message = 'Steps+run:%s' % '+,'.join(result['steps'])
+
+ RESPONSE.redirect('%s/manage_importSteps?manage_tabs_message=%s'
+ % (self.absolute_url(), message))
+
+ security.declareProtected(ManagePortal, 'manage_exportSteps')
+ manage_exportSteps = PageTemplateFile('sutExportSteps', _wwwdir)
+
+ security.declareProtected(ManagePortal, 'manage_exportSelectedSteps')
+ def manage_exportSelectedSteps(self, ids, RESPONSE):
+
+ """ Export the steps selected by the user.
+ """
+ if not ids:
+ RESPONSE.redirect('%s/manage_exportSteps?manage_tabs_message=%s'
+ % (self.absolute_url(), 'No+steps+selected.'))
+
+ result = self._doRunExportSteps(ids)
+ RESPONSE.setHeader('Content-type', 'application/x-gzip')
+ RESPONSE.setHeader('Content-disposition',
+ 'attachment; filename=%s' % result['filename'])
+ return result['tarball']
+
+ security.declareProtected(ManagePortal, 'manage_exportAllSteps')
+ def manage_exportAllSteps(self, RESPONSE):
+
+ """ Export all steps.
+ """
+ result = self.runAllExportSteps()
+ RESPONSE.setHeader('Content-type', 'application/x-gzip')
+ RESPONSE.setHeader('Content-disposition',
+ 'attachment; filename=%s' % result['filename'])
+ return result['tarball']
+
+ security.declareProtected(ManagePortal, 'manage_snapshots')
+ manage_snapshots = PageTemplateFile('sutSnapshots', _wwwdir)
+
+ security.declareProtected(ManagePortal, 'listSnapshotInfo')
+ def listSnapshotInfo(self):
+
+ """ Return a list of mappings describing available snapshots.
+
+ o Keys include:
+
+ 'id' -- snapshot ID
+
+ 'title' -- snapshot title or ID
+
+ 'url' -- URL of the snapshot folder
+ """
+ result = []
+ snapshots = self._getOb('snapshots', None)
+
+ if snapshots:
+
+ for id, folder in snapshots.objectItems('Folder'):
+
+ result.append({ 'id' : id
+ , 'title' : folder.title_or_id()
+ , 'url' : folder.absolute_url()
+ })
+ return result
+
+ security.declareProtected(ManagePortal, 'listProfileInfo')
+ def listProfileInfo(self):
+
+ """ Return a list of mappings describing registered profiles.
+
+ o Keys include:
+
+ 'id' -- profile ID
+
+ 'title' -- profile title or ID
+
+ 'description' -- description of the profile
+
+ 'path' -- path to the profile within its product
+
+ 'product' -- name of the registering product
+ """
+ return _profile_registry.listProfileInfo()
+
+ security.declareProtected(ManagePortal, 'listContextInfos')
+ def listContextInfos(self):
+
+ """ List registered profiles and snapshots.
+ """
+
+ s_infos = [{ 'id': 'snapshot-%s' % info['id'],
+ 'title': info['title'] }
+ for info in self.listSnapshotInfo()]
+ p_infos = [{ 'id': 'profile-%s' % info['id'],
+ 'title': info['title'] }
+ for info in self.listProfileInfo()]
+
+ return tuple(s_infos + p_infos)
+
+ security.declareProtected(ManagePortal, 'manage_createSnapshot')
+ def manage_createSnapshot(self, RESPONSE, snapshot_id=None):
+
+ """ Create a snapshot with the given ID.
+
+ o If no ID is passed, generate one.
+ """
+ if snapshot_id is None:
+ timestamp = time.gmtime()
+ snapshot_id = 'snapshot-%4d%02d%02d%02d%02d%02d' % timestamp[:6]
+
+ self.createSnapshot(snapshot_id)
+
+ RESPONSE.redirect('%s/manage_snapshots?manage_tabs_message=%s'
+ % (self.absolute_url(), 'Snapshot+created.'))
+
+ security.declareProtected(ManagePortal, 'manage_showDiff')
+ manage_showDiff = PageTemplateFile('sutCompare', _wwwdir)
+
+ def manage_downloadDiff(self,
+ lhs,
+ rhs,
+ missing_as_empty,
+ ignore_blanks,
+ RESPONSE,
+ ):
+ """ Crack request vars and call compareConfigurations.
+
+ o Return the result as a 'text/plain' stream, suitable for framing.
+ """
+ comparison = self.manage_compareConfigurations(lhs,
+ rhs,
+ missing_as_empty,
+ ignore_blanks,
+ )
+ RESPONSE.setHeader('Content-Type', 'text/plain')
+ return _PLAINTEXT_DIFF_HEADER % (lhs, rhs, comparison)
+
+ security.declareProtected(ManagePortal, 'manage_compareConfigurations')
+ def manage_compareConfigurations(self,
+ lhs,
+ rhs,
+ missing_as_empty,
+ ignore_blanks,
+ ):
+ """ Crack request vars and call compareConfigurations.
+ """
+ lhs_context = self._getImportContext(lhs)
+ rhs_context = self._getImportContext(rhs)
+
+ return self.compareConfigurations(lhs_context,
+ rhs_context,
+ missing_as_empty,
+ ignore_blanks,
+ )
+
+
+ #
+ # Helper methods
+ #
+ security.declarePrivate('_getProductPath')
+ def _getProductPath(self, product_name):
+
+ """ Return the absolute path of the product's directory.
+ """
+ try:
+ product = __import__('Products.%s' % product_name
+ , globals(), {}, ['initialize'])
+ except ImportError:
+ raise ValueError, 'Not a valid product name: %s' % product_name
+
+ return product.__path__[0]
+
+ security.declarePrivate('_getImportContext')
+ def _getImportContext(self, context_id, should_purge=None):
+
+ """ Crack ID and generate appropriate import context.
+ """
+ encoding = self.getEncoding()
+
+ if context_id.startswith('profile-'):
+
+ context_id = context_id[len('profile-'):]
+ info = _profile_registry.getProfileInfo(context_id)
+
+ if info.get('product'):
+ path = os.path.join(self._getProductPath(info['product'])
+ , info['path'])
+ else:
+ path = info['path']
+ if should_purge is None:
+ should_purge = (info.get('type') != EXTENSION)
+ return DirectoryImportContext(self, path, should_purge, encoding)
+
+ # else snapshot
+ context_id = context_id[len('snapshot-'):]
+ if should_purge is None:
+ should_purge = True
+ return SnapshotImportContext(self, context_id, should_purge, encoding)
+
+ security.declarePrivate('_updateImportStepsRegistry')
+ def _updateImportStepsRegistry(self, encoding):
+
+ """ Update our import steps registry from our profile.
+ """
+ context = self._getImportContext(self._import_context_id)
+ xml = context.readDataFile(IMPORT_STEPS_XML)
+ if xml is None:
+ return
+
+ info_list = self._import_registry.parseXML(xml, encoding)
+
+ for step_info in info_list:
+
+ id = step_info['id']
+ version = step_info['version']
+ handler = _resolveDottedName(step_info['handler'])
+
+ dependencies = tuple(step_info.get('dependencies', ()))
+ title = step_info.get('title', id)
+ description = ''.join(step_info.get('description', []))
+
+ self._import_registry.registerStep(id=id,
+ version=version,
+ handler=handler,
+ dependencies=dependencies,
+ title=title,
+ description=description,
+ )
+
+ security.declarePrivate('_updateExportStepsRegistry')
+ def _updateExportStepsRegistry(self, encoding):
+
+ """ Update our export steps registry from our profile.
+ """
+ context = self._getImportContext(self._import_context_id)
+ xml = context.readDataFile(EXPORT_STEPS_XML)
+ if xml is None:
+ return
+
+ info_list = self._export_registry.parseXML(xml, encoding)
+
+ for step_info in info_list:
+
+ id = step_info['id']
+ handler = _resolveDottedName(step_info['handler'])
+
+ title = step_info.get('title', id)
+ description = ''.join(step_info.get('description', []))
+
+ self._export_registry.registerStep(id=id,
+ handler=handler,
+ title=title,
+ description=description,
+ )
+
+ security.declarePrivate('_updateToolsetRegistry')
+ def _updateToolsetRegistry(self, encoding):
+
+ """ Update our toolset registry from our profile.
+ """
+ context = self._getImportContext(self._import_context_id)
+ xml = context.readDataFile(TOOLSET_XML)
+ if xml is None:
+ return
+
+ self._toolset_registry.parseXML(xml, encoding)
+
+ security.declarePrivate('_doRunImportStep')
+ def _doRunImportStep(self, step_id, context):
+
+ """ Run a single import step, using a pre-built context.
+ """
+ handler = self._import_registry.getStep(step_id)
+
+ if handler is None:
+ raise ValueError('Invalid import step: %s' % step_id)
+
+ return handler(context)
+
+ security.declarePrivate('_doRunExportSteps')
+ def _doRunExportSteps(self, steps):
+
+ """ See ISetupTool.
+ """
+ context = TarballExportContext(self)
+ messages = {}
+
+ for step_id in steps:
+
+ handler = self._export_registry.getStep(step_id)
+
+ if handler is None:
+ raise ValueError('Invalid export step: %s' % step_id)
+
+ messages[step_id] = handler(context)
+
+
+ return { 'steps' : steps
+ , 'messages' : messages
+ , 'tarball' : context.getArchive()
+ , 'filename' : context.getArchiveFilename()
+ }
+
+InitializeClass(SetupTool)
+
+_PLAINTEXT_DIFF_HEADER ="""\
+Comparing configurations: '%s' and '%s'
+
+%s"""
+
+addSetupToolForm = PageTemplateFile('toolAdd.zpt', _wwwdir)
+
+def addSetupTool(dispatcher, RESPONSE):
+ """
+ """
+ tool = SetupTool()
+ dispatcher._setObject(tool.id, tool)
+
+ RESPONSE.redirect('%s/manage_main' % dispatcher.absolute_url())
Added: CMF/branches/goldegg-phase-1/GenericSetup/utils.py
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/utils.py 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/utils.py 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,514 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" GenericSetup product utilities
+
+$Id: utils.py,v 1.1.1.1 2005/08/08 19:38:37 tseaver Exp $
+"""
+
+import os
+from inspect import getdoc
+from xml.dom.minidom import parseString as domParseString
+from xml.sax.handler import ContentHandler
+
+import Products
+from AccessControl import ClassSecurityInfo
+from Acquisition import aq_base
+from Acquisition import Implicit
+from Globals import InitializeClass
+from Globals import package_home
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+
+from exceptions import BadRequest
+from permissions import ManagePortal
+
+
+_pkgdir = package_home( globals() )
+_wwwdir = os.path.join( _pkgdir, 'www' )
+_datadir = os.path.join( _pkgdir, 'data' )
+_xmldir = os.path.join( _pkgdir, 'xml' )
+
+CONVERTER, DEFAULT, KEY = range(3)
+
+
+def _getDottedName( named ):
+
+ if isinstance( named, basestring ):
+ return str( named )
+
+ try:
+ return '%s.%s' % ( named.__module__, named.__name__ )
+ except AttributeError:
+ raise ValueError, 'Cannot compute dotted name: %s' % named
+
+def _resolveDottedName( dotted ):
+
+ parts = dotted.split( '.' )
+
+ if not parts:
+ raise ValueError, "incomplete dotted name: %s" % dotted
+
+ parts_copy = parts[:]
+
+ while parts_copy:
+ try:
+ module = __import__( '.'.join( parts_copy ) )
+ break
+
+ except ImportError:
+
+ del parts_copy[ -1 ]
+
+ if not parts_copy:
+ raise
+
+ parts = parts[ 1: ] # Funky semantics of __import__'s return value
+
+ obj = module
+
+ for part in parts:
+ obj = getattr( obj, part )
+
+ return obj
+
+def _extractDocstring( func, default_title, default_description ):
+
+ try:
+ doc = getdoc( func )
+ lines = doc.split( '\n' )
+
+ except AttributeError:
+
+ title = default_title
+ description = default_description
+
+ else:
+ title = lines[ 0 ]
+
+ if len( lines ) > 1 and lines[ 1 ].strip() == '':
+ del lines[ 1 ]
+
+ description = '\n'.join( lines[ 1: ] )
+
+ return title, description
+
+
+class HandlerBase( ContentHandler ):
+
+ _encoding = None
+ _MARKER = object()
+
+ def _extract( self, attrs, key, default=None ):
+
+ result = attrs.get( key, self._MARKER )
+
+ if result is self._MARKER:
+ return default
+
+ return self._encode( result )
+
+ def _extractBoolean( self, attrs, key, default ):
+
+ result = attrs.get( key, self._MARKER )
+
+ if result is self._MARKER:
+ return default
+
+ result = result.lower()
+ return result in ( '1', 'yes', 'true' )
+
+ def _encode( self, content ):
+
+ if self._encoding is None:
+ return content
+
+ return content.encode( self._encoding )
+
+
+class ImportConfiguratorBase(Implicit):
+ """ Synthesize data from XML description.
+ """
+ security = ClassSecurityInfo()
+ security.setDefaultAccess('allow')
+
+ def __init__(self, site, encoding=None):
+
+ self._site = site
+ self._encoding = encoding
+
+ security.declareProtected(ManagePortal, 'parseXML')
+ def parseXML(self, xml):
+ """ Pseudo API.
+ """
+ reader = getattr(xml, 'read', None)
+
+ if reader is not None:
+ xml = reader()
+
+ dom = domParseString(xml)
+ root = dom.documentElement
+
+ return self._extractNode(root)
+
+ def _extractNode(self, node):
+
+ nodes_map = self._getImportMapping()
+ if node.nodeName not in nodes_map:
+ nodes_map = self._getSharedImportMapping()
+ if node.nodeName not in nodes_map:
+ raise ValueError('Unknown node: %s' % node.nodeName)
+ node_map = nodes_map[node.nodeName]
+ info = {}
+
+ for name, val in node.attributes.items():
+ key = node_map[name].get( KEY, str(name) )
+ val = self._encoding and val.encode(self._encoding) or val
+ info[key] = val
+
+ for child in node.childNodes:
+ name = child.nodeName
+
+ if name == '#comment':
+ continue
+
+ if not name == '#text':
+ key = node_map[name].get(KEY, str(name) )
+ info[key] = info.setdefault( key, () ) + (
+ self._extractNode(child),)
+
+ elif '#text' in node_map:
+ key = node_map['#text'].get(KEY, 'value')
+ val = child.nodeValue.lstrip()
+ val = self._encoding and val.encode(self._encoding) or val
+ info[key] = info.setdefault(key, '') + val
+
+ for k, v in node_map.items():
+ key = v.get(KEY, k)
+
+ if DEFAULT in v and not key in info:
+ if isinstance( v[DEFAULT], basestring ):
+ info[key] = v[DEFAULT] % info
+ else:
+ info[key] = v[DEFAULT]
+
+ elif CONVERTER in v and key in info:
+ info[key] = v[CONVERTER]( info[key] )
+
+ if key is None:
+ info = info[key]
+
+ return info
+
+ def _getSharedImportMapping(self):
+
+ return {
+ 'object':
+ { 'i18n:domain': {},
+ 'name': {KEY: 'id'},
+ 'meta_type': {},
+ 'insert-before': {},
+ 'insert-after': {},
+ 'property': {KEY: 'properties', DEFAULT: ()},
+ 'object': {KEY: 'objects', DEFAULT: ()},
+ 'xmlns:i18n': {} },
+ 'property':
+ { 'name': {KEY: 'id'},
+ '#text': {KEY: 'value', DEFAULT: ''},
+ 'element': {KEY: 'elements', DEFAULT: ()},
+ 'type': {},
+ 'select_variable': {},
+ 'i18n:translate': {} },
+ 'element':
+ { 'value': {KEY: None} },
+ 'description':
+ { '#text': {KEY: None, DEFAULT: ''} } }
+
+ def _convertToBoolean(self, val):
+
+ return val.lower() in ('true', 'yes', '1')
+
+ def _convertToUnique(self, val):
+
+ assert len(val) == 1
+ return val[0]
+
+ security.declareProtected(ManagePortal, 'initObject')
+ def initObject(self, parent, o_info):
+
+ obj_id = str(o_info['id'])
+ if obj_id not in parent.objectIds():
+ meta_type = o_info['meta_type']
+ for mt_info in Products.meta_types:
+ if mt_info['name'] == meta_type:
+ parent._setObject( obj_id, mt_info['instance'](obj_id) )
+ break
+ else:
+ raise ValueError('unknown meta_type \'%s\'' % obj_id)
+ obj = parent._getOb(obj_id)
+
+ if 'insert-before' in o_info:
+ if o_info['insert-before'] == '*':
+ parent.moveObjectsToTop(obj_id)
+ else:
+ try:
+ position = parent.getObjectPosition(o_info['insert-before'])
+ parent.moveObjectToPosition(obj_id, position)
+ except ValueError:
+ pass
+ elif 'insert-after' in o_info:
+ if o_info['insert-after'] == '*':
+ parent.moveObjectsToBottom(obj_id)
+ else:
+ try:
+ position = parent.getObjectPosition(o_info['insert-after'])
+ parent.moveObjectToPosition(obj_id, position+1)
+ except ValueError:
+ pass
+
+ [ self.initObject(obj, info) for info in o_info['objects'] ]
+
+ if 'i18n:domain' in o_info:
+ obj.i18n_domain = o_info['i18n:domain']
+
+ [ self.initProperty(obj, info) for info in o_info['properties'] ]
+
+ security.declareProtected(ManagePortal, 'initProperty')
+ def initProperty(self, obj, p_info):
+
+ prop_id = p_info['id']
+ prop_map = obj.propdict().get(prop_id, None)
+
+ if prop_map is None:
+ type = p_info.get('type', None)
+ if type:
+ val = p_info.get('select_variable', '')
+ obj._setProperty(prop_id, val, type)
+ prop_map = obj.propdict().get(prop_id, None)
+ else:
+ raise ValueError('undefined property \'%s\'' % prop_id)
+
+ if not 'w' in prop_map.get('mode', 'wd'):
+ raise BadRequest('%s cannot be changed' % prop_id)
+
+ if prop_map.get('type') == 'multiple selection':
+ prop_value = p_info['elements'] or ()
+ elif prop_map.get('type') == 'boolean':
+ # Make sure '0' is imported as False
+ prop_value = str(p_info['value'])
+ if prop_value == '0':
+ prop_value = ''
+ else:
+ # if we pass a *string* to _updateProperty, all other values
+ # are converted to the right type
+ prop_value = p_info['elements'] or str( p_info['value'] )
+
+ obj._updateProperty(prop_id, prop_value)
+
+InitializeClass(ImportConfiguratorBase)
+
+
+class ExportConfiguratorBase(Implicit):
+ """ Synthesize XML description.
+ """
+ security = ClassSecurityInfo()
+ security.setDefaultAccess('allow')
+
+ def __init__(self, site, encoding=None):
+
+ self._site = site
+ self._encoding = encoding
+ self._template = self._getExportTemplate()
+
+ security.declareProtected(ManagePortal, 'generateXML')
+ def generateXML(self, **kw):
+ """ Pseudo API.
+ """
+ return self._template(**kw)
+
+ #
+ # generic object and property support
+ #
+ _ob_nodes = PageTemplateFile('object_nodes.xml', _xmldir)
+ _prop_nodes = PageTemplateFile('property_nodes.xml', _xmldir)
+
+ security.declareProtected(ManagePortal, 'generateObjectNodes')
+ def generateObjectNodes(self, obj_infos):
+ """ Pseudo API.
+ """
+ lines = self._ob_nodes(objects=obj_infos).splitlines()
+ return '\n'.join(lines)
+
+ security.declareProtected(ManagePortal, 'generatePropertyNodes')
+ def generatePropertyNodes(self, prop_infos):
+ """ Pseudo API.
+ """
+ lines = self._prop_nodes(properties=prop_infos).splitlines()
+ return '\n'.join(lines)
+
+ def _extractObject(self, obj):
+
+ properties = []
+ subobjects = []
+ i18n_domain = getattr(obj, 'i18n_domain', None)
+
+ if getattr( aq_base(obj), '_propertyMap' ):
+ for prop_map in obj._propertyMap():
+ prop_info = self._extractProperty(obj, prop_map)
+ if i18n_domain and prop_info['id'] in ('title', 'description'):
+ prop_info['i18ned'] = ''
+ if prop_info['id'] != 'i18n_domain':
+ properties.append(prop_info)
+
+ if getattr( aq_base(obj), 'objectValues' ):
+ for sub in obj.objectValues():
+ subobjects.append( self._extractObject(sub) )
+
+ return { 'id': obj.getId(),
+ 'meta_type': obj.meta_type,
+ 'i18n_domain': i18n_domain or None,
+ 'properties': tuple(properties),
+ 'subobjects': tuple(subobjects) }
+
+ def _extractProperty(self, obj, prop_map):
+
+ prop_id = prop_map['id']
+ prop = obj.getProperty(prop_id)
+
+ if isinstance(prop, tuple):
+ prop_value = ''
+ prop_elements = prop
+ elif isinstance(prop, list):
+ # Backward compat for old instances that stored
+ # properties as list.
+ prop_value = ''
+ prop_elements = tuple(prop)
+ else:
+ prop_value = prop
+ prop_elements = ()
+
+ if 'd' in prop_map.get('mode', 'wd') and not prop_id == 'title':
+ type = prop_map.get('type', 'string')
+ select_variable = prop_map.get('select_variable', None)
+ else:
+ type = None
+ select_variable = None
+
+ return { 'id': prop_id,
+ 'value': prop_value,
+ 'elements': prop_elements,
+ 'type': type,
+ 'select_variable': select_variable }
+
+InitializeClass(ExportConfiguratorBase)
+
+
+# BBB: old class mixing the two, will be removed in CMF 1.7
+class ConfiguratorBase(ImportConfiguratorBase, ExportConfiguratorBase):
+ """ Synthesize XML description.
+ """
+ security = ClassSecurityInfo()
+ security.setDefaultAccess('allow')
+
+ def __init__(self, site, encoding=None):
+ ImportConfiguratorBase.__init__(self, site, encoding)
+ ExportConfiguratorBase.__init__(self, site, encoding)
+
+InitializeClass(ConfiguratorBase)
+
+
+#
+# deprecated DOM parsing utilities
+#
+_marker = object()
+
+def _queryNodeAttribute( node, attr_name, default, encoding=None ):
+
+ """ Extract a string-valued attribute from node.
+
+ o Return 'default' if the attribute is not present.
+ """
+ attr_node = node.attributes.get( attr_name, _marker )
+
+ if attr_node is _marker:
+ return default
+
+ value = attr_node.nodeValue
+
+ if encoding is not None:
+ value = value.encode( encoding )
+
+ return value
+
+def _getNodeAttribute( node, attr_name, encoding=None ):
+
+ """ Extract a string-valued attribute from node.
+ """
+ value = _queryNodeAttribute( node, attr_name, _marker, encoding )
+
+ if value is _marker:
+ raise ValueError, 'Invaid attribute: %s' % attr_name
+
+ return value
+
+def _queryNodeAttributeBoolean( node, attr_name, default ):
+
+ """ Extract a string-valued attribute from node.
+
+ o Return 'default' if the attribute is not present.
+ """
+ attr_node = node.attributes.get( attr_name, _marker )
+
+ if attr_node is _marker:
+ return default
+
+ value = node.attributes[ attr_name ].nodeValue.lower()
+
+ return value in ( 'true', 'yes', '1' )
+
+def _getNodeAttributeBoolean( node, attr_name ):
+
+ """ Extract a string-valued attribute from node.
+ """
+ value = node.attributes[ attr_name ].nodeValue.lower()
+
+ return value in ( 'true', 'yes', '1' )
+
+def _coalesceTextNodeChildren( node, encoding=None ):
+
+ """ Concatenate all childe text nodes into a single string.
+ """
+ from xml.dom import Node
+ fragments = []
+ node.normalize()
+ child = node.firstChild
+
+ while child is not None:
+
+ if child.nodeType == Node.TEXT_NODE:
+ fragments.append( child.nodeValue )
+
+ child = child.nextSibling
+
+ joined = ''.join( fragments )
+
+ if encoding is not None:
+ joined = joined.encode( encoding )
+
+ return ''.join( [ line.lstrip() for line in joined.splitlines(True) ] )
+
+def _extractDescriptionNode(parent, encoding=None):
+
+ d_nodes = parent.getElementsByTagName('description')
+ if d_nodes:
+ return _coalesceTextNodeChildren(d_nodes[0], encoding)
+ else:
+ return ''
Added: CMF/branches/goldegg-phase-1/GenericSetup/version.txt
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/version.txt 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/version.txt 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1 @@
+GenericSetup-1.0
Added: CMF/branches/goldegg-phase-1/GenericSetup/www/siteAddForm.zpt
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/www/siteAddForm.zpt 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/www/siteAddForm.zpt 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,51 @@
+<h1 tal:replace="structure context/manage_page_header">PAGE HEADER</h1>
+<h2 tal:define="form_title string:Add Configured CMF Site"
+ tal:replace="structure context/manage_form_title">FORM TITLE</h2>
+
+<p class="form-help">Please select ID and configuration for the new site.</p>
+
+<form action="addConfiguredSite" method="post">
+<table cellspacing="0" cellpadding="2" border="0">
+ <tr valign="top">
+ <td>
+ <div class="form-label">Site ID</div>
+ </td>
+ <td>
+ <input type="text" name="site_id" />
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>
+ <div class="form-label">Setup profile</div>
+ </td>
+ <td>
+ <select name="profile_id">
+ <option value="PROFILE_ID"
+ tal:repeat="info options/base_profiles"
+ tal:attributes="value info/id"
+ tal:content="info/title">PROFILE TITLE</option>
+ </select>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>
+ <div class="form-label">Optional extensions</div>
+ </td>
+ <td><tal:span tal:repeat="info options/extension_profiles">
+ <input type="checkbox" name="extension_ids:list" value="PROFILE_ID"
+ tal:attributes="value info/id" />
+ <tal:span tal:content="info/title">PROFILE TITLE</tal:span><br /></tal:span>
+ </td>
+ </tr>
+ <tr>
+ <td>
+
+ </td>
+ <td>
+ <input class="form-element" type="submit" name="submit" value="Add" />
+ </td>
+ </tr>
+</table>
+</form>
+
+<h1 tal:replace="structure context/manage_page_footer">PAGE FOOTER</h1>
Added: CMF/branches/goldegg-phase-1/GenericSetup/www/sutCompare.zpt
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/www/sutCompare.zpt 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/www/sutCompare.zpt 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,136 @@
+<h1 tal:replace="structure context/manage_page_header">PAGE HEADER</h1>
+<h2 tal:replace="structure context/manage_tabs">TABS</h2>
+
+<style type="text/css">
+.file-to-dir {
+ font-weight: bold;
+ background-color: rgb(255, 182, 193);
+}
+
+.file-added {
+ font-weight: bold;
+ color: rgb(0, 139, 139);
+}
+
+.file-removed {
+ font-weight: bold;
+ color: rgb(0, 0, 139);
+}
+
+.dir-to-file {
+ font-weight: bold;
+ background-color: rgb(255, 182, 193);
+}
+
+.dir-added {
+ font-weight: bold;
+ color: rgb(0, 139, 139);
+}
+
+.dir-removed {
+ font-weight: bold;
+ color: rgb(0, 0, 139);
+}
+
+.diff-range {
+ background-color: rgb(244, 244, 244);
+ color: rgb(165, 42, 42);
+ font-weight: bold;
+}
+
+.diff-context {
+ background-color: rgb(244, 244, 244);
+}
+
+.diff-added {
+ background-color: rgb(244, 244, 244);
+ color: rgb(0, 139, 139);
+}
+
+.diff-removed {
+ background-color: rgb(244, 244, 244);
+ color: rgb(0, 0, 139);
+}
+
+.diff-header {
+ font-weight: bold;
+}
+</style>
+
+<div tal:define="lhs request/lhs | string:;
+ rhs request/rhs | string:;
+ ">
+
+<h3> Setup Tool </h3>
+
+<p class="form-help">
+By selecting two snapshots (or a snapshot and a filesystem setup directory), a
+comparison can be made, highlighting the differences between the two
+configuration sets.
+</p>
+
+<p>Configurations to compare:</p>
+<form method="post" action="."
+ tal:attributes="action string:${context/absolute_url}">
+
+<select name="lhs">
+ <option value="context-CONTEXT_ID"
+ tal:repeat="context_info context/listContextInfos"
+ tal:attributes="selected python:lhs == context_info['id'];
+ value context_info/id"
+ tal:content="context_info/title"
+ >CONTEXT_TITLE</option>
+</select>
+
+<select name="rhs">
+ <option value="context-CONTEXT_ID"
+ tal:repeat="context_info context/listContextInfos"
+ tal:attributes="selected python:rhs == context_info['id'];
+ value context_info/id"
+ tal:content="context_info/title"
+ >CONTEXT_TITLE</option>
+</select>
+
+<br />
+
+<input type="hidden" name="missing_as_empty:int:default" value="0" />
+<input type="checkbox" name="missing_as_empty:boolean" value="1"
+ tal:attributes="checked request/missing_as_empty | nothing" />
+Treat missing files as empty
+
+<br />
+
+<input type="hidden" name="ignore_blanks:int:default" value="0" />
+<input type="checkbox" name="ignore_blanks:boolean" value="1"
+ tal:attributes="checked request/ignore_blanks | nothing" />
+Ignore lines of whitespace
+
+<br />
+
+<input type="submit" name="manage_showDiff:method" value="Compare">
+<input type="submit" name="manage_downloadDiff:method" value="Download">
+
+</form>
+
+<hr />
+
+<div tal:condition="python: lhs and rhs" >
+
+<div tal:define="mae request/missing_as_empty | nothing;
+ ib request/ignore_blanks | nothing;
+ mcc nocall: context/manage_compareConfigurations;
+ comparison python:mcc( lhs, rhs, mae, ib )"
+>
+<p>
+Comparison of <span tal:replace="request/lhs">LHS</span>
+ and <span tal:replace="request/rhs">RHS</span>:</p>
+
+<span tal:replace="structure python: context.markupComparison( comparison )"
+>COMPARISON HERE</span>
+
+</div>
+</div>
+
+</div>
+
+<h1 tal:replace="structure context/manage_page_footer">PAGE FOOTER</h1>
Added: CMF/branches/goldegg-phase-1/GenericSetup/www/sutExportSteps.zpt
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/www/sutExportSteps.zpt 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/www/sutExportSteps.zpt 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,75 @@
+<h1 tal:replace="structure here/manage_page_header"> PAGE HEADER </h1>
+<h2 tal:replace="structure here/manage_tabs"> PAGE HEADER </h2>
+
+<h3> Site Configuration Export Steps </h3>
+
+
+<p class="form-help">
+Download selected export steps as tarball.
+</p>
+
+<h3>Available Export Steps</h3>
+
+<form action="." method="POST"
+ tal:attributes="action here/absolute_url" >
+<input type="hidden" name="ids:default:tokens" value="" />
+
+<table cellspacing="0" cellpadding="4">
+
+ <thead>
+ <tr class="list-header">
+ <td class="list-item">Sel.</td>
+ <td class="list-item">#</td>
+ <td class="list-item">Title / Description</td>
+ <td class="list-item">Handler</td>
+ </tr>
+ </thead>
+
+ <tbody tal:define="registry here/getExportStepRegistry;
+ step_ids registry/listSteps;
+ ">
+ <tal:loop tal:repeat="step_id step_ids">
+ <tr valign="top"
+ tal:define="info python: registry.getStepMetadata( step_id );"
+ tal:attributes="class python:
+ repeat[ 'step_id' ].odd and 'row-normal' or 'row-hilite'" >
+ <td class="list-item" width="16">
+ <input type="checkbox" name="ids:list" value="STEP_ID"
+ tal:attributes="value step_id" />
+ </td>
+ <td align="right" class="list-item"
+ tal:content="repeat/step_id/number">1</td>
+ <td class="list-item">
+ <span tal:content="info/title">STEP TITLE</span><br />
+ <em tal:content="info/description">STEP DESCRIPTION</em>
+ </td>
+ <td class="list-item"
+ tal:content="info/handler">DOTTED.NAME</td>
+ </tr>
+ </tal:loop>
+
+ <tr valign="top" class="list-header">
+ <td colspan="4"> </td>
+ </tr>
+
+ <tr valign="top">
+ <td />
+ <td colspan="3">
+
+ <input class="form-element" type="submit"
+ name="manage_exportSelectedSteps:method"
+ value=" Export selected steps " />
+
+ <input class="form-element" type="submit"
+ name="manage_exportAllSteps:method"
+ value=" Export all steps " />
+
+ </td>
+ </tr>
+ </tbody>
+
+</table>
+</form>
+
+
+<h1 tal:replace="structure here/manage_page_footer"> PAGE FOOTER </h1>
Added: CMF/branches/goldegg-phase-1/GenericSetup/www/sutImportSteps.zpt
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/www/sutImportSteps.zpt 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/www/sutImportSteps.zpt 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,80 @@
+<h1 tal:replace="structure here/manage_page_header"> PAGE HEADER </h1>
+<h2 tal:replace="structure here/manage_tabs"> PAGE HEADER </h2>
+
+<h2> Site Configuration Import Steps </h2>
+
+<p class="form-help">
+This tool allows one to re-run individual steps of the site setup
+procedure, in order to pick up changes since the site was created.
+</p>
+
+<h3>Available Import Steps</h3>
+
+<form action="." method="POST"
+ tal:attributes="action here/absolute_url" >
+<input type="hidden" name="ids:default:tokens" value="" />
+
+<table cellspacing="0" cellpadding="4">
+
+ <thead>
+ <tr class="list-header">
+ <td class="list-item">Sel.</td>
+ <td class="list-item">#</td>
+ <td class="list-item">Title / Description</td>
+ <td class="list-item">Handler</td>
+ </tr>
+ </thead>
+
+ <tbody tal:define="registry here/getImportStepRegistry;
+ step_ids registry/sortSteps;
+ ">
+ <tal:loop tal:repeat="step_id step_ids">
+ <tr valign="top"
+ tal:define="info python: registry.getStepMetadata( step_id );"
+ tal:attributes="class python:
+ repeat[ 'step_id' ].odd and 'row-normal' or 'row-hilite'" >
+ <td class="list-item" width="16">
+ <input type="checkbox" name="ids:list" value="STEP_ID"
+ tal:attributes="value step_id" />
+ </td>
+ <td align="right" class="list-item"
+ tal:content="repeat/step_id/number">1</td>
+ <td class="list-item">
+ <span tal:content="info/title">STEP TITLE</span><br />
+ <em tal:content="info/description">STEP DESCRIPTION</em>
+ </td>
+ <td class="list-item"
+ tal:content="info/handler">DOTTED.NAME</td>
+ </tr>
+ </tal:loop>
+
+ <tr valign="top" class="list-header">
+ <td colspan="4"> </td>
+ </tr>
+
+ <tr valign="top">
+ <td />
+ <td colspan="3">
+
+ <input type="hidden" name="run_dependencies:int:default" value="0" />
+ <input class="form-element" type="checkbox" id="run_dependencies"
+ name="run_dependencies:boolean" value="1" checked="checked" />
+ <label for="run_dependencies">Include dependencies?</label>
+
+
+ <input class="form-element" type="submit"
+ name="manage_importSelectedSteps:method"
+ value=" Import selected steps " />
+
+ <input class="form-element" type="submit"
+ name="manage_importAllSteps:method"
+ value=" Import all steps " />
+ </td>
+ </tr>
+ </tbody>
+
+</table>
+</form>
+
+
+<h1 tal:replace="structure here/manage_page_footer"> PAGE FOOTER </h1>
Added: CMF/branches/goldegg-phase-1/GenericSetup/www/sutProperties.zpt
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/www/sutProperties.zpt 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/www/sutProperties.zpt 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,37 @@
+<h1 tal:replace="structure context/manage_page_header">PAGE HEADER</h1>
+<h2 tal:replace="structure context/manage_tabs">TABS</h2>
+
+<h3> Setup Tool Properties </h3>
+
+<form method="post" action="manage_updateToolProperties">
+
+<table>
+
+ <tr valign="top">
+ <td>
+ <div class="form-label">Active site configuration:</div>
+ </td>
+ <td>
+ <select name="context_id"
+ tal:define="context_id context/getImportContextID">
+ <option value="context-CONTEXT_ID"
+ tal:repeat="context_info context/listContextInfos"
+ tal:attributes="selected python:context_id == context_info['id'];
+ value context_info/id"
+ tal:content="context_info/title"
+ >CONTEXT_TITLE</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td />
+ <td>
+ <input class="form-element" type="submit" value=" Update " />
+ </td>
+ </tr>
+
+</table>
+</form>
+
+<h1 tal:replace="structure context/manage_page_footer">PAGE FOOTER</h1>
Added: CMF/branches/goldegg-phase-1/GenericSetup/www/sutSnapshots.zpt
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/www/sutSnapshots.zpt 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/www/sutSnapshots.zpt 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,64 @@
+<h1 tal:replace="structure here/manage_page_header"> PAGE HEADER </h1>
+<h2 tal:replace="structure here/manage_tabs"> PAGE HEADER </h2>
+
+<h3> Site Configuration Snapshots </h3>
+
+
+<p class="form-help">
+Snapshots capture site configuration at a particular point in time.
+</p>
+
+<h3>Available Snapshots</h3>
+
+<form action="." method="POST"
+ tal:attributes="action here/absolute_url" >
+<input type="hidden" name="ids:default:tokens" value="" />
+
+<table cellspacing="0" cellpadding="4"
+ tal:define="snapshot_info here/listSnapshotInfo;"
+>
+
+ <thead tal:condition="not: snapshot_info">
+ <tr>
+ <td colspan="4">No snapshots exist.</td>
+ </tr>
+ </thead>
+
+ <thead tal:condition="snapshot_info">
+ <tr class="list-header">
+ <td class="list-item">Title</td>
+ </tr>
+ </thead>
+
+ <tbody >
+ <tal:loop tal:repeat="info snapshot_info">
+ <tr valign="top"
+ tal:attributes="class python:
+ ( repeat[ 'info' ].odd and 'row-normal'
+ or 'row-hilite' )" >
+ <td class="list-item">
+ <a href="."
+ tal:attributes="href string:${info/url}/manage_main"
+ tal:content="info/title">STEP TITLE</a>
+ </td>
+ </tr>
+ </tal:loop>
+
+ <tr valign="top" class="list-header">
+ <td> </td>
+ </tr>
+
+ <tr valign="top">
+ <td>
+ <input class="form-element" type="submit"
+ name="manage_createSnapshot:method"
+ value=" Create a Snapshot " />
+ </td>
+ </tr>
+ </tbody>
+
+</table>
+</form>
+
+
+<h1 tal:replace="structure here/manage_page_footer"> PAGE FOOTER </h1>
Added: CMF/branches/goldegg-phase-1/GenericSetup/www/tool.png
===================================================================
(Binary files differ)
Property changes on: CMF/branches/goldegg-phase-1/GenericSetup/www/tool.png
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: CMF/branches/goldegg-phase-1/GenericSetup/www/toolAdd.zpt
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/www/toolAdd.zpt 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/www/toolAdd.zpt 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,6 @@
+<h1 tal:replace="structure context/manage_page_header">PAGE HEADER</h1>
+<h1 tal:replace="structure context/manage_tabs">TABS</h1>
+
+<h3> Add Setup Tool </h3>
+
+<h1 tal:replace="structure context/manage_page_footer">PAGE FOOTER</h1>
Added: CMF/branches/goldegg-phase-1/GenericSetup/xml/esrExport.xml
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/xml/esrExport.xml 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/xml/esrExport.xml 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<export-steps xmlns:tal="http://xml.zope.org/namespaces/tal">
+ <export-step id="STEP_ID"
+ handler="DOTTED.NAME"
+ title="TITLE"
+ tal:repeat="step here/listStepMetadata"
+ tal:attributes="id step/id;
+ handler step/handler;
+ title step/title
+ ">
+ <span tal:replace="step/description">DESCRIPTION</span>
+ </export-step>
+</export-steps>
Added: CMF/branches/goldegg-phase-1/GenericSetup/xml/isrExport.xml
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/xml/isrExport.xml 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/xml/isrExport.xml 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<import-steps xmlns:tal="http://xml.zope.org/namespaces/tal">
+ <import-step id="STEP_ID"
+ version="STEP_VERSION"
+ handler="DOTTED.NAME"
+ title="TITLE"
+ tal:repeat="step here/listStepMetadata"
+ tal:attributes="id step/id;
+ version step/version;
+ handler step/handler;
+ title step/title
+ ">
+ <dependency step="DEPENDENCY"
+ tal:repeat="dep step/dependencies"
+ tal:attributes="step dep" />
+ <span tal:replace="step/description">DESCRIPTION</span>
+ </import-step>
+</import-steps>
Added: CMF/branches/goldegg-phase-1/GenericSetup/xml/object_nodes.xml
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/xml/object_nodes.xml 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/xml/object_nodes.xml 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,11 @@
+<tal:loop xmlns:tal="http://xml.zope.org/namespaces/tal"
+ tal:repeat="obj_info options/objects">
+ <object name="ID" meta_type="META TYPE"
+ tal:attributes="name obj_info/id;
+ meta_type obj_info/meta_type"
+ ><tal:span tal:define="prop_infos obj_info/properties"
+ tal:replace="structure python: context.generatePropertyNodes(prop_infos)"
+/><tal:span tal:define="sub_infos obj_info/subobjects"
+ tal:condition="sub_infos"
+ tal:replace="structure python: context.generateObjectNodes(sub_infos)"/>
+ </object></tal:loop>
Added: CMF/branches/goldegg-phase-1/GenericSetup/xml/property_nodes.xml
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/xml/property_nodes.xml 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/xml/property_nodes.xml 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,10 @@
+<tal:loop xmlns:tal="http://xml.zope.org/namespaces/tal"
+ tal:repeat="prop_info options/properties">
+ <property name="ID"
+ tal:attributes="name prop_info/id;
+ type prop_info/type;
+ select_variable prop_info/select_variable"
+ ><tal:span tal:content="prop_info/value"
+ /><tal:loop tal:repeat="element prop_info/elements">
+ <element value="VALUE"
+ tal:attributes="value element"/></tal:loop></property></tal:loop>
Added: CMF/branches/goldegg-phase-1/GenericSetup/xml/rmeExport.xml
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/xml/rmeExport.xml 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/xml/rmeExport.xml 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<rolemap xmlns:tal="http://xml.zope.org/namespaces/tal">
+ <roles>
+ <role name="ROLENAME"
+ tal:repeat="role context/listRoles"
+ tal:attributes="name role"/>
+ </roles>
+ <permissions>
+ <permission name="PERMISSION NAME" acquire="True"
+ tal:repeat="info context/listPermissions"
+ tal:attributes="name info/name;
+ acquire info/acquire;
+ ">
+ <role name="ROLENAME"
+ tal:repeat="role info/roles"
+ tal:attributes="name role"/>
+ </permission>
+ </permissions>
+</rolemap>
Added: CMF/branches/goldegg-phase-1/GenericSetup/xml/spcExport.xml
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/xml/spcExport.xml 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/xml/spcExport.xml 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<site xmlns:tal="http://xml.zope.org/namespaces/tal"
+><tal:span tal:define="prop_infos context/listSiteInfos"
+ tal:replace="structure python: context.generatePropertyNodes(prop_infos)"/>
+</site>
Added: CMF/branches/goldegg-phase-1/GenericSetup/xml/tscExport.xml
===================================================================
--- CMF/branches/goldegg-phase-1/GenericSetup/xml/tscExport.xml 2005-09-23 18:27:29 UTC (rev 38572)
+++ CMF/branches/goldegg-phase-1/GenericSetup/xml/tscExport.xml 2005-09-23 21:33:02 UTC (rev 38573)
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<tool-setup xmlns:tal="http://xml.zope.org/namespaces/tal">
+ <forbidden
+ tool_id="TOOL_ID"
+ tal:repeat="id here/listForbiddenTools"
+ tal:attributes="tool_id id" />
+ <required
+ tool_id="TOOL_ID"
+ class="dotted.name.of.tool.class"
+ tal:repeat="info here/listRequiredToolInfo"
+ tal:attributes="tool_id info/id;
+ class info/class;
+ " />
+</tool-setup>
More information about the CMF-checkins
mailing list