[Checkins] SVN: zope.kgs/trunk/ - Collected all generic KGS-related scripts into one package.

Stephan Richter srichter at cosmos.phy.tufts.edu
Fri Nov 16 21:31:31 EST 2007


Log message for revision 81891:
  - Collected all generic KGS-related scripts into one package.
  
  - Implemented some new features based on recent zope-dev discussions, such as a find 
    link.
  
  - Made server maintainance much simpler by having a generator for all files.
  
  - Provided features to keep history better.
  
  

Changed:
  _U  zope.kgs/trunk/
  U   zope.kgs/trunk/CHANGES.txt
  U   zope.kgs/trunk/buildout.cfg
  U   zope.kgs/trunk/setup.py
  _U  zope.kgs/trunk/src/
  A   zope.kgs/trunk/src/zope/kgs/README.txt
  A   zope.kgs/trunk/src/zope/kgs/buildout.cfg.in
  A   zope.kgs/trunk/src/zope/kgs/buildout.py
  A   zope.kgs/trunk/src/zope/kgs/intro.pt
  A   zope.kgs/trunk/src/zope/kgs/intro.py
  A   zope.kgs/trunk/src/zope/kgs/kgs.py
  A   zope.kgs/trunk/src/zope/kgs/link.py
  A   zope.kgs/trunk/src/zope/kgs/ppix.py
  A   zope.kgs/trunk/src/zope/kgs/site.py
  A   zope.kgs/trunk/src/zope/kgs/tests.py
  A   zope.kgs/trunk/src/zope/kgs/version.py

-=-

Property changes on: zope.kgs/trunk
___________________________________________________________________
Name: svn:ignore
   + .installed.cfg
bin
develop-eggs
dist
parts
python

Name: svn:externals
   + 


Modified: zope.kgs/trunk/CHANGES.txt
===================================================================
--- zope.kgs/trunk/CHANGES.txt	2007-11-17 01:18:45 UTC (rev 81890)
+++ zope.kgs/trunk/CHANGES.txt	2007-11-17 02:31:30 UTC (rev 81891)
@@ -7,8 +7,18 @@
 
 - Initial version as ``zope.kgs``.
 
+  * A script that manages the generation of the entire site.
+
+  * Generate an intro page to the KGS.
+
+  * Generate `links.html` file which lists all controlled packages files.
+
   * Features copied from ``zope.release``:
 
     + Parser for KGS configuration files.
 
     + Generate `versions.cfg` and `buildout.cfg` script.
+
+  * Features copied from ``zc.mirrorcheeseshopslashsimple``:
+
+    + Generate new index pages for the controlled packages.

Modified: zope.kgs/trunk/buildout.cfg
===================================================================
--- zope.kgs/trunk/buildout.cfg	2007-11-17 01:18:45 UTC (rev 81890)
+++ zope.kgs/trunk/buildout.cfg	2007-11-17 02:31:30 UTC (rev 81891)
@@ -1,22 +1,12 @@
 [buildout]
 develop = .
 index = http://download.zope.org/zope3.4
-parts = test generate-buildout generate-versions
+parts = test scripts
 
 [test]
 recipe = zc.recipe.testrunner
 eggs = zope.kgs [test]
 
-[generate-buildout]
+[scripts]
 recipe = zc.recipe.egg:scripts
 eggs = zope.kgs
-scripts = generate-buildout
-arguments = ('controlled-packages.cfg',
-             './test/buildout.cfg')
-
-[generate-versions]
-recipe = zc.recipe.egg:scripts
-eggs = zope.kgs
-scripts = generate-versions
-arguments = ('controlled-packages.cfg',
-             './test/versions.cfg')

Modified: zope.kgs/trunk/setup.py
===================================================================
--- zope.kgs/trunk/setup.py	2007-11-17 01:18:45 UTC (rev 81890)
+++ zope.kgs/trunk/setup.py	2007-11-17 02:31:30 UTC (rev 81891)
@@ -46,14 +46,20 @@
       package_dir = {'': 'src'},
       namespace_packages=['zope'],
       extras_require = dict(
-          test=['zope.testing']),
+          test=['zope.testing'],
+          ),
       install_requires=[
           'setuptools',
           'zc.buildout',
+          'zope.pagetemplate',
           ],
       entry_points = dict(console_scripts=[
           'generate-buildout = zope.kgs.buildout:main',
           'generate-versions = zope.kgs.version:main',
+          'generate-index = zope.kgs.ppix:main',
+          'generate-links = zope.kgs.link:main',
+          'generate-intro = zope.kgs.intro:main',
+          'generate-site = zope.kgs.site:main',
           ]),
       include_package_data = True,
       zip_safe = False,


Property changes on: zope.kgs/trunk/src
___________________________________________________________________
Name: svn:ignore
   + zope.kgs.egg-info


