[Checkins] SVN: zope.release/trunk/ - Added support for a new `extends` option that allows using other controlled

Stephan Richter srichter at cosmos.phy.tufts.edu
Sat Nov 10 13:15:27 EST 2007


Log message for revision 81726:
  - Added support for a new `extends` option that allows using other controlled
    package configurations as a base.
  
  Note: I shamelessly copied the code from buildout.
  
  

Changed:
  U   zope.release/trunk/CHANGES.txt
  U   zope.release/trunk/setup.py
  U   zope.release/trunk/src/zope/release/README.txt
  U   zope.release/trunk/src/zope/release/kgs.py

-=-
Modified: zope.release/trunk/CHANGES.txt
===================================================================
--- zope.release/trunk/CHANGES.txt	2007-11-10 17:26:27 UTC (rev 81725)
+++ zope.release/trunk/CHANGES.txt	2007-11-10 18:15:27 UTC (rev 81726)
@@ -8,11 +8,15 @@
 3.4.0 (2007-11-??)
 ------------------
 
+- Added support for a new `extends` option that allows using other controlled
+  package configurations as a base.
+
 - Refactored configuration file parsing into a new module that provides
   object-oriented output.
 
 - Added tests for the existing code.
 
+- Update package data.
 
 3.4.0b2 (2007-11-05)
 --------------------

