[Checkins] SVN: Products.GenericSetup/trunk/Products/GenericSetup/
Merge wichert-dependencies branch
Wichert Akkerman
wichert at wiggy.net
Fri Nov 23 13:42:56 EST 2007
Log message for revision 81973:
Merge wichert-dependencies branch
Changed:
U Products.GenericSetup/trunk/Products/GenericSetup/CHANGES.txt
U Products.GenericSetup/trunk/Products/GenericSetup/interfaces.py
U Products.GenericSetup/trunk/Products/GenericSetup/metadata.py
U Products.GenericSetup/trunk/Products/GenericSetup/tests/test_profile_metadata.py
U Products.GenericSetup/trunk/Products/GenericSetup/tests/test_registry.py
U Products.GenericSetup/trunk/Products/GenericSetup/tests/test_tool.py
U Products.GenericSetup/trunk/Products/GenericSetup/tool.py
-=-
Modified: Products.GenericSetup/trunk/Products/GenericSetup/CHANGES.txt
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/CHANGES.txt 2007-11-23 18:28:21 UTC (rev 81972)
+++ Products.GenericSetup/trunk/Products/GenericSetup/CHANGES.txt 2007-11-23 18:42:55 UTC (rev 81973)
@@ -2,6 +2,8 @@
GenericSetup 1.4 (unreleased)
+ - Add support for context dependencies in profiles.
+
- Deprecate the version field for import steps.
- Deprecate reading of version.txt to get the version for a profile.
Modified: Products.GenericSetup/trunk/Products/GenericSetup/interfaces.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/interfaces.py 2007-11-23 18:28:21 UTC (rev 81972)
+++ Products.GenericSetup/trunk/Products/GenericSetup/interfaces.py 2007-11-23 18:42:55 UTC (rev 81973)
@@ -545,7 +545,7 @@
DEPRECATED. Use runImportStepFromProfile instead.
"""
- def runAllImportStepsFromProfile(profile_id, purge_old=None):
+ def runAllImportStepsFromProfile(profile_id, purge_old=None, ignore_dependencies=False):
""" Run all setup steps for the given profile in dependency order.
@@ -556,6 +556,9 @@
"old" setup first (this is the responsibility of the step,
which must check the context we supply).
+ o Unless 'ignore_dependencies' is true this will also import
+ all profiles this profile depends on.
+
o Return a mapping, with keys:
'steps' -- a sequence of IDs of the steps run.
Modified: Products.GenericSetup/trunk/Products/GenericSetup/metadata.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/metadata.py 2007-11-23 18:28:21 UTC (rev 81972)
+++ Products.GenericSetup/trunk/Products/GenericSetup/metadata.py 2007-11-23 18:42:55 UTC (rev 81973)
@@ -19,6 +19,8 @@
from utils import ImportConfiguratorBase
from utils import CONVERTER, DEFAULT, KEY
+METADATA_XML = 'metadata.xml'
+
class ProfileMetadata( ImportConfiguratorBase ):
""" Extracts profile metadata from metadata.xml file.
"""
@@ -32,7 +34,7 @@
def __call__( self ):
- full_path = os.path.join( self._path, 'metadata.xml' )
+ full_path = os.path.join( self._path, METADATA_XML )
if not os.path.exists( full_path ):
return {}
Modified: Products.GenericSetup/trunk/Products/GenericSetup/tests/test_profile_metadata.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/tests/test_profile_metadata.py 2007-11-23 18:28:21 UTC (rev 81972)
+++ Products.GenericSetup/trunk/Products/GenericSetup/tests/test_profile_metadata.py 2007-11-23 18:42:55 UTC (rev 81973)
@@ -28,8 +28,7 @@
dep1 = 'DEPENDENCY 1'
dep2 = 'DEPENDENCY 2'
-_METADATA_XML = """\
-<?xml version="1.0"?>
+_METADATA_XML = """<?xml version="1.0"?>
<metadata>
<description>%s</description>
<version>%s</version>
Modified: Products.GenericSetup/trunk/Products/GenericSetup/tests/test_registry.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/tests/test_registry.py 2007-11-23 18:28:21 UTC (rev 81972)
+++ Products.GenericSetup/trunk/Products/GenericSetup/tests/test_registry.py 2007-11-23 18:42:55 UTC (rev 81973)
@@ -573,7 +573,6 @@
</import-steps>
""" % ( ONE_FUNC_NAME, THREE_FUNC_NAME, TWO_FUNC_NAME )
-
#==============================================================================
# ESR tests
#==============================================================================
Modified: Products.GenericSetup/trunk/Products/GenericSetup/tests/test_tool.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/tests/test_tool.py 2007-11-23 18:28:21 UTC (rev 81972)
+++ Products.GenericSetup/trunk/Products/GenericSetup/tests/test_tool.py 2007-11-23 18:42:55 UTC (rev 81973)
@@ -55,12 +55,22 @@
def handleProfileImportedEvent(event):
_after_import_events.append(event)
+_METADATA_XML = """<?xml version="1.0"?>
+<metadata>
+ <version>1.0</version>
+ <dependencies>
+ <dependency>profile-other:bar</dependency>
+ </dependencies>
+</metadata>
+"""
+
class SetupToolTests(FilesystemTestBase, TarballTester, ConformsToISetupTool):
layer = ExportImportZCMLLayer
_PROFILE_PATH = '/tmp/STT_test'
+ _PROFILE_PATH2 = '/tmp/STT_test2'
def afterSetUp(self):
self._profile_registry_info = profile_registry._profile_info
@@ -491,6 +501,45 @@
self.assertEqual( result[ 'steps' ][ 2 ], 'dependent' )
self.failIf( site.purged )
+ def test_runAllImportStepsFromProfileWithoutDepends( self ):
+ from Products.GenericSetup.metadata import METADATA_XML
+
+ self._makeFile(METADATA_XML, _METADATA_XML)
+
+ site = self._makeSite()
+ tool = self._makeOne('setup_tool').__of__( site )
+
+ profile_registry.registerProfile('foo', 'Foo', '', self._PROFILE_PATH)
+
+ _imported = []
+ def applyContext(context):
+ _imported.append(context._profile_path)
+
+ tool.applyContext=applyContext
+ result = tool.runAllImportStepsFromProfile('profile-other:foo', ignore_dependencies=True)
+ self.assertEqual(_imported, [self._PROFILE_PATH])
+
+ def test_runAllImportStepsFromProfileWithDepends( self ):
+ from Products.GenericSetup.metadata import METADATA_XML
+
+ self._makeFile(METADATA_XML, _METADATA_XML)
+
+ site = self._makeSite()
+ tool = self._makeOne('setup_tool').__of__( site )
+
+ profile_registry.registerProfile('foo', 'Foo', '', self._PROFILE_PATH)
+ profile_registry.registerProfile('bar', 'Bar', '', self._PROFILE_PATH2)
+
+ _imported = []
+ def applyContext(context):
+ _imported.append(context._profile_path)
+
+ tool.applyContext=applyContext
+ result = tool.runAllImportStepsFromProfile('profile-other:foo',
+ ignore_dependencies=False)
+ self.assertEqual(_imported, [self._PROFILE_PATH2, self._PROFILE_PATH])
+
+
def test_runExportStep_nonesuch( self ):
site = self._makeSite()
Modified: Products.GenericSetup/trunk/Products/GenericSetup/tool.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/tool.py 2007-11-23 18:28:21 UTC (rev 81972)
+++ Products.GenericSetup/trunk/Products/GenericSetup/tool.py 2007-11-23 18:42:55 UTC (rev 81973)
@@ -29,7 +29,6 @@
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from ZODB.POSException import ConflictError
from zope.interface import implements
-from zope.interface import implementedBy
from zope import event
from interfaces import BASE
@@ -363,16 +362,22 @@
)
security.declareProtected(ManagePortal, 'runAllImportStepsFromProfile')
- def runAllImportStepsFromProfile(self, profile_id, purge_old=None):
+ def runAllImportStepsFromProfile(self,
+ profile_id,
+ purge_old=None,
+ ignore_dependencies=False,
+ archive=None):
""" See ISetupTool.
"""
__traceback_info__ = profile_id
old_context = self._import_context_id
- context = self._getImportContext(profile_id, purge_old)
- result = self._runImportStepsFromContext(context, purge_old=purge_old, profile_id=profile_id)
+ result = self._runImportStepsFromContext(purge_old=purge_old,
+ profile_id=profile_id,
+ archive=archive,
+ ignore_dependencies=ignore_dependencies)
prefix = 'import-all-%s' % profile_id.replace(':', '_')
name = self._mangleTimestampName(prefix, 'log')
self._createReport(name, result['steps'], result['messages'])
@@ -613,18 +618,10 @@
if getattr(tarball, 'read', None) is not None:
tarball = tarball.read()
- context = TarballImportContext(tool=self,
- archive_bits=tarball,
- encoding='UTF8',
- should_purge=True,
- )
- result = self._runImportStepsFromContext(context,
- purge_old=True)
+ result = self.runAllImportStepsFromProfile(None, True, archive=tarball)
+
steps_run = 'Steps run: %s' % ', '.join(result['steps'])
- name = self._mangleTimestampName('import-all', 'log')
- self._createReport(name, result['steps'], result['messages'])
-
return self.manage_importSteps(manage_tabs_message=steps_run,
messages=result['messages'])
@@ -847,9 +844,34 @@
"""Return the registered filesystem version for the specified
profile.
"""
- info = _profile_registry.getProfileInfo(profile_id)
- return info.get('version', 'unknown')
+ return self.getProfileInfo( profile_id ).get('version', 'unknown')
+ security.declareProtected(ManagePortal, 'profileExists')
+ def profileExists(self, profile_id):
+ """Check if a profile exists."""
+ try:
+ self.getProfileInfo( profile_id )
+ except KeyError:
+ return False
+ else:
+ return True
+
+ security.declareProtected(ManagePortal, "getProfileInfo")
+ def getProfileInfo(self, profile_id):
+ if profile_id.startswith("profile-"):
+ profile_id = profile_id[len('profile-'):]
+ elif profile_id.startswith("snapshot-"):
+ profile_id = profile_id[len('snapshot-'):]
+ return _profile_registry.getProfileInfo(profile_id)
+
+ security.declareProtected(ManagePortal, 'getDependenciesForProfile')
+ def getDependenciesForProfile(self, profile_id):
+ try:
+ return self.getProfileInfo( profile_id ).get('dependencies', ())
+ except KeyError:
+ return ()
+
+
security.declareProtected(ManagePortal, 'listProfilesWithUpgrades')
def listProfilesWithUpgrades(self):
return listProfilesWithUpgrades()
@@ -934,7 +956,7 @@
return product.__path__[0]
security.declarePrivate('_getImportContext')
- def _getImportContext(self, context_id, should_purge=None):
+ def _getImportContext(self, context_id, should_purge=None, archive=None):
""" Crack ID and generate appropriate import context.
"""
@@ -959,6 +981,12 @@
if should_purge is None:
should_purge = True
return SnapshotImportContext(self, context_id, should_purge, encoding)
+ elif context_id is None and archive is not None:
+ return TarballImportContext(tool=self,
+ archive_bits=archive,
+ encoding='UTF8',
+ should_purge=should_purge,
+ )
else:
raise KeyError, 'Unknown context %s' % context_id
@@ -1070,7 +1098,35 @@
}
security.declarePrivate('_runImportStepsFromContext')
- def _runImportStepsFromContext(self, context, steps=None, purge_old=None, profile_id=None):
+ def _runImportStepsFromContext(self,
+ steps=None,
+ purge_old=None,
+ profile_id=None,
+ archive=None,
+ ignore_dependencies=False,
+ seen=None):
+
+ results = []
+
+ if not ignore_dependencies:
+ if seen is None:
+ seen=set()
+ seen.add( profile_id )
+
+ dependencies = self.getDependenciesForProfile( profile_id )
+ for dependency in dependencies:
+ if dependency not in seen:
+ if not self.profileExists( dependency ):
+ warn("Profile %s depends on unknown profile %s" % (profile_id, dependency))
+ continue
+ res = self._runImportStepsFromContext(steps=steps,
+ purge_old=purge_old,
+ profile_id=dependency,
+ ignore_dependencies=ignore_dependencies,
+ seen=seen)
+ results.append( res )
+
+ context = self._getImportContext(profile_id, purge_old, archive)
self.applyContext(context)
if steps is None:
@@ -1088,8 +1144,23 @@
event.notify(ProfileImportedEvent(self, profile_id, steps, True))
- return { 'steps' : steps, 'messages' : messages }
+ results.append({'steps' : steps, 'messages' : messages })
+ data = { 'steps' : [], 'messages' : {}}
+ for result in results:
+ for step in result['steps']:
+ if step not in data['steps']:
+ data['steps'].append(step)
+
+ for (step, msg) in result['messages'].items():
+ if step in data['messages']:
+ data['messages'][step]+="\n"+msg
+ else:
+ data['messages'][step]=msg
+ data['steps'] = list(data['steps'])
+
+ return data
+
security.declarePrivate('_mangleTimestampName')
def _mangleTimestampName(self, prefix, ext=None):
More information about the Checkins
mailing list