Copied: zope.kgs/trunk/src/zope/kgs/README.txt (from rev 81726, zope.release/trunk/src/zope/release/README.txt)
===================================================================
--- zope.kgs/trunk/src/zope/kgs/README.txt	                        (rev 0)
+++ zope.kgs/trunk/src/zope/kgs/README.txt	2007-11-17 02:31:30 UTC (rev 81891)
@@ -0,0 +1,477 @@
+===============
+Known Good Sets
+===============
+
+This package provides a set of scripts and tools to manage Good-Known-Sets, or
+short KGSs. A KGS is a set of package distributions that are known to work
+well together. You can verify this, for example, by running all the tests of
+all the packages at once.
+
+Let me show you how a typical controlled packages configuration file looks
+like:
+
+  >>> import tempfile
+  >>> cfgFile = tempfile.mktemp('-cp.cfg')
+  >>> open(cfgFile, 'w').write('''\
+  ... [DEFAULT]
+  ... tested = true
+  ...
+  ... [KGS]
+  ... name = zope-dev
+  ... version = 1.2.0
+  ...
+  ... [packageA]
+  ... versions = 1.0.0
+  ...            1.0.1
+  ...
+  ... [packageB]
+  ... versions = 1.2.3
+  ...
+  ... [packageC]
+  ... # Do not test this package.
+  ... tested = false
+  ... versions = 4.3.1
+  ... ''')
+
+As you can see, this file uses an INI-style format. The "DEFAULT" section is
+special, as it will insert the specified options into all other sections as
+default. The "KGS" section specifies some global information about the KGS,
+such as the name of the KGS.
+
+All other sections refer to package names. Currently each package section
+supports two options. The "versions" option lists all versions that are known
+to work in the KGS. Those versions should *always* only be bug fixes to the
+first listed version. The second option, "tested", specifies whether the
+package should be part of the KGS test suite. By default, we want all packages
+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
+  ... version = 0.1.0
+  ... 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.
+
+.. [1]: This is usually due to bugs in setuptools or buildout, such as PYC
+files not containing the correct reference to their PY file.
+
+
+Generate Versions
+-----------------
+
+One of the easiest scripts, is the version generation. This script will
+generate a "versions" section that is compatible with buildout.
+
+  >>> versionsFile = tempfile.mktemp('-versions.cfg')
+
+  >>> from zope.kgs import version
+  >>> version.main((cfgFile, versionsFile))
+
+  >>> print open(versionsFile, 'r').read()
+  [versions]
+  packageA = 1.0.1
+  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')
+
+  >>> 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
+-----------------
+
+In order to be able to test the KGS, you can also generate a full buildout
+file that will create and install a testrunner over all packages for you:
+
+  >>> buildoutFile = tempfile.mktemp('-buildout.cfg')
+
+  >>> from zope.kgs import buildout
+  >>> buildout.main((cfgFile, buildoutFile))
+
+  >>> print open(buildoutFile, 'r').read()
+  [buildout]
+  parts = test
+  versions = versions
+  <BLANKLINE>
+  [test]
+  recipe = zc.recipe.testrunner
+  eggs = packageA
+      packageB
+  <BLANKLINE>
+  [versions]
+  packageA = 1.0.1
+  packageB = 1.2.3
+  packageC = 4.3.1
+  <BLANKLINE>
+
+Let's make sure that the buildout generation also honors the extensions:
+
+  >>> buildoutFile2 = tempfile.mktemp('-buildout.cfg')
+
+  >>> 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>
+
+
+Flat Links Pages
+----------------
+
+We can also create a flat links page that can be used in the
+`dependency_links` argument in your `setup.py` file. Since this module
+accesses the original PyPI to ask for the download locations and filenames, we
+have to create a controlled packages configuration file that contains real
+packages with real version numbers:
+
+  >>> cfgFileReal = tempfile.mktemp('-cp.cfg')
+  >>> open(cfgFileReal, 'w').write('''\
+  ... [DEFAULT]
+  ... tested = true
+  ...
+  ... [KGS]
+  ... name = zope-dev
+  ... version = 3.4.0b2
+  ...
+  ... [PIL]
+  ... versions = 1.1.6
+  ...
+  ... [zope.component]
+  ... versions = 3.4.0
+  ...
+  ... [zope.interface]
+  ... versions = 3.4.0
+  ...            3.4.1
+  ... ''')
+
+Let's now create the links page:
+
+  >>> linksFile = tempfile.mktemp('-links.html')
+
+  >>> from zope.kgs import link
+  >>> link.main((cfgFileReal, linksFile))
+
+  >>> print open(linksFile, 'r').read()
+  <html>
+  <head>
+  <title>Links for the "zope-dev" KGS (version 3.4.0b2)</title>
+  </head>
+  <body>
+  <h1>Links for the "zope-dev" KGS (version 3.4.0b2)</h1>
+  <a href="http://pypi.python.org/packages/source/z/zope.component/zope.component-3.4.0.tar.gz#md5=94afb57dfe605d7235ff562d1eaa3bed">zope.component-3.4.0.tar.gz</a><br/>
+  <a href="http://pypi.python.org/packages/2.4/z/zope.component/zope.component-3.4.0-py2.4.egg#md5=c0763e94912e4a8ac1e321a068c916ba">zope.component-3.4.0-py2.4.egg</a><br/>
+  <a href="http://pypi.python.org/packages/source/z/zope.interface/zope.interface-3.4.0.tar.gz#md5=0be9fd80b7bb6bee520e56eba7d29c90">zope.interface-3.4.0.tar.gz</a><br/>
+  <a href="http://pypi.python.org/packages/2.4/z/zope.interface/zope.interface-3.4.0-py2.4-win32.egg#md5=3fa5e992271375eac597622d8e2fd5ec">zope.interface-3.4.0-py2.4-win32.egg</a><br/>
+  <a href="http://pypi.python.org/packages/source/z/zope.interface/zope.interface-3.4.1.tar.gz#md5=b085f4a774adab688e037ad32fbbf08e">zope.interface-3.4.1.tar.gz</a><br/>
+  </body>
+  </html>
+
+PPIX Support
+------------
+
+You can also use the KGS to limit the available packages in a package index
+generated ``zc.mirrorcheeseshopslashsimple``. This script also uses PyPI to
+look up distribution file, so wave to use the real configuration file again.
+
+Let's create the pages:
+
+  >>> indexDir = tempfile.mkdtemp('-ppix')
+
+  >>> from zope.kgs import ppix
+  >>> ppix.main((cfgFileReal, indexDir))
+
+The index contains one directory per package. So let's have a look:
+
+  >>> import os
+  >>> sorted(os.listdir(indexDir))
+  ['PIL', 'zope.component', 'zope.interface']
+
+Each directory contains a single "index.html" file with the download links:
+
+  >>> pkgDir = os.path.join(indexDir, 'zope.component')
+  >>> sorted(os.listdir(pkgDir))
+  ['index.html']
+
+  >>> pkgIndex = os.path.join(pkgDir, 'index.html')
+  >>> print open(pkgIndex, 'r').read()
+  <html>
+  <head>
+  <title>Links for "zope.component"</title>
+  </head>
+  <body>
+  <h1>Links for "zope.component"</h1>
+  <a href="http://pypi.python.org/packages/source/z/zope.component/zope.component-3.4.0.tar.gz#md5=94afb57dfe605d7235ff562d1eaa3bed">zope.component-3.4.0.tar.gz</a><br/>
+  <a href="http://pypi.python.org/packages/2.4/z/zope.component/zope.component-3.4.0-py2.4.egg#md5=c0763e94912e4a8ac1e321a068c916ba">zope.component-3.4.0-py2.4.egg</a><br/>
+  </body>
+  </html>
+
+PIL is an interesting case, because it does not upload its distribution files
+yet, at least not for version 1.1.6:
+
+  >>> pkgIndex = os.path.join(indexDir, 'PIL', 'index.html')
+  >>> print open(pkgIndex, 'r').read()
+  <html><head><title>Links for PIL</title></head><body><h1>Links for PIL</h1><a href='http://www.pythonware.com/products/pil' rel="homepage">1.1.6 home_page</a><br/>
+  <a href='http://effbot.org/downloads/#Imaging' rel="download">1.1.6 download_url</a><br/>
+  <a href='http://www.pythonware.com/products/pil/' rel="homepage">1.1.4 home_page</a><br/>
+  <a href='http://www.pythonware.com/products/pil/' rel="homepage">1.1.3 home_page</a><br/>
+  <a href='http://www.pythonware.com/downloads/Imaging-1.1.3.tar.gz' rel="download">1.1.3 download_url</a><br/>
+  <a href='http://www.pythonware.com/products/pil' rel="homepage">1.1.5a1 home_page</a><br/>
+  <a href='http://effbot.org/zone/pil-changes-115.htm' rel="download">1.1.5a1 download_url</a><br/>
+  <a href='http://www.pythonware.com/products/pil' rel="homepage">1.1.5a2 home_page</a><br/>
+  <a href='http://effbot.org/zone/pil-changes-115.htm' rel="download">1.1.5a2 download_url</a><br/>
+  <a href='http://www.pythonware.com/products/pil' rel="homepage">1.1.5 home_page</a><br/>
+  <a href='http://effbot.org/zone/pil-changes-115.htm' rel="download">1.1.5 download_url</a><br/>
+  </body></html>
+
+Optionally, you can also specify the `-i` option to generate an overview:
+
+  >>> ppix.main(('-i', cfgFileReal, indexDir))
+
+  >>> sorted(os.listdir(indexDir))
+  ['PIL', 'index.html', 'zope.component', 'zope.interface']
+
+Let's now look at the file:
+
+  >>> indexPage = os.path.join(indexDir, 'index.html')
+  >>> print open(indexPage, 'r').read()
+  <html>
+  <head>
+  <title>Simple Index for the "zope-dev" KGS (version 3.4.0b2)</title>
+  </head>
+  <body>
+  <h1>Simple Index for the "zope-dev" KGS (version 3.4.0b2)</h1>
+  <a href="PIL">PIL</a><br/>
+  <a href="zope.component">zope.component</a><br/>
+  <a href="zope.interface">zope.interface</a><br/>
+  </body>
+  </html>
+
+Allowing exisitng package pages to be overwritten and making the main index
+page an optional feature makes it possible to use this script for two use
+cases: (1) Merge the constraints into a PPIX index created by
+``zc.mirrorcheeseshopslashsimple``, and (2) create a standalone index which
+only provides the packages of the KGS.
+
+
+Introduction Page
+-----------------
+
+Once all the files have been created, one can generate an introduction page
+that explains how the files can be used. It also lists all the files by
+distribution. In order for this script to work, you need the following
+directory layout:
+
+  >>> kgsDir = tempfile.mkdtemp()
+
+  >>> open(os.path.join(kgsDir, 'controlled-packages.cfg'), 'w').write(' ')
+  >>> open(os.path.join(kgsDir, 'buildout.cfg'), 'w').write(' ')
+  >>> open(os.path.join(kgsDir, 'versions.cfg'), 'w').write(' ')
+  >>> open(os.path.join(kgsDir, 'links.cfg'), 'w').write(' ')
+
+  >>> open(os.path.join(kgsDir, 'controlled-packages-1.0.0.cfg'), 'w').write(' ')
+  >>> open(os.path.join(kgsDir, 'buildout-1.0.0.cfg'), 'w').write(' ')
+  >>> open(os.path.join(kgsDir, 'versions-1.0.0.cfg'), 'w').write(' ')
+
+  >>> open(os.path.join(kgsDir, 'controlled-packages-1.1.0.cfg'), 'w').write(' ')
+  >>> open(os.path.join(kgsDir, 'buildout-1.1.0.cfg'), 'w').write(' ')
+  >>> open(os.path.join(kgsDir, 'versions-1.1.0.cfg'), 'w').write(' ')
+  >>> open(os.path.join(kgsDir, 'links-1.1.0.cfg'), 'w').write(' ')
+
+  >>> open(os.path.join(kgsDir, 'index.html'), 'w').write(' ')
+  >>> os.mkdir(os.path.join(kgsDir, 'minimal'))
+
+Let's now generate the page:
+
+  >>> introPage = os.path.join(kgsDir, 'intro.html')
+
+  >>> from zope.kgs import intro
+  >>> intro.main((introPage,))
+
+  >>> print open(introPage, 'r').read()
+    <!DOCTYPE ...
+      <body>
+        <h1>Introduction to the KGS</h1>
+        <h2>Available Versions</h2>
+        <h3>Version 1.0.0</h3>
+        <ul>
+          <li>
+            <a href="controlled-packages-1.0.0.cfg">Controlled Packages</a>
+          </li>
+          <li>
+            <a href="versions-1.0.0.cfg">Versions</a>
+          </li>
+          <li>
+            <a href="index.html">Index</a>
+          </li>
+          <li>
+            <a href="minimal">Minimal Index</a>
+          </li>
+        </ul>
+        <h3>Version 1.1.0</h3>
+        <ul>
+          <li>
+            <a href="controlled-packages-1.1.0.cfg">Controlled Packages</a>
+          </li>
+          <li>
+            <a href="versions-1.1.0.cfg">Versions</a>
+          </li>
+          <li>
+            <a href="index.html">Index</a>
+          </li>
+          <li>
+            <a href="minimal">Minimal Index</a>
+          </li>
+        </ul>
+        ...
+      </body>
+    </html>
+
+
+The Site Generator
+------------------
+
+The easiest way to publish the KGS is via a directory published by a Web
+server. Whenever a new `controlled-packages.cfg` file is uploaded, a script is
+run that generates all the files. I usually set up a crontab job to do
+this. The site generator script acts upon a directory, in which it assumes a
+`controlled-packages.cfg` file was placed:
+
+  >>> siteDir = tempfile.mkdtemp()
+  >>> cfgFileSite = os.path.join(siteDir, 'controlled-packages.cfg')
+
+  >>> import shutil
+  >>> shutil.copy(cfgFileReal, cfgFileSite)
+
+  >>> from zope.kgs import site
+  >>> site.main((siteDir,))
+
+Let's have a look at the generated files:
+
+  >>> sorted(os.listdir(siteDir))
+  ['PIL',
+   'buildout-3.4.0b2.cfg', 'buildout.cfg',
+   'cf-timestamp',
+   'controlled-packages-3.4.0b2.cfg', 'controlled-packages.cfg',
+   'intro.html',
+   'links-3.4.0b2.cfg', 'links.cfg',
+   'minimal',
+   'versions-3.4.0b2.cfg', 'versions.cfg',
+   'zope.component', 'zope.interface']
+
+  >>> sorted(os.listdir(os.path.join(siteDir, 'minimal')))
+  ['PIL', 'index.html', 'zope.component', 'zope.interface']
+
+If you try to generate the site again without changing the controlled packages
+config file, it will simply return, because it checks the timestamp from the
+previous generation:
+
+  >>> tsPath = os.path.join(siteDir, 'cf-timestamp')
+
+  >>> beforeTimestamp = open(tsPath).read()
+  >>> site.main((siteDir,))
+  >>> afterTimestamp = open(tsPath).read()
+
+  >>> beforeTimestamp == afterTimestamp
+  True
+
+
+Basic Parser API
+----------------
+
+The ``kgs.py`` module provides a simple class that parses the KGS
+configuration file and provides all data in an object-oriented manner.
+
+  >>> from zope.kgs import kgs
+
+The class is simply instnatiated using the path to the config file:
+
+  >>> myKGS = kgs.KGS(cfgFile)
+  >>> myKGS
+  <KGS 'zope-dev'>
+
+The name and version  of the KGS is available via:
+
+  >>> myKGS.name
+  'zope-dev'
+  >>> myKGS.version
+  '1.2.0'
+
+The packages are available under `packages`:
+
+  >>> myKGS.packages
+  [<Package 'packageA'>, <Package 'packageB'>, <Package 'packageC'>]
+
+Each package is also an object:
+
+  >>> pkgA = myKGS.packages[0]
+  >>> pkgA
+  <Package 'packageA'>
+
+  >>> pkgA.name
+  'packageA'
+  >>> pkgA.versions
+  ['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'>]