Modified: zope.release/trunk/setup.py
===================================================================
--- zope.release/trunk/setup.py	2007-11-10 17:26:27 UTC (rev 81725)
+++ zope.release/trunk/setup.py	2007-11-10 18:15:27 UTC (rev 81726)
@@ -49,6 +49,7 @@
           test=['zope.testing']),
       install_requires=[
           'setuptools',
+          'zc.buildout',
           ],
       entry_points = dict(console_scripts=[
           'generate-buildout = zope.release.buildout:main',

Modified: zope.release/trunk/src/zope/release/README.txt
===================================================================
--- zope.release/trunk/src/zope/release/README.txt	2007-11-10 17:26:27 UTC (rev 81725)
+++ zope.release/trunk/src/zope/release/README.txt	2007-11-10 18:15:27 UTC (rev 81726)
@@ -45,6 +45,30 @@
 to be tested, but some packages require very specific test setups that cannot
 be easily reproduced _[1], so we turn off those tests.
 
+You can also stack controlled package configurations on top of each
+other. Base configurations can be specified using the `extends` option:
+
+  >>> import tempfile
+  >>> cfgFile2 = tempfile.mktemp('-cp.cfg')
+  >>> open(cfgFile2, 'w').write('''\
+  ... [DEFAULT]
+  ... tested = true
+  ...
+  ... [KGS]
+  ... name = grok-dev
+  ... extends = %s
+  ...
+  ... [packageA]
+  ... versions = 1.0.2
+  ...
+  ... [packageD]
+  ... versions = 2.2.3
+  ...            2.2.4
+  ... ''' %cfgFile)
+
+As you can see, you can completely override another package's version
+specification as well.
+
 Generating the configuration file and managing it is actually the hard
 part. Let's now see what we can do with it.
 
@@ -69,7 +93,21 @@
   packageB = 1.2.3
   packageC = 4.3.1
 
+Let's now ensure that the versions also work for the extended configuration:
 
+  >>> versionsFile2 = tempfile.mktemp('-versions.cfg')
+
+  >>> from zope.release import version
+  >>> version.main((cfgFile2, versionsFile2))
+
+  >>> print open(versionsFile2, 'r').read()
+  [versions]
+  packageA = 1.0.2
+  packageB = 1.2.3
+  packageC = 4.3.1
+  packageD = 2.2.4
+
+
 Generate Buildout
 -----------------
 
@@ -97,7 +135,32 @@
   packageC = 4.3.1
   <BLANKLINE>
 
+Let's make sure that the buildout generation also honors the extensions:
 
+  >>> buildoutFile2 = tempfile.mktemp('-buildout.cfg')
+
+  >>> from zope.release import buildout
+  >>> buildout.main((cfgFile2, buildoutFile2))
+
+  >>> print open(buildoutFile2, 'r').read()
+  [buildout]
+  parts = test
+  versions = versions
+  <BLANKLINE>
+  [test]
+  recipe = zc.recipe.testrunner
+  eggs = packageA
+      packageB
+      packageD
+  <BLANKLINE>
+  [versions]
+  packageA = 1.0.2
+  packageB = 1.2.3
+  packageC = 4.3.1
+  packageD = 2.2.4
+  <BLANKLINE>
+
+
 Uploading Files
 ---------------
 
@@ -235,3 +298,19 @@
   ['1.0.0', '1.0.1']
   >>> pkgA.tested
   True
+
+As we have seen in the scripts above, the KGS class also supports the
+`entends` option. Thus, let's load the KGS for the config file 2:
+
+  >>> myKGS2 = kgs.KGS(cfgFile2)
+  >>> myKGS2
+  <KGS 'grok-dev'>
+
+  >>> myKGS2.name
+  'grok-dev'
+
+  >>> myKGS2.packages
+  [<Package 'packageA'>,
+   <Package 'packageB'>,
+   <Package 'packageC'>,
+   <Package 'packageD'>]

Modified: zope.release/trunk/src/zope/release/kgs.py
===================================================================
--- zope.release/trunk/src/zope/release/kgs.py	2007-11-10 17:26:27 UTC (rev 81725)
+++ zope.release/trunk/src/zope/release/kgs.py	2007-11-10 18:15:27 UTC (rev 81726)
@@ -12,8 +12,65 @@
 #
 ##############################################################################
 """KGS configuration file parser."""
+import os.path
+import urllib2
 import ConfigParser
+from zc.buildout.buildout import _update, _isurl
 
+MAIN_SECTION = 'KGS'
+EXTENDS_OPTION = 'extends'
+
+def _open(base, filename, seen):
+    """Open a configuration file and return the result as a dictionary,
+
+    Recursively open other files based on options found.
+
+    Note: Shamelessly copied from zc.buildout!
+    """
+
+    if _isurl(filename):
+        fp = urllib2.urlopen(filename)
+        base = filename[:filename.rfind('/')]
+    elif _isurl(base):
+        if os.path.isabs(filename):
+            fp = open(filename)
+            base = os.path.dirname(filename)
+        else:
+            filename = base + '/' + filename
+            fp = urllib2.urlopen(filename)
+            base = filename[:filename.rfind('/')]
+    else:
+        filename = os.path.join(base, filename)
+        fp = open(filename)
+        base = os.path.dirname(filename)
+
+    if filename in seen:
+        raise ValueError("Recursive file include", seen, filename)
+
+    seen.append(filename)
+
+    result = {}
+
+    parser = ConfigParser.RawConfigParser()
+    parser.optionxform = lambda s: s
+    parser.readfp(fp)
+    extends = None
+    for section in parser.sections():
+        options = dict(parser.items(section))
+        if section == MAIN_SECTION:
+            extends = options.pop(EXTENDS_OPTION, extends)
+        result[section] = options
+
+    if extends:
+        extends = extends.split()
+        extends.reverse()
+        for fname in extends:
+            result = _update(_open(base, fname, seen), result)
+
+    seen.pop()
+    return result
+
+
 class Package(object):
 
     def __init__(self, name, versions, tested):
@@ -35,19 +92,19 @@
         self._extract()
 
     def _extract(self):
-        config = ConfigParser.RawConfigParser()
-        config.read(self.path)
-        if config.has_section('KGS'):
-            self.name = config.get('KGS', 'name')
-            config.remove_section('KGS')
+        result = _open(os.path.dirname(self.path), self.path, [])
+        if MAIN_SECTION in result:
+            self.name = result[MAIN_SECTION].get('name', u'')
+            del result[MAIN_SECTION]
         self.packages = []
-        sections = config.sections()
+        sections = result.keys()
         sections.sort()
         for section in sections:
             self.packages.append(
                 Package(section,
-                        config.get(section, 'versions').split(),
-                        config.getboolean(section, 'tested')
+                        result[section]['versions'].split(),
+                        ConfigParser.ConfigParser._boolean_states[
+                            result[section]['tested']]
                         )
                 )
 



More information about the Checkins mailing list