[Checkins] SVN: Products.GenericSetup/branches/wichert-dependencies/ Cut a branch for work on dependencies in profiles

Wichert Akkerman wichert at wiggy.net
Wed Nov 21 16:30:44 EST 2007


Log message for revision 81954:
  Cut a branch for work on dependencies in profiles
  

Changed:
  A   Products.GenericSetup/branches/wichert-dependencies/
  U   Products.GenericSetup/branches/wichert-dependencies/CHANGES.txt
  U   Products.GenericSetup/branches/wichert-dependencies/interfaces.py
  U   Products.GenericSetup/branches/wichert-dependencies/metadata.py
  U   Products.GenericSetup/branches/wichert-dependencies/tests/test_profile_metadata.py
  U   Products.GenericSetup/branches/wichert-dependencies/tests/test_registry.py
  U   Products.GenericSetup/branches/wichert-dependencies/tests/test_tool.py
  U   Products.GenericSetup/branches/wichert-dependencies/tool.py

-=-
Copied: Products.GenericSetup/branches/wichert-dependencies (from rev 81953, Products.GenericSetup/trunk/Products/GenericSetup)

Modified: Products.GenericSetup/branches/wichert-dependencies/CHANGES.txt
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/CHANGES.txt	2007-11-21 18:40:10 UTC (rev 81953)
+++ Products.GenericSetup/branches/wichert-dependencies/CHANGES.txt	2007-11-21 21:30:44 UTC (rev 81954)
@@ -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/branches/wichert-dependencies/interfaces.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/interfaces.py	2007-11-21 18:40:10 UTC (rev 81953)
+++ Products.GenericSetup/branches/wichert-dependencies/interfaces.py	2007-11-21 21:30:44 UTC (rev 81954)
@@ -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/branches/wichert-dependencies/metadata.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/metadata.py	2007-11-21 18:40:10 UTC (rev 81953)
+++ Products.GenericSetup/branches/wichert-dependencies/metadata.py	2007-11-21 21:30:44 UTC (rev 81954)
@@ -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/branches/wichert-dependencies/tests/test_profile_metadata.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/tests/test_profile_metadata.py	2007-11-21 18:40:10 UTC (rev 81953)
+++ Products.GenericSetup/branches/wichert-dependencies/tests/test_profile_metadata.py	2007-11-21 21:30:44 UTC (rev 81954)
@@ -28,7 +28,7 @@
 dep1 = 'DEPENDENCY 1'
 dep2 = 'DEPENDENCY 2'
 
-_METADATA_XML = """\
+_METADATA_XML = """
 <?xml version="1.0"?>
 <metadata>
   <description>%s</description>

Modified: Products.GenericSetup/branches/wichert-dependencies/tests/test_registry.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/tests/test_registry.py	2007-11-21 18:40:10 UTC (rev 81953)
+++ Products.GenericSetup/branches/wichert-dependencies/tests/test_registry.py	2007-11-21 21:30:44 UTC (rev 81954)
@@ -573,7 +573,6 @@
 </import-steps>
 """ % ( ONE_FUNC_NAME, THREE_FUNC_NAME, TWO_FUNC_NAME )
 
-
 #==============================================================================
 #   ESR tests
 #==============================================================================

Modified: Products.GenericSetup/branches/wichert-dependencies/tests/test_tool.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/tests/test_tool.py	2007-11-21 18:40:10 UTC (rev 81953)
+++ Products.GenericSetup/branches/wichert-dependencies/tests/test_tool.py	2007-11-21 21:30:44 UTC (rev 81954)
@@ -55,7 +55,16 @@
 def handleProfileImportedEvent(event):
     _after_import_events.append(event)
 
+_METADATA_XML = """<?xml version="1.0"?>
+<metadata>
+  <version>1.0</version>
+  <dependencies>
+    <dependency>profile-bar</dependency>
+  </dependencies>
+</metadata>
+"""
 
+
 class SetupToolTests(FilesystemTestBase, TarballTester, ConformsToISetupTool):
 
     layer = ExportImportZCMLLayer
@@ -491,6 +500,47 @@
         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_PATH)
+
+        _imported = []
+        def _runImportStepsFromContext(context, steps=None, purge_old=None, profile_id=None):
+            _imported.append(profile_id)
+            return dict(steps=[], messages="")
+
+        tool._runImportStepsFromContext=_runImportStepsFromContext
+        import pdb ; pdb.set_trace()
+        result = tool.runAllImportStepsFromProfile('profile-other:foo',
+                                                   ignore_dependencies=False)
+        self.assertEqual(_imported, ["profile-other:bar", "profile-other:foo"])
+
+
     def test_runExportStep_nonesuch( self ):
 
         site = self._makeSite()

Modified: Products.GenericSetup/branches/wichert-dependencies/tool.py
===================================================================
--- Products.GenericSetup/trunk/Products/GenericSetup/tool.py	2007-11-21 18:40:10 UTC (rev 81953)
+++ Products.GenericSetup/branches/wichert-dependencies/tool.py	2007-11-21 21:30:44 UTC (rev 81954)
@@ -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,
+                                     archive=None,
+                                     ignore_dependencies=False):
 
         """ 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, 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,31 @@
         """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):
+        return self.getProfileInfo( profile_id ).get('dependencies', ())
+
+
     security.declareProtected(ManagePortal, 'listProfilesWithUpgrades')
     def listProfilesWithUpgrades(self):
         return listProfilesWithUpgrades()
@@ -934,7 +953,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 +978,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 +1095,31 @@
                }
 
     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):
+        if seen is None:
+            seen=set()
+        seen.add( profile_id )
+
+        if not ignore_dependencies:
+            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
+                    self._runImportStepsFromContext(steps=steps,
+                                                    purge_old=purge_old,
+                                                    profile_id=profile_id,
+                                                    ignore_dependencies=ignore_dependencies,
+                                                    seen=seen)
+
+        context = self._getImportContext(profile_id, purge_old, archive)
         self.applyContext(context)
 
         if steps is None:



More information about the Checkins mailing list