Copied: zope.kgs/trunk/src/zope/kgs/buildout.cfg.in (from rev 81726, zope.release/trunk/src/zope/release/buildout.cfg.in)
===================================================================
--- zope.kgs/trunk/src/zope/kgs/buildout.cfg.in	                        (rev 0)
+++ zope.kgs/trunk/src/zope/kgs/buildout.cfg.in	2007-11-17 02:31:30 UTC (rev 81891)
@@ -0,0 +1,10 @@
+[buildout]
+parts = test
+versions = versions
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = %(tested-packages)s
+
+[versions]
+%(versions)s

Copied: zope.kgs/trunk/src/zope/kgs/buildout.py (from rev 81726, zope.release/trunk/src/zope/release/buildout.py)
===================================================================
--- zope.kgs/trunk/src/zope/kgs/buildout.py	                        (rev 0)
+++ zope.kgs/trunk/src/zope/kgs/buildout.py	2007-11-17 02:31:30 UTC (rev 81891)
@@ -0,0 +1,73 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Generate a ``buildout.cfg`` file from the controlled list of packages.
+
+Usage: generate-buildout package-cfg-path [output-cfg-path]
+
+* ``package-cfg-path``
+
+  This is the path to the controlled packages configuration file.
+
+* ``output-cfg-path``
+
+  The path of the file under which the generated buildout configuration file
+  is stored. By default it is placed in the package configuration file's
+  directory under the name 'test-buildout.cfg'.
+
+"""
+import ConfigParser
+import os
+
+from zope.kgs import kgs
+
+def getVersionsListing(packages):
+    """Create a version listing string."""
+    return '\n'.join(
+        [package.name + ' = ' + package.versions[-1]
+         for package in packages])
+
+
+def generateBuildout(packageConfigPath, outputPath):
+    """Generate a ``buildout.cfg`` from the list of controlled packages."""
+    # Load all package information from the controlled pacakge config file.
+    packages = kgs.KGS(packageConfigPath).packages
+
+    # Create the data dictionary
+    data = {
+        'tested-packages': '\n    '.join(
+            [package.name for package in packages if package.tested]),
+        'versions': getVersionsListing(packages)
+        }
+
+    # Write a new buildout.cfg file
+    templatePath = os.path.join(os.path.dirname(__file__), 'buildout.cfg.in')
+    open(outputPath, 'w').write(open(templatePath, 'r').read() %data)
+
+
+def main(args=None):
+    if args is None:
+        args = sys.argv[1:]
+
+    if len(args) < 1:
+        print __file__.__doc__
+        sys.exit(1)
+
+    packageConfigPath = os.path.abspath(args[0])
+
+    outputPath = os.path.join(
+        os.path.dirname(packageConfigPath), 'test-buildout.cfg')
+    if len(args) == 2:
+        outputPath = args[1]
+
+    generateBuildout(packageConfigPath, outputPath)

Added: zope.kgs/trunk/src/zope/kgs/intro.pt
===================================================================
--- zope.kgs/trunk/src/zope/kgs/intro.pt	                        (rev 0)
+++ zope.kgs/trunk/src/zope/kgs/intro.pt	2007-11-17 02:31:30 UTC (rev 81891)
@@ -0,0 +1,115 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+  <head>
+    <title>Introduction to the KGS</title>
+  </head>
+  <body>
+    <h1>Introduction to the KGS</h1>
+
+    <h2>Available Versions</h2>
+
+    <tal:block repeat="version self/versions">
+    <h3>Version <span tal:replace="version/name" /></h3>
+    <ul>
+      <li tal:repeat="feature version/features">
+        <a href="versions-1.0.0.cfg"
+           tal:attributes="href feature/url"
+           tal:content="feature/title">Versions</a>
+      </li>
+    </ul>
+    </tal:block>
+
+
+    <h2>Usage</h2>
+
+    <p>
+      This KGS was designed to work with many of the tools developed to
+      manage and install Python pacakges. The following sub-sections will
+      explain its use in more detail.
+    </p>
+
+    <h3>The Index</h3>
+
+    <p>
+      You can use the index directly. It then behaves exactely like
+      <a href="http://pypi.python.org/simple">http://pypi.python.org/simple</a>,
+      except that for the controlled packages only the good versions are
+      available. The advantage of using the KGS as an index is that you get
+      bug fixes automatically.
+    </p>
+
+    <ul>
+      <li>
+        <div>Buildout, <code>buildout.cfg</code>:</div>
+        <pre>
+          [buildout]
+          index = http://download.project.org/kgs
+          ...
+        </pre>
+      </li>
+      <li>
+        <div>Setup Tools, <code>easy_install</code></div>
+        <pre>
+          $ easy_install -i http://download.project.org/kgs mypackage
+        </pre>
+      </li>
+    </ul>
+
+    <h3>Nailed or Pinned Versions</h3>
+
+    <p>
+      When deploying an application, it is often important to nail or pin down
+      the versions of all used packages, so that it can be guaranteed that the
+      setup is identical all the time.
+    </p>
+
+    <ul>
+      <li>
+        <div>Buildout, <code>buildout.cfg</code>:</div>
+        <pre>
+          [buildout]
+          versions = versions
+          ...
+          [version]
+          zope.interface = 3.4.0
+          (copy the content here)
+        </pre>
+        or
+        <pre>
+          [buildout]
+          extend = http://download.project.org/kgs/versions-1.0.0.cfg
+        </pre>
+      </li>
+      <li>
+        <div>Setup Tools itself cannot use the <code>version.cfg</code>
+          file.</div>
+      </li>
+    </ul>
+
+    <h3>Find Links</h3>
+
+    <p>
+      The way of providing the installation tools with additional locations to
+      look for packages is via find links. Those URLs are expected to be an
+      HTML page with links to files or files directly.
+    </p>
+
+    <ul>
+      <li>
+        <div>Buildout, <code>buildout.cfg</code>:</div>
+        <pre>
+          [buildout]
+          find-links = http://download.project.org/kgs/links.html
+          ...
+        </pre>
+      </li>
+      <li>
+        <div>Setup Tools, <code>easy_install</code></div>
+        <pre>
+          $ easy_install -f http://download.project.org/kgs/links.html mypackage
+        </pre>
+      </li>
+    </ul>
+
+  </body>
+</html>


Property changes on: zope.kgs/trunk/src/zope/kgs/intro.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: zope.kgs/trunk/src/zope/kgs/intro.py
===================================================================
--- zope.kgs/trunk/src/zope/kgs/intro.py	                        (rev 0)
+++ zope.kgs/trunk/src/zope/kgs/intro.py	2007-11-17 02:31:30 UTC (rev 81891)
@@ -0,0 +1,79 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Generate an Introduction HTML page for the KGS.
+
+Usage: %s output-intro-path
+
+* ``output-intro-path``
+
+  The path of the file under which the generated intro file is stored.
+"""
+import os
+import zope.pagetemplate.pagetemplatefile
+
+FEATURES = [
+    ('controlled-packages-%(version)s.cfg', u'Controlled Packages'),
+    ('buildout-%s.cfg',                     u'Buildout Configuration'),
+    ('versions-%(version)s.cfg',            u'Versions'),
+    ('links-%(version)s.html',              u'Package Links'),
+    ('index.html',                          u'Index'),
+    ('minimal',                             u'Minimal Index'),
+    ]
+
+TEMPLATE_PATH = os.path.join(os.path.dirname(__file__), 'intro.pt')
+
+class IntroPage(zope.pagetemplate.pagetemplatefile.PageTemplateFile):
+
+    def __init__(self, kgsDir):
+        super(IntroPage, self).__init__(TEMPLATE_PATH)
+        self.kgsDir = kgsDir
+
+    def update(self):
+        kgsFileNames = os.listdir(self.kgsDir)
+        vnums = [fn[20:-4] for fn in kgsFileNames
+                 if fn.startswith('controlled-packages-')]
+        vnums.sort()
+        self.versions = []
+        for vnum in vnums:
+            features = []
+            for (templ, title) in FEATURES:
+                featureFileName = templ %{'version': vnum}
+                if featureFileName in kgsFileNames:
+                    features.append({'url': featureFileName, 'title': title})
+            self.versions.append({'name': vnum, 'features': features})
+
+
+    def pt_getContext(self, args=(), options=None, **ignore):
+        rval = {'args': args,
+                'nothing': None,
+                'options': options,
+                'self': self
+                }
+        rval.update(self.pt_getEngine().getBaseNames())
+        return rval
+
+
+def main(args=None):
+    if args is None:
+        args = sys.argv[1:]
+
+    if len(args) < 0:
+        print __file__.__doc__
+        sys.exit(1)
+
+    outputPath = args[0]
+
+    page = IntroPage(os.path.dirname(outputPath))
+    page.update()
+    open(outputPath, 'w').write(page())


