[Checkins] SVN: GenericSetup/branches/tseaver-bbq_sprint/ added
support for metadata.xml file,
read at profile registration time, which
Rob Miller
ra at burningman.com
Thu Mar 29 09:02:38 EDT 2007
Log message for revision 73910:
added support for metadata.xml file, read at profile registration time, which
allows users to specify profile description, version, and dependencies
Changed:
U GenericSetup/branches/tseaver-bbq_sprint/CHANGES.txt
A GenericSetup/branches/tseaver-bbq_sprint/doc/configurators.txt
A GenericSetup/branches/tseaver-bbq_sprint/metadata.py
U GenericSetup/branches/tseaver-bbq_sprint/registry.py
A GenericSetup/branches/tseaver-bbq_sprint/tests/test_profile_metadata.py
U GenericSetup/branches/tseaver-bbq_sprint/utils.py
-=-
Modified: GenericSetup/branches/tseaver-bbq_sprint/CHANGES.txt
===================================================================
--- GenericSetup/branches/tseaver-bbq_sprint/CHANGES.txt 2007-03-29 12:57:53 UTC (rev 73909)
+++ GenericSetup/branches/tseaver-bbq_sprint/CHANGES.txt 2007-03-29 13:02:36 UTC (rev 73910)
@@ -2,6 +2,10 @@
GenericSetup 1.3-beta (unreleased)
+ - Added support for 'metadata.xml' in the profile (read during
+ profile registration) to register profile description, version,
+ and dependencies.
+
- Deprecated runImportStep and runAllImportSteps in favor of
runImportStepFromProfile and runAllImportStepsFromProfile.
Added: GenericSetup/branches/tseaver-bbq_sprint/doc/configurators.txt
===================================================================
--- GenericSetup/branches/tseaver-bbq_sprint/doc/configurators.txt 2007-03-29 12:57:53 UTC (rev 73909)
+++ GenericSetup/branches/tseaver-bbq_sprint/doc/configurators.txt 2007-03-29 13:02:36 UTC (rev 73910)
@@ -0,0 +1,47 @@
+The Products.GenericSetup.utils.ImportConfiguratorBase class provides
+a convenient shortcut for defining how an XML file should be parsed
+and converted to a python dictionary. To use this, create a subclass
+of ImportConfiguratorBase and implement a _getImportMapping method
+which returns a dictionary. The returned dictionary should adhere to
+the following guidelines:
+
+- The utils module provides CONVERTER, DEFAULT, and KEY constants that
+ are to be used in the import mapping to define certain behaviours.
+
+- Any possible tag that you want your XML file format to support must
+ be listed as a top-level key in the import mapping dictionary.
+
+- The value of any key in the import mapping dictionary should be
+ another dictionary.
+
+- If an outer key represents a possible tag, then the nested
+ dictionary represents the possible "properties" of that tag, where a
+ property might be an attribute of the tag, the text content of the
+ tag, or possibly a nested tag.
+
+- If a key of the nested dictionary represents a nested tag, you will
+ also need a top-level key to represent that tag. The nested
+ representation of the tag is where you make statements about how the
+ tag itself should be represented, while the top-level key allows you
+ to express information about how the data that is further nested
+ within the nested tag should be represented.
+
+- A CONVERTER can be registered on a an element to change the way that
+ the element is represented in the generated data structure.
+ self._convertToUnique will cause the element to be represented as a
+ single item and not a tuple of items, for instance.
+
+- A KEY can be specified for an element. If it is specified then the
+ element's value will be stored in the resulting python dictionary
+ with the KEY value as the key. If KEY is None, then the value will
+ be stored in a tuple rather than as a value in a nested dictionary.
+ If KEY is omitted, then the name of the element will be used as the
+ key.
+
+- A DEFAULT value can be specified on an element, which will be used
+ as the value on that element if the element doesn't actually exist
+ in the XML file.
+
+- Reference examples for this syntax can be found in the
+ metadata.ProfileMetadata and the rolemap.RolemapImportConfigurator
+ classes.
Added: GenericSetup/branches/tseaver-bbq_sprint/metadata.py
===================================================================
--- GenericSetup/branches/tseaver-bbq_sprint/metadata.py 2007-03-29 12:57:53 UTC (rev 73909)
+++ GenericSetup/branches/tseaver-bbq_sprint/metadata.py 2007-03-29 13:02:36 UTC (rev 73910)
@@ -0,0 +1,61 @@
+##############################################################################
+#
+# Copyright (c) 2007 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 profile metadata
+
+$Id:$
+"""
+import os
+
+from utils import ImportConfiguratorBase
+from utils import CONVERTER, DEFAULT, KEY
+
+class ProfileMetadata( ImportConfiguratorBase ):
+ """ Extracts profile metadata from metadata.xml file.
+ """
+
+ def __init__( self, path, encoding=None ):
+
+ # don't call the base class __init__ b/c we don't have (or need)
+ # a site
+ self._path = path
+ self._encoding = encoding
+
+ def __call__( self ):
+
+ full_path = os.path.join( self._path, 'metadata.xml' )
+ if not os.path.exists( full_path ):
+ return {}
+
+ file = open( full_path, 'r' )
+ return self.parseXML( file.read() )
+
+ def _getImportMapping( self ):
+
+ return {
+ 'metadata':
+ {'description': { CONVERTER: self._convertToUnique },
+ 'version': { CONVERTER: self._convertToUnique },
+ 'dependencies': { CONVERTER: self._convertToUnique },
+ },
+ 'description':
+ { '#text': { KEY: None, DEFAULT: '' },
+ },
+ 'version':
+ { '#text': { KEY: None },
+ },
+ 'dependencies':
+ {'dependency': { KEY: None },},
+ 'dependency':
+ { '#text': { KEY: None },
+ },
+ }
Modified: GenericSetup/branches/tseaver-bbq_sprint/registry.py
===================================================================
--- GenericSetup/branches/tseaver-bbq_sprint/registry.py 2007-03-29 12:57:53 UTC (rev 73909)
+++ GenericSetup/branches/tseaver-bbq_sprint/registry.py 2007-03-29 13:02:36 UTC (rev 73910)
@@ -14,12 +14,14 @@
$Id$
"""
-
+import os
from xml.sax import parseString
from AccessControl import ClassSecurityInfo
from Acquisition import Implicit
from Globals import InitializeClass
+from App.FactoryDispatcher import ProductDispatcher
+import App.Product
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from zope.interface import implements
@@ -29,13 +31,13 @@
from interfaces import IToolsetRegistry
from interfaces import IProfileRegistry
from permissions import ManagePortal
+from metadata import ProfileMetadata
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.
@@ -610,6 +612,31 @@
, 'for': for_
}
+ metadata = ProfileMetadata( path )()
+
+ version = metadata.get( 'version', None )
+ if version is None and product is not None:
+ prod_module = getattr(App.Product.Products, product, None)
+ if prod_module is not None:
+ prod_path = prod_module.__path__[0]
+
+ # Retrieve version number from any suitable version.txt
+ for fname in ('version.txt', 'VERSION.txt', 'VERSION.TXT'):
+ try:
+ fpath = os.path.join( prod_path, fname )
+ fhandle = open( fpath, 'r' )
+ version = fhandle.read().strip()
+ fhandle.close()
+ break
+ except IOError:
+ continue
+
+ if version is not None:
+ metadata[ 'version' ] = version
+
+ # metadata.xml description trumps ZCML description... awkward
+ info.update( metadata )
+
self._profile_info[ profile_id ] = info
security.declarePrivate( 'clear' )
Added: GenericSetup/branches/tseaver-bbq_sprint/tests/test_profile_metadata.py
===================================================================
--- GenericSetup/branches/tseaver-bbq_sprint/tests/test_profile_metadata.py 2007-03-29 12:57:53 UTC (rev 73909)
+++ GenericSetup/branches/tseaver-bbq_sprint/tests/test_profile_metadata.py 2007-03-29 13:02:36 UTC (rev 73910)
@@ -0,0 +1,80 @@
+##############################################################################
+#
+# Copyright (c) 2007 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 ProfileMetadata.
+
+$Id:$
+"""
+import unittest
+import os
+
+from Testing.ZopeTestCase import ZopeTestCase
+from Testing.ZopeTestCase import installProduct
+
+from Products.GenericSetup import profile_registry
+from Products.GenericSetup.metadata import ProfileMetadata
+
+desc = 'DESCRIPTION TEXT'
+version = 'VERSION'
+dep1 = 'DEPENDENCY 1'
+dep2 = 'DEPENDENCY 2'
+
+_METADATA_XML = """\
+<?xml version="1.0"?>
+<metadata>
+ <description>%s</description>
+ <version>%s</version>
+ <dependencies>
+ <dependency>%s</dependency>
+ <dependency>%s</dependency>
+ </dependencies>
+</metadata>
+""" % (desc, version, dep1, dep2)
+
+_METADATA_MAP = {
+ 'description': desc,
+ 'version': version,
+ 'dependencies': (dep1, dep2),
+ }
+
+class ProfileMetadataTests( ZopeTestCase ):
+
+ installProduct('GenericSetup')
+
+ def test_parseXML(self):
+ metadata = ProfileMetadata( '' )
+ parsed = metadata.parseXML( _METADATA_XML )
+ self.assertEqual(parsed, _METADATA_MAP)
+
+ def test_versionFromProduct(self):
+ profile_id = 'dummy_profile'
+ product_name = 'GenericSetup'
+ directory = os.path.split(__file__)[0]
+ path = os.path.join(directory, 'default_profile')
+ profile_registry.registerProfile( profile_id,
+ 'Dummy Profile',
+ 'This is a dummy profile',
+ path,
+ product=product_name)
+ profile_info = profile_registry.getProfileInfo('%s:%s' % (product_name,
+ profile_id))
+ product = getattr(self.app.Control_Panel.Products, product_name)
+ self.assertEqual(profile_info['version'], product.version)
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite( ProfileMetadataTests ),
+ ))
+
+if __name__ == '__main__':
+ from Products.GenericSetup.testing import run
+ run(test_suite())
Modified: GenericSetup/branches/tseaver-bbq_sprint/utils.py
===================================================================
--- GenericSetup/branches/tseaver-bbq_sprint/utils.py 2007-03-29 12:57:53 UTC (rev 73909)
+++ GenericSetup/branches/tseaver-bbq_sprint/utils.py 2007-03-29 13:02:36 UTC (rev 73910)
@@ -181,7 +181,9 @@
return self._extractNode(root)
def _extractNode(self, node):
-
+ """ Please see docs/configurator.txt for information about the
+ import mapping syntax.
+ """
nodes_map = self._getImportMapping()
if node.nodeName not in nodes_map:
nodes_map = self._getSharedImportMapping()
More information about the Checkins
mailing list