Property changes on: zope.kgs/trunk/src/zope/kgs/intro.py
___________________________________________________________________
Name: svn:keywords
   + Id

Copied: zope.kgs/trunk/src/zope/kgs/kgs.py (from rev 81726, zope.release/trunk/src/zope/release/kgs.py)
===================================================================
--- zope.kgs/trunk/src/zope/kgs/kgs.py	                        (rev 0)
+++ zope.kgs/trunk/src/zope/kgs/kgs.py	2007-11-17 02:31:30 UTC (rev 81891)
@@ -0,0 +1,115 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""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):
+        self.name = name
+        self.versions = versions
+        self.tested = tested
+
+    def __repr__(self):
+        return '<%s %r>' %(self.__class__.__name__, self.name)
+
+
+class KGS(object):
+
+    name = u'noname'
+    version = u'unknown'
+    packages = ()
+
+    def __init__(self, path):
+        self.path = path
+        self._extract()
+
+    def _extract(self):
+        result = _open(os.path.dirname(self.path), self.path, [])
+        if MAIN_SECTION in result:
+            self.name = result[MAIN_SECTION].get('name', self.name)
+            self.version = result[MAIN_SECTION].get('version', self.version)
+            del result[MAIN_SECTION]
+        self.packages = []
+        sections = result.keys()
+        sections.sort()
+        for section in sections:
+            self.packages.append(
+                Package(section,
+                        result[section]['versions'].split(),
+                        ConfigParser.ConfigParser._boolean_states[
+                            result[section]['tested']]
+                        )
+                )
+
+    def __repr__(self):
+        return '<%s %r>' %(self.__class__.__name__, self.name)
+

Added: zope.kgs/trunk/src/zope/kgs/link.py
===================================================================
--- zope.kgs/trunk/src/zope/kgs/link.py	                        (rev 0)
+++ zope.kgs/trunk/src/zope/kgs/link.py	2007-11-17 02:31:30 UTC (rev 81891)
@@ -0,0 +1,78 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Generate a 'Links' HTML page that can be used as a `find-links` entry in
+setuptools.
+
+Usage: %s package-cfg-path [output-links-path]
+
+* ``package-cfg-path``
+
+  This is the path to the controlled packages configuration file.
+
+* ``output-links-path``
+
+  The path of the file under which the generated links file is stored. By
+  default it is placed in the package configuration file's directory under the
+  name 'links.html'.
+"""
+import os
+import xmlrpclib
+import zope.kgs.kgs
+
+TEMPLATE = ('<html>\n<head>\n'
+            '<title>Links for the "%(name)s" KGS (version %(version)s)</title>\n'
+            '</head>\n'
+            '<body>\n'
+            '<h1>Links for the "%(name)s" KGS (version %(version)s)</h1>\n'
+            '%(links)s\n'
+            '</body>\n'
+            '</html>')
+
+LINK_TEMPLATE = '<a href="%(url)s#md5=%(md5_digest)s">%(filename)s</a><br/>'
+
+def generateLinks(packageConfigPath, outputPath):
+    """Generate a ``buildout.cfg`` from the list of controlled packages."""
+    kgs = zope.kgs.kgs.KGS(packageConfigPath)
+    server = xmlrpclib.Server('http://cheeseshop.python.org/pypi')
+
+    # Collect all links
+    links = []
+    for package in kgs.packages:
+        for version in package.versions:
+            dist_links = server.package_urls(package.name, version)
+            for link in dist_links:
+                links.append(LINK_TEMPLATE %link)
+
+    # Write a new versions.cfg file
+    open(outputPath, 'w').write(
+        TEMPLATE %{'name': kgs.name,
+                   'version': kgs.version,
+                   'links': '\n'.join(links)})
+
+def main(args=None):
+    if args is None:
+        args = sys.argv[1:]
+
+    if len(args) < 1:
+        print __file__.__doc__ % sys.argv[0]
+        sys.exit(1)
+
+    packageConfigPath = os.path.abspath(args[0])
+
+    outputPath = os.path.join(
+        os.path.dirname(packageConfigPath), 'links.html')
+    if len(args) == 2:
+        outputPath = args[1]
+
+    generateLinks(packageConfigPath, outputPath)


Property changes on: zope.kgs/trunk/src/zope/kgs/link.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: zope.kgs/trunk/src/zope/kgs/ppix.py
===================================================================
--- zope.kgs/trunk/src/zope/kgs/ppix.py	                        (rev 0)
+++ zope.kgs/trunk/src/zope/kgs/ppix.py	2007-11-17 02:31:30 UTC (rev 81891)
@@ -0,0 +1,117 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Generate a 'Links' HTML page that can be used as a `find-links` entry in
+setuptools.
+
+Usage: %s [-i] package-cfg-path [output-links-path]
+
+* -i
+
+  When set, this flag causes an `index.html` file to be generated that
+  provides a link to every package's links page.
+
+* ``package-cfg-path``
+
+  This is the path to the controlled packages configuration file.
+
+* ``output-links-path``
+
+  The path of the file under which the generated links file is stored. By
+  default it is placed in the package configuration file's directory under the
+  name 'links.html'.
+"""
+import os
+import urllib
+import urllib2
+import xmlrpclib
+import zope.kgs.kgs
+
+TEMPLATE = ('<html>\n<head>\n<title>%(title)s</title>\n</head>\n'
+            '<body>\n<h1>%(title)s</h1>\n%(body)s\n</body>\n'
+            '</html>')
+
+LINK_TEMPLATE = '<a href="%(url)s#md5=%(md5_digest)s">%(filename)s</a><br/>'
+SIMPLE_LINK_TEMPLATE = '<a href="%(url)s">%(name)s</a><br/>'
+
+SIMPLE_BASE_URL = "http://cheeseshop.python.org/simple/"
+
+def generatePackagePage(package, destDir, server):
+    packagePath = os.path.join(destDir, package.name)
+    links = []
+    for version in package.versions:
+        dist_links = server.package_urls(package.name, version)
+        for link in dist_links:
+            links.append(LINK_TEMPLATE %link)
+
+    if not os.path.exists(packagePath):
+        os.mkdir(packagePath)
+
+    if links:
+        open(os.path.join(packagePath, 'index.html'), 'w').write(
+            TEMPLATE %{'title': 'Links for "%s"' %package.name,
+                       'body': '\n'.join(links)})
+    else:
+        # A small fallback, in case PyPI does not maintain the release
+        # files.
+        page = urllib2.urlopen(SIMPLE_BASE_URL + package.name + '/').read()
+        open(os.path.join(packagePath, 'index.html'), 'w').write(page)
+
+
+def generatePackagePages(packageConfigPath, destDir):
+    kgs = zope.kgs.kgs.KGS(packageConfigPath)
+    server = xmlrpclib.Server('http://cheeseshop.python.org/pypi')
+
+    for package in kgs.packages:
+        generatePackagePage(package, destDir, server)
+
+
+def generateIndexPage(packageConfigPath, destDir):
+    kgs = zope.kgs.kgs.KGS(packageConfigPath)
+    links = []
+    for pkg in kgs.packages:
+        links.append(
+            SIMPLE_LINK_TEMPLATE %{
+                'url': urllib.quote(pkg.name), 'name': pkg.name}
+            )
+    open(os.path.join(destDir, 'index.html'), 'w').write(
+        TEMPLATE %{
+          'title': 'Simple Index for the "%s" KGS (version %s)' %(kgs.name,
+                                                                  kgs.version),
+          'body': '\n'.join(links)})
+
+
+def main(args=None):
+    if args is None:
+        args = sys.argv[1:]
+
+    if len(args) < 1:
+        print __file__.__doc__ % sys.argv[0]
+        sys.exit(1)
+
+    createIndex = False
+    if args[0] == '-i':
+        createIndex = True
+        args = args[1:]
+
+    packageConfigPath = os.path.abspath(args[0])
+
+    destDir = os.path.join(
+        os.path.dirname(packageConfigPath), 'links.html')
+    if len(args) == 2:
+        destDir = args[1]
+
+    generatePackagePages(packageConfigPath, destDir)
+
+    if createIndex:
+        generateIndexPage(packageConfigPath, destDir)


Property changes on: zope.kgs/trunk/src/zope/kgs/ppix.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: zope.kgs/trunk/src/zope/kgs/site.py
===================================================================
--- zope.kgs/trunk/src/zope/kgs/site.py	                        (rev 0)
+++ zope.kgs/trunk/src/zope/kgs/site.py	2007-11-17 02:31:30 UTC (rev 81891)
@@ -0,0 +1,92 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Generates a full KGS site with all bells and whistles.
+
+Usage: %s site-dir
+
+* ``site-dir``
+
+  The path to the directory where a ``controlled-packages.cfg`` file is
+  located to generate the site. The generated site is in that directory as
+  well.
+"""
+import os
+import shutil
+import time
+from zope.kgs import version, buildout, ppix, link, intro, kgs
+
+TIMESTAMP_FILENAME = 'cf-timestamp'
+
+def generateSite(siteDir):
+    kgsPath = os.path.join(siteDir, 'controlled-packages.cfg')
+    ver = kgs.KGS(kgsPath).version
+
+    timestampPath = os.path.join(siteDir, TIMESTAMP_FILENAME)
+
+    # If there have been no changes in the file since the last generation,
+    # simple do not do anything.
+    if os.path.exists(timestampPath):
+        last_update = float(open(timestampPath, 'r').read())
+        last_modified = os.stat(kgsPath)[-2]
+        if last_update > last_modified:
+            return
+
+    # Copy the KGS config file to a versioned version
+    shutil.copy(
+        kgsPath, os.path.join(siteDir, 'controlled-packages-%s.cfg' %ver))
+
+    # Create the buildout config file and version it
+    buildoutPath = os.path.join(siteDir, 'buildout.cfg')
+    buildout.generateBuildout(kgsPath, buildoutPath)
+    shutil.copy(buildoutPath, os.path.join(siteDir, 'buildout-%s.cfg' %ver))
+
+    # Create a versions config file and version it
+    versionsPath = os.path.join(siteDir, 'versions.cfg')
+    version.generateVersions(kgsPath, versionsPath)
+    shutil.copy(versionsPath, os.path.join(siteDir, 'versions-%s.cfg' %ver))
+
+    # Create a links config file and version it
+    linksPath = os.path.join(siteDir, 'links.cfg')
+    link.generateLinks(kgsPath, linksPath)
+    shutil.copy(linksPath, os.path.join(siteDir, 'links-%s.cfg' %ver))
+
+    # Update the full index (which is asummed to live in the site directory)
+    ppix.generatePackagePages(kgsPath, siteDir)
+
+    # Update the minimal index
+    midxDir = os.path.join(siteDir, 'minimal')
+    if not os.path.exists(midxDir):
+        os.mkdir(midxDir)
+    ppix.generatePackagePages(kgsPath, midxDir)
+    ppix.generateIndexPage(kgsPath, midxDir)
+
+    # Update the intro page
+    introPath = os.path.join(siteDir, 'intro.html')
+    intro.main((introPath,))
+
+    # Save the last generation date-time.
+    open(timestampPath, 'w').write(str(time.time()))
+
+
+def main(args=None):
+    if args is None:
+        args = sys.argv[1:]
+
+    if len(args) < 1:
+        print __file__.__doc__ % sys.argv[0]
+        sys.exit(1)
+
+    siteDir = os.path.abspath(args[0])
+
+    generateSite(siteDir)


Property changes on: zope.kgs/trunk/src/zope/kgs/site.py
___________________________________________________________________
Name: svn:keywords
   + Id

Copied: zope.kgs/trunk/src/zope/kgs/tests.py (from rev 81726, zope.release/trunk/src/zope/release/tests.py)
===================================================================
--- zope.kgs/trunk/src/zope/kgs/tests.py	                        (rev 0)
+++ zope.kgs/trunk/src/zope/kgs/tests.py	2007-11-17 02:31:30 UTC (rev 81891)
@@ -0,0 +1,29 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""zope.release tools tests
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+import unittest
+from zope.testing import doctest
+from zope.testing.doctestunit import DocFileSuite
+
+def test_suite():
+    return unittest.TestSuite((
+        DocFileSuite('README.txt',
+                     optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+                     ),
+        ))

Copied: zope.kgs/trunk/src/zope/kgs/version.py (from rev 81726, zope.release/trunk/src/zope/release/version.py)
===================================================================
--- zope.kgs/trunk/src/zope/kgs/version.py	                        (rev 0)
+++ zope.kgs/trunk/src/zope/kgs/version.py	2007-11-17 02:31:30 UTC (rev 81891)
@@ -0,0 +1,62 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Generate a ``latest-versions.cfg`` file from the controlled list of
+packages.
+
+This file can
+
+Usage: generate-buildout package-cfg-path [output-cfg-path]
+
+* ``package-cfg-path``
+
+  This is the path to the controlled packages configuration file.
+
+* ``output-cfg-path``
+
+  The path of the file under which the generated buildout configuration file
+  is stored. By default it is placed in the package configuration file's
+  directory under the name 'latest-versions.cfg'.
+
+"""
+import os
+
+from zope.kgs import buildout, kgs
+
+def generateVersions(packageConfigPath, outputPath):
+    """Generate a ``buildout.cfg`` from the list of controlled packages."""
+    # Load all package information from the controlled pacakge config file.
+    packages = kgs.KGS(packageConfigPath).packages
+
+    # Write a new versions.cfg file
+    open(outputPath, 'w').write(
+        '[versions]\n' +
+        buildout.getVersionsListing(packages))
+
+
+def main(args=None):
+    if args is None:
+        args = sys.argv[1:]
+
+    if len(args) < 1:
+        print __file__.__doc__
+        sys.exit(1)
+
+    packageConfigPath = os.path.abspath(args[0])
+
+    outputPath = os.path.join(
+        os.path.dirname(packageConfigPath), 'latest-versions.cfg')
+    if len(args) == 2:
+        outputPath = args[1]
+
+    generateVersions(packageConfigPath, outputPath)



More information about the Checkins mailing list