[Repoze-checkins] r755 - in repoze.recipe.egg: . trunk trunk/repoze trunk/repoze/recipe trunk/repoze/recipe/egg

Chris McDonough chrism at agendaless.com
Sat Mar 1 07:04:51 UTC 2008


Author: Chris McDonough <chrism at agendaless.com>
Date: Sat Mar  1 02:04:50 2008
New Revision: 755

Log:
(Hopefully) temporary fork of zc.recipe.egg which is willing to install dependent egg scripts.


Added:
   repoze.recipe.egg/
   repoze.recipe.egg/trunk/
   repoze.recipe.egg/trunk/CHANGES.txt
   repoze.recipe.egg/trunk/README.txt
   repoze.recipe.egg/trunk/repoze/
   repoze.recipe.egg/trunk/repoze/__init__.py   (contents, props changed)
   repoze.recipe.egg/trunk/repoze/recipe/
   repoze.recipe.egg/trunk/repoze/recipe/__init__.py   (contents, props changed)
   repoze.recipe.egg/trunk/repoze/recipe/egg/
   repoze.recipe.egg/trunk/repoze/recipe/egg/README.txt
   repoze.recipe.egg/trunk/repoze/recipe/egg/__init__.py   (contents, props changed)
   repoze.recipe.egg/trunk/repoze/recipe/egg/api.txt
   repoze.recipe.egg/trunk/repoze/recipe/egg/custom.py   (contents, props changed)
   repoze.recipe.egg/trunk/repoze/recipe/egg/custom.txt
   repoze.recipe.egg/trunk/repoze/recipe/egg/egg.py   (contents, props changed)
   repoze.recipe.egg/trunk/repoze/recipe/egg/selecting-python.txt
   repoze.recipe.egg/trunk/repoze/recipe/egg/tests.py   (contents, props changed)
   repoze.recipe.egg/trunk/setup.py   (contents, props changed)

Added: repoze.recipe.egg/trunk/CHANGES.txt
==============================================================================
--- (empty file)
+++ repoze.recipe.egg/trunk/CHANGES.txt	Sat Mar  1 02:04:50 2008
@@ -0,0 +1,15 @@
+To do
+*****
+
+- Some way to freeze the egg-versions used.  This includes some way to
+  record which versions were selected dynamially and then a way to
+  require that the recorded versions be used in a later run.
+
+Change History
+**************
+
+Unreleased (2008-02-29)
+=======================
+
+- Fork of zc.recipe.egg 1.0.0 which will install dependent scripts by default.
+

Added: repoze.recipe.egg/trunk/README.txt
==============================================================================
--- (empty file)
+++ repoze.recipe.egg/trunk/README.txt	Sat Mar  1 02:04:50 2008
@@ -0,0 +1,11 @@
+********************************
+Buildout Egg-Installation Recipe
+********************************
+
+.. contents::
+
+The egg-installation recipe is a customization of zc.recipe.egg that
+allows for by-default installs of dependent scripts.
+
+
+

Added: repoze.recipe.egg/trunk/repoze/__init__.py
==============================================================================
--- (empty file)
+++ repoze.recipe.egg/trunk/repoze/__init__.py	Sat Mar  1 02:04:50 2008
@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)

Added: repoze.recipe.egg/trunk/repoze/recipe/__init__.py
==============================================================================
--- (empty file)
+++ repoze.recipe.egg/trunk/repoze/recipe/__init__.py	Sat Mar  1 02:04:50 2008
@@ -0,0 +1 @@
+__import__('pkg_resources').declare_namespace(__name__)

Added: repoze.recipe.egg/trunk/repoze/recipe/egg/README.txt
==============================================================================
--- (empty file)
+++ repoze.recipe.egg/trunk/repoze/recipe/egg/README.txt	Sat Mar  1 02:04:50 2008
@@ -0,0 +1,498 @@
+Installation of distributions as eggs
+=====================================
+
+The repoze.recipe.egg:eggs recipe can be used to install various types if
+distutils distributions as eggs.  It takes a number of options:
+
+eggs
+    A list of eggs to install given as one or more setuptools
+    requirement strings.  Each string must be given on a separate
+    line.
+
+find-links
+   A list of URLs, files, or directories to search for distributions.
+
+index
+   The URL of an index server, or almost any other valid URL. :)
+
+   If not specified, the Python Package Index,
+   http://cheeseshop.python.org/pypi, is used.  You can specify an
+   alternate index with this option.  If you use the links option and
+   if the links point to the needed distributions, then the index can
+   be anything and will be largely ignored.  In the examples, here,
+   we'll just point to an empty directory on our link server.  This
+   will make our examples run a little bit faster.
+
+python
+   The name of a section to get the Python executable from.
+   If not specified, then the buildout python option is used.  The
+   Python executable is found in the executable option of the named
+   section.
+
+We have a link server that has a number of distributions:
+
+    >>> print get(link_server),
+    <html><body>
+    <a href="demo-0.1-py2.3.egg">demo-0.1-py2.3.egg</a><br>
+    <a href="demo-0.2-py2.3.egg">demo-0.2-py2.3.egg</a><br>
+    <a href="demo-0.3-py2.3.egg">demo-0.3-py2.3.egg</a><br>
+    <a href="demo-0.4c1-py2.3.egg">demo-0.4c1-py2.3.egg</a><br>
+    <a href="demoneeded-1.0.zip">demoneeded-1.0.zip</a><br>
+    <a href="demoneeded-1.1.zip">demoneeded-1.1.zip</a><br>
+    <a href="demoneeded-1.2c1.zip">demoneeded-1.2c1.zip</a><br>
+    <a href="extdemo-1.4.zip">extdemo-1.4.zip</a><br>
+    <a href="index/">index/</a><br>
+    <a href="other-1.0-py2.3.egg">other-1.0-py2.3.egg</a><br>
+    </body></html>
+
+We have a sample buildout.  Let's update it's configuration file to
+install the demo package.
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... """
+    ... [buildout]
+    ... parts = demo
+    ...
+    ... [demo]
+    ... recipe = repoze.recipe.egg:eggs
+    ... eggs = demo<0.3
+    ... find-links = %(server)s
+    ... index = %(server)s/index
+    ... """ % dict(server=link_server))
+
+In this example, we limited ourselves to revisions before 0.3. We also
+specified where to find distributions using the find-links option.
+
+Let's run the buildout:
+
+    >>> import os
+    >>> print system(buildout),
+    Installing demo.
+    Getting distribution for 'demo<0.3'.
+    Got demo 0.2.
+    Getting distribution for 'demoneeded'.
+    Got demoneeded 1.2c1.
+
+Now, if we look at the buildout eggs directory:
+
+    >>> ls(sample_buildout, 'eggs')
+    -  demo-0.2-py2.3.egg
+    -  demoneeded-1.2c1-py2.3.egg
+    -  setuptools-0.6-py2.3.egg
+    -  zc.buildout-1.0-py2.3.egg
+
+We see that we got an egg for demo that met the requirement, as well
+as the egg for demoneeded, which demo requires.  (We also see an egg
+link for the recipe in the develop-eggs directory.  This egg link was
+actually created as part of the sample buildout setup. Normally, when
+using the recipe, you'll get a regular egg installation.)
+
+Script generation
+-----------------
+
+The demo egg defined a script, but we didn't get one installed:
+
+    >>> ls(sample_buildout, 'bin')
+    -  buildout
+
+If we want scripts provided by eggs to be installed, we should use the 
+scripts recipe:
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... """
+    ... [buildout]
+    ... parts = demo
+    ...
+    ... [demo]
+    ... recipe = repoze.recipe.egg:scripts
+    ... eggs = demo<0.3
+    ... find-links = %(server)s
+    ... index = %(server)s/index
+    ... """ % dict(server=link_server))
+
+    >>> print system(buildout),
+    Uninstalling demo.
+    Installing demo.
+    Generated script '/sample-buildout/bin/demo'.
+
+Now we also see the script defined by the dmo script:
+
+    >>> ls(sample_buildout, 'bin')
+    -  buildout
+    -  demo
+
+The scripts recipe defines some additional options:
+
+entry-points
+   A list of entry-point identifiers of the form name=module#attrs,
+   name is a script name, module is a module name, and a attrs is a
+   (possibly dotted) name of an object wihin the module.  This option
+   is useful when working with distributions that don't declare entry
+   points, such as distributions not written to work with setuptools.
+
+scripts
+   Control which scripts are generated.  The value should be a list of
+   zero or more tokens.  Each token is either a name, or a name
+   followed by an '=' and a new name.  Only the named scripts are
+   generated.  If no tokens are given, then script generation is
+   disabled.  If the option isn't given at all, then all scripts
+   defined by the named eggs will be generated.
+
+interpreter
+   The name of a script to generate that allows access to a Python
+   interpreter that has the path set based on the eggs installed.
+
+extra-paths
+   Extra paths to include in a generates script.
+
+initialization
+   Specify some Python initialization code.  This is very limited.  In
+   particular, be aware that leading whitespace is stripped from the
+   code given.
+
+arguments
+   Specify some arguments to be passed to entry points as Python source.
+
+Let's add an interpreter option:
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... """
+    ... [buildout]
+    ... parts = demo
+    ...
+    ... [demo]
+    ... recipe = repoze.recipe.egg
+    ... eggs = demo<0.3
+    ... find-links = %(server)s
+    ... index = %(server)s/index
+    ... interpreter = py-demo
+    ... """ % dict(server=link_server))
+
+Note that we ommitted the entry point name from the recipe
+specification. We were able to do this because the scripts recipe if
+the default entry point for the repoze.recipe.egg egg.
+
+   >>> print system(buildout),
+   Uninstalling demo.
+   Installing demo.
+   Generated script '/sample-buildout/bin/demo'.
+   Generated interpreter '/sample-buildout/bin/py-demo'.
+
+Now we also get a py-demo script for giving us a Python prompt with
+the path for demo and any eggs it depends on included in sys.path.
+This is useful for debugging and testing.
+
+    >>> ls(sample_buildout, 'bin')
+    -  buildout
+    -  demo
+    -  py-demo
+
+If we run the demo script, it prints out some minimal data:
+
+    >>> print system(join(sample_buildout, 'bin', 'demo')),
+    2 2
+
+The value it prints out happens to be some values defined in the
+modules installed.
+
+We can also run the py-demo script.  Here we'll just print out
+the bits if the path added to reflect the eggs:
+
+    >>> print system(join(sample_buildout, 'bin', 'py-demo'),
+    ... """import os, sys
+    ... for p in sys.path:
+    ...     if 'demo' in p:
+    ...         print os.path.basename(p)
+    ...
+    ... """).replace('>>> ', '').replace('... ', ''),
+    ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+    demo-0.2-py2.4.egg
+    demoneeded-1.2c1-py2.4.egg
+
+Egg updating
+------------
+
+The recipe normally gets the most recent distribution that satisfies the
+specification.  It won't do this is the buildout is either in
+non-newest mode or in offline mode.  To see how this works, we'll
+remove the restriction on demo:
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... """
+    ... [buildout]
+    ... parts = demo
+    ...
+    ... [demo]
+    ... recipe = repoze.recipe.egg
+    ... find-links = %(server)s
+    ... index = %(server)s/index
+    ... """ % dict(server=link_server))
+
+and run the buildout in non-newest mode:
+
+    >>> print system(buildout+' -N'),
+    Uninstalling demo.
+    Installing demo.
+    Generated script '/sample-buildout/bin/demo'.
+
+Note that we removed the eggs option, and the eggs defaulted to the
+part name. Because we removed the eggs option, the demo was
+reinstalled.
+
+We'll also run the buildout in off-line mode:
+
+    >>> print system(buildout+' -o'),
+    Updating demo.
+
+We didn't get an update for demo:
+
+    >>> ls(sample_buildout, 'eggs')
+    -  demo-0.2-py2.3.egg
+    -  demoneeded-1.2c1-py2.3.egg
+    -  setuptools-0.6-py2.3.egg
+    -  zc.buildout-1.0-py2.3.egg
+
+If we run the buildout on the default online and newest modes, 
+we'll get an update for demo:
+
+    >>> print system(buildout),
+    Updating demo.
+    Getting distribution for 'demo'.
+    Got demo 0.4c1.
+    Generated script '/sample-buildout/bin/demo'.
+
+Then we'll get a new demo egg:
+
+    >>> ls(sample_buildout, 'eggs')
+    -  demo-0.2-py2.3.egg
+    -  demo-0.4c1-py2.3.egg
+    -  demoneeded-1.2c1-py2.3.egg
+    -  setuptools-0.6-py2.4.egg
+    -  zc.buildout-1.0-py2.4.egg
+
+The script is updated too:
+
+    >>> print system(join(sample_buildout, 'bin', 'demo')),
+    4 2
+
+Controlling script generation
+-----------------------------
+
+You can control which scripts get generated using the scripts option.
+For example, to suppress scripts, use the scripts option without any
+arguments:
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... """
+    ... [buildout]
+    ... parts = demo
+    ...
+    ... [demo]
+    ... recipe = repoze.recipe.egg
+    ... find-links = %(server)s
+    ... index = %(server)s/index
+    ... scripts =
+    ... """ % dict(server=link_server))
+
+
+    >>> print system(buildout),
+    Uninstalling demo.
+    Installing demo.
+
+    >>> ls(sample_buildout, 'bin')
+    -  buildout
+
+You can also control the name used for scripts:
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... """
+    ... [buildout]
+    ... parts = demo
+    ...
+    ... [demo]
+    ... recipe = repoze.recipe.egg
+    ... find-links = %(server)s
+    ... index = %(server)s/index
+    ... scripts = demo=foo
+    ... """ % dict(server=link_server))
+
+    >>> print system(buildout),
+    Uninstalling demo.
+    Installing demo.
+    Generated script '/sample-buildout/bin/foo'.
+
+    >>> ls(sample_buildout, 'bin')
+    -  buildout
+    -  foo
+
+Specifying extra script paths
+-----------------------------
+
+If we need to include extra paths in a script, we can use the
+extra-paths option:
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... """
+    ... [buildout]
+    ... parts = demo
+    ...
+    ... [demo]
+    ... recipe = repoze.recipe.egg
+    ... find-links = %(server)s
+    ... index = %(server)s/index
+    ... scripts = demo=foo
+    ... extra-paths =
+    ...    /foo/bar
+    ...    /spam/eggs
+    ... """ % dict(server=link_server))
+
+    >>> print system(buildout),
+    Uninstalling demo.
+    Installing demo.
+    Generated script '/sample-buildout/bin/foo'.
+
+Let's look at the script that was generated:
+
+    >>> cat(sample_buildout, 'bin', 'foo') # doctest: +NORMALIZE_WHITESPACE
+    #!/usr/local/bin/python2.4
+    <BLANKLINE>
+    import sys
+    sys.path[0:0] = [
+      '/sample-buildout/eggs/demo-0.4c1-py2.4.egg',
+      '/sample-buildout/eggs/demoneeded-1.2c1-py2.4.egg',
+      '/foo/bar',
+      '/spam/eggs',
+      ]
+    <BLANKLINE>
+    import eggrecipedemo
+    <BLANKLINE>
+    if __name__ == '__main__':
+        eggrecipedemo.main()
+
+Specifying initialialization code and arguments
+-----------------------------------------------
+
+Sometimes, we ned to do more than just calling entry points.  We can
+use the initialialization and arguments options to specify extra code
+to be included in generated scripts:
+
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... """
+    ... [buildout]
+    ... parts = demo
+    ...
+    ... [demo]
+    ... recipe = repoze.recipe.egg
+    ... find-links = %(server)s
+    ... index = %(server)s/index
+    ... scripts = demo=foo
+    ... extra-paths =
+    ...    /foo/bar
+    ...    /spam/eggs
+    ... initialization = a = (1, 2
+    ...                       3, 4)
+    ... arguments = a, 2
+    ... """ % dict(server=link_server))
+
+    >>> print system(buildout),
+    Uninstalling demo.
+    Installing demo.
+    Generated script '/sample-buildout/bin/foo'.
+
+    >>> cat(sample_buildout, 'bin', 'foo') # doctest: +NORMALIZE_WHITESPACE
+    #!/usr/local/bin/python2.4
+    <BLANKLINE>
+    import sys
+    sys.path[0:0] = [
+      '/sample-buildout/eggs/demo-0.4c1-py2.4.egg',
+      '/sample-buildout/eggs/demoneeded-1.2c1-py2.4.egg',
+      '/foo/bar',
+      '/spam/eggs',
+      ]
+    <BLANKLINE>
+    a = (1, 2
+    3, 4)
+    <BLANKLINE>
+    import eggrecipedemo
+    <BLANKLINE>
+    if __name__ == '__main__':
+        eggrecipedemo.main(a, 2)
+
+Here we see that the initialization code we specified was added after
+setting the path.  Note, as mentioennd above, that leading whitespace
+has been stripped.  Similarly, the argument code we specified was
+added in the entry point call (to main).
+
+Specifying entry points
+-----------------------
+
+Scripts can be generated for entry points declared explicitly.  We can
+declare entry points using the entry-points option:
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... """
+    ... [buildout]
+    ... parts = demo
+    ...
+    ... [demo]
+    ... recipe = repoze.recipe.egg
+    ... find-links = %(server)s
+    ... index = %(server)s/index
+    ... extra-paths =
+    ...    /foo/bar
+    ...    /spam/eggs
+    ... entry-points = alt=eggrecipedemo:alt other=foo.bar:a.b.c
+    ... """ % dict(server=link_server))
+
+    >>> print system(buildout),
+    Uninstalling demo.
+    Installing demo.
+    Generated script '/sample-buildout/bin/demo'.
+    Generated script '/sample-buildout/bin/alt'.
+    Generated script '/sample-buildout/bin/other'.
+
+    >>> ls(sample_buildout, 'bin')
+    -  alt
+    -  buildout
+    -  demo
+    -  other
+
+    >>> cat(sample_buildout, 'bin', 'other')
+    #!/usr/local/bin/python2.4
+    <BLANKLINE>
+    import sys
+    sys.path[0:0] = [
+      '/sample-buildout/eggs/demo-0.4c1-py2.4.egg',
+      '/sample-buildout/eggs/demoneeded-1.2c1-py2.4.egg',
+      '/foo/bar',
+      '/spam/eggs',
+      ]
+    <BLANKLINE>
+    import foo.bar
+    <BLANKLINE>
+    if __name__ == '__main__':
+        foo.bar.a.b.c()
+
+Offline mode
+------------
+
+If the buildout offline option is set to "true", then no attempt will
+be made to contact an index server:
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... """
+    ... [buildout]
+    ... parts = demo
+    ... offline = true
+    ...
+    ... [demo]
+    ... recipe = repoze.recipe.egg
+    ... index = eek!
+    ... scripts = demo=foo
+    ... """ % dict(server=link_server))
+
+    >>> print system(buildout),
+    Uninstalling demo.
+    Installing demo.
+    Generated script '/sample-buildout/bin/foo'.

Added: repoze.recipe.egg/trunk/repoze/recipe/egg/__init__.py
==============================================================================
--- (empty file)
+++ repoze.recipe.egg/trunk/repoze/recipe/egg/__init__.py	Sat Mar  1 02:04:50 2008
@@ -0,0 +1,2 @@
+from repoze.recipe.egg.egg import Egg, Scripts, Eggs
+from repoze.recipe.egg.custom import Custom, Develop

Added: repoze.recipe.egg/trunk/repoze/recipe/egg/api.txt
==============================================================================
--- (empty file)
+++ repoze.recipe.egg/trunk/repoze/recipe/egg/api.txt	Sat Mar  1 02:04:50 2008
@@ -0,0 +1,152 @@
+Egg Recipe API for other Recipes
+================================
+
+It is common for recipes to accept a collection of egg specifications
+and generate scripts based on the resulting working sets.  The egg
+recipe provides an API that other recipes can use.
+
+A recipe can reuse the egg recipe, supporting the eggs, find-links,
+index, extra-paths, and python options.  This is done by creating an
+egg recipe instance in a recipes's contructor.  In the recipe's
+install script, the egg-recipe instance's working_set method is used
+to collect the requested eggs and working set.
+
+To illustrate, we create a sample recipe that is a very thin layer
+around the egg recipe:
+
+    >>> mkdir(sample_buildout, 'sample')
+    >>> write(sample_buildout, 'sample', 'sample.py', 
+    ... """
+    ... import logging, os
+    ... import repoze.recipe.egg
+    ...
+    ... class Sample:
+    ...
+    ...     def __init__(self, buildout, name, options):
+    ...         self.egg = repoze.recipe.egg.Scripts(buildout, name, options)
+    ...         self.name = name
+    ...         self.options = options
+    ...
+    ...     def install(self):
+    ...         extras = self.options['extras'].split()
+    ...         requirements, ws = self.egg.working_set(extras)
+    ...         print 'Part:', self.name
+    ...         print 'Egg requirements:'
+    ...         for r in requirements:
+    ...             print r
+    ...         print 'Working set:'
+    ...         for d in ws:
+    ...             print d
+    ...         print 'extra paths:', self.egg.extra_paths
+    ...         return ()
+    ...
+    ...     update = install
+    ... """)
+
+Here we instantiated the egg recipe in the constructor, saving it in
+an attribute.  This also initialized the options dictionary.
+
+In our install method, we called the working_set method on the
+instance we saved.  The working_set method takes an optional sequence
+of extra requirements to be included in the working set.
+
+    >>> write(sample_buildout, 'sample', 'setup.py',
+    ... """
+    ... from setuptools import setup
+    ... 
+    ... setup(
+    ...     name = "sample",
+    ...     entry_points = {'zc.buildout': ['default = sample:Sample']},
+    ...     install_requires = 'repoze.recipe.egg',
+    ...     )
+    ... """)
+
+
+    >>> write(sample_buildout, 'sample', 'README.txt', " ")
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... """
+    ... [buildout]
+    ... develop = sample
+    ... parts = sample-part
+    ...
+    ... [sample-part]
+    ... recipe = sample
+    ... eggs = demo<0.3
+    ... find-links = %(server)s
+    ... index = %(server)sindex
+    ... extras = other
+    ... """ % dict(server=link_server))
+
+    >>> import os
+    >>> os.chdir(sample_buildout)
+    >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
+    >>> print system(buildout + ' -q'),
+    Part: sample-part
+    Egg requirements:
+    demo<0.3
+    Working set:
+    demo 0.2
+    other 1.0
+    demoneeded 1.2c1
+    extra paths: []
+
+We can see that the options were augmented with additionl data
+computed by the egg recipe by looking at .installed.cfg:
+
+    >>> cat(sample_buildout, '.installed.cfg')
+    [buildout]
+    installed_develop_eggs = /sample-buildout/develop-eggs/sample.egg-link
+    parts = sample-part
+    <BLANKLINE>
+    [sample-part]
+    __buildout_installed__ = 
+    __buildout_signature__ = sample-6aWMvV2EJ9Ijq+bR8ugArQ==
+            repoze.recipe.egg-cAsnudgkduAa/Fd+WJIM6Q==
+            setuptools-0.6-py2.4.egg
+            zc.buildout-+rYeCcmFuD1K/aB77XTj5A==
+    _b = /sample-buildout/bin
+    _d = /sample-buildout/develop-eggs
+    _e = /sample-buildout/eggs
+    bin-directory = /sample-buildout/bin
+    develop-eggs-directory = /sample-buildout/develop-eggs
+    eggs = demo<0.3
+    eggs-directory = /sample-buildout/eggs
+    executable = /usr/local/bin/python2.3
+    extras = other
+    find-links = http://localhost:27071/
+    index = http://localhost:27071/index
+    recipe = sample
+
+If we use the extra-paths option:
+
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... """
+    ... [buildout]
+    ... develop = sample
+    ... parts = sample-part
+    ...
+    ... [sample-part]
+    ... recipe = sample
+    ... eggs = demo<0.3
+    ... find-links = %(server)s
+    ... index = %(server)sindex
+    ... extras = other
+    ... extra-paths = /foo/bar
+    ...               /spam/eggs
+    ... """ % dict(server=link_server))
+
+Then we'll see that reflected in the extra_paths attribute in the egg
+recipe instance:
+
+    >>> print system(buildout + ' -q'),
+    Part: sample-part
+    Egg requirements:
+    demo<0.3
+    Working set:
+    demo 0.2
+    other 1.0
+    demoneeded 1.2c1
+    extra paths: ['/foo/bar', '/spam/eggs']
+

Added: repoze.recipe.egg/trunk/repoze/recipe/egg/custom.py
==============================================================================
--- (empty file)
+++ repoze.recipe.egg/trunk/repoze/recipe/egg/custom.py	Sat Mar  1 02:04:50 2008
@@ -0,0 +1,135 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+"""Install packages as eggs
+
+$Id: custom.py 73397 2007-03-20 12:08:44Z jim $
+"""
+
+import logging
+import os
+import zc.buildout.easy_install
+
+logger = logging.getLogger(__name__)
+
+class Base:
+
+    def __init__(self, buildout, name, options):
+        self.name, self.options = name, options
+
+        options['_d'] = buildout['buildout']['develop-eggs-directory']
+
+        python = options.get('python', buildout['buildout']['python'])
+        options['executable'] = buildout[python]['executable']
+
+        self.build_ext = build_ext(buildout, options)
+
+
+    def update(self):
+        return self.install()
+
+class Custom(Base):
+
+    def __init__(self, buildout, name, options):
+        Base.__init__(self, buildout, name, options)
+
+        links = options.get('find-links',
+                            buildout['buildout'].get('find-links'))
+        if links:
+            links = links.split()
+            options['find-links'] = '\n'.join(links)
+        else:
+            links = ()
+        self.links = links
+
+        index = options.get('index', buildout['buildout'].get('index'))
+        if index is not None:
+            options['index'] = index
+        self.index = index
+
+        options['_e'] = buildout['buildout']['eggs-directory']
+
+        assert options.get('unzip') in ('true', 'false', None)
+
+        if buildout['buildout'].get('offline') == 'true':
+            self.install = lambda: ()
+
+        self.newest = buildout['buildout'].get('newest') == 'true'
+
+    def install(self):
+        options = self.options
+        distribution = options.get('egg')
+        if distribution is None:
+            distribution = options.get('eggs')
+            if distribution is None:
+                distribution = self.name
+            else:
+                logger.warn("The eggs option is deprecated. Use egg instead")
+            
+        
+        distribution = options.get('egg', options.get('eggs', self.name)
+                                   ).strip()
+        return zc.buildout.easy_install.build(
+            distribution, options['_d'], self.build_ext,
+            self.links, self.index, options['executable'], [options['_e']],
+            newest=self.newest,
+            )
+        
+class Develop(Base):
+
+    def __init__(self, buildout, name, options):
+        Base.__init__(self, buildout, name, options)
+        options['setup'] = os.path.join(buildout['buildout']['directory'],
+                                        options['setup'])
+
+    def install(self):
+        options = self.options
+        return zc.buildout.easy_install.develop(
+            options['setup'], options['_d'], self.build_ext,
+            options['executable'],
+            )
+        
+
+def build_ext(buildout, options):
+    result = {}
+    for be_option in ('include-dirs', 'library-dirs', 'rpath'):
+        value = options.get(be_option)
+        if value is None:
+            continue
+        value = [
+            os.path.join(
+                buildout['buildout']['directory'],
+                v.strip()
+                )
+            for v in value.strip().split('\n')
+            if v.strip()
+        ]
+        result[be_option] = os.pathsep.join(value)
+        options[be_option] = os.pathsep.join(value)
+
+    swig = options.get('swig')
+    if swig:
+        options['swig'] = result['swig'] = os.path.join(
+            buildout['buildout']['directory'],
+            swig,
+            )
+
+    for be_option in ('define', 'undef', 'libraries', 'link-objects',
+                      'debug', 'force', 'compiler', 'swig-cpp', 'swig-opts',
+                      ):
+        value = options.get(be_option)
+        if value is None:
+            continue
+        result[be_option] = value
+
+    return result

Added: repoze.recipe.egg/trunk/repoze/recipe/egg/custom.txt
==============================================================================
--- (empty file)
+++ repoze.recipe.egg/trunk/repoze/recipe/egg/custom.txt	Sat Mar  1 02:04:50 2008
@@ -0,0 +1,414 @@
+Creating eggs with extensions neededing custom build settings
+=============================================================
+
+Sometimes, It's necessary to provide extra control over how an egg is
+created.  This is commonly true for eggs with extension modules that
+need to access libraries or include files.
+
+The repoze.recipe.egg:custom recipe can be used to define an egg with
+custom build parameters.  The currently defined parameters are:
+
+include-dirs
+   A new-line separated list of directories to search for include
+   files.
+
+library-dirs
+   A new-line separated list of directories to search for libraries
+   to link with.
+
+rpath
+   A new-line separated list of directories to search for dynamic libraries
+   at run time.
+
+define
+   A comma-separated list of names of C preprocessor variables to
+   define.
+
+undef
+   A comman separated list of names of C preprocessor variables to
+   undefine.
+
+libraries
+   The name of an additional library to link with.  Due to limitations
+   in distutils and desprite the option name, only a single library
+   can be specified.
+
+link-objects
+   The name of an link object to link afainst.  Due to limitations
+   in distutils and desprite the option name, only a single link object
+   can be specified.
+
+debug
+   Compile/link with debugging information
+
+force
+   Forcibly build everything (ignore file timestamps)
+
+compiler
+   Specify the compiler type
+
+swig
+   The path to the swig executable
+
+swig-cpp           
+   Make SWIG create C++ files (default is C)
+
+swig-opts
+   List of SWIG command line options
+
+In addition, the following options can be used to specify the egg:
+
+egg
+    An specification for the egg to be created, to install given as a
+    setuptools requirement string.  This defaults to the part name.
+
+find-links
+   A list of URLs, files, or directories to search for distributions.
+
+index
+   The URL of an index server, or almost any other valid URL. :)
+
+   If not specified, the Python Package Index,
+   http://cheeseshop.python.org/pypi, is used.  You can specify an
+   alternate index with this option.  If you use the links option and
+   if the links point to the needed distributions, then the index can
+   be anything and will be largely ignored.  In the examples, here,
+   we'll just point to an empty directory on our link server.  This 
+   will make our examples run a little bit faster.
+
+python
+   The name of a section to get the Python executable from.
+   If not specified, then the buildout python option is used.  The
+   Python executable is found in the executable option of the named
+   section. 
+
+To illustrate this, we'll define a buildout that builds an egg for a
+package that has a simple extension module::
+
+  #include <Python.h>
+  #include <extdemo.h>
+
+  static PyMethodDef methods[] = {};
+
+  PyMODINIT_FUNC
+  initextdemo(void)
+  {
+      PyObject *m;
+      m = Py_InitModule3("extdemo", methods, "");
+  #ifdef TWO
+      PyModule_AddObject(m, "val", PyInt_FromLong(2));
+  #else
+      PyModule_AddObject(m, "val", PyInt_FromLong(EXTDEMO));
+  #endif
+  }
+
+The extension depends on a system-dependnt include file, extdemo.h,
+that defines a constant, EXTDEMO, that is exposed by the extension.
+
+The extension module is available as a source distribution,
+extdemo-1.4.tar.gz, on a distribution server.
+
+We have a sample buildout that we'll add an include directory to with
+the necessary include file:
+
+    >>> mkdir('include')
+    >>> write('include', 'extdemo.h',
+    ... """
+    ... #define EXTDEMO 42
+    ... """)
+
+We'll also update the buildout configuration file to define a part for
+the egg:
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... """
+    ... [buildout]
+    ... parts = extdemo
+    ...
+    ... [extdemo]
+    ... recipe = repoze.recipe.egg:custom
+    ... find-links = %(server)s
+    ... index = %(server)s/index
+    ... include-dirs = include
+    ... """ % dict(server=link_server))
+
+    >>> print system(buildout),
+    Installing extdemo.
+    zip_safe flag not set; analyzing archive contents...
+
+We got the zip_safe warning because the source distribution we used
+wasn't setuptools based and thus didn't set the option.
+
+The egg is created in the develop-eggs directory *not* the eggs
+directory because it depends on buildout-specific parameters and the
+eggs directory can be shared across multiple buildouts.
+
+    >>> ls(sample_buildout, 'develop-eggs')
+    d  extdemo-1.4-py2.4-unix-i686.egg
+    -  repoze.recipe.egg.egg-link
+
+Note that no scripts or dependencies are installed.  To install
+dependencies or scripts for a custom egg, define another part and use
+the repoze.recipe.egg recipe, listing the custom egg as one of the eggs to
+be installed.  The repoze.recipe.egg recipe will use the installed egg.
+
+Let's define a script that uses out ext demo:
+
+    >>> mkdir('demo')
+    >>> write('demo', 'demo.py',
+    ... """
+    ... import extdemo
+    ... def main():
+    ...     print extdemo.val
+    ... """)
+
+    >>> write('demo', 'setup.py',
+    ... """
+    ... from setuptools import setup
+    ... setup(name='demo')
+    ... """)
+
+
+    >>> write('buildout.cfg',
+    ... """
+    ... [buildout]
+    ... develop = demo
+    ... parts = extdemo demo
+    ...
+    ... [extdemo]
+    ... recipe = repoze.recipe.egg:custom
+    ... find-links = %(server)s
+    ... index = %(server)s/index
+    ... include-dirs = include
+    ...
+    ... [demo]
+    ... recipe = repoze.recipe.egg
+    ... eggs = demo 
+    ...        extdemo
+    ... entry-points = demo=demo:main
+    ... """ % dict(server=link_server))
+
+    >>> print system(buildout),
+    Develop: '/sample-buildout/demo'
+    Updating extdemo.
+    Installing demo.
+    Generated script '/sample-buildout/bin/demo'.
+
+When we run the script, we'll 42 printed:
+
+    >>> print system(join('bin', 'demo')),
+    42
+
+Updating
+--------
+
+The custom recipe will normally check for new source distributions
+that meet the given specification.  This can be suppressed using the
+buildout non-newest and offline modes.  We'll generate a new source
+distribution for extdemo:
+
+    >>> update_extdemo()
+
+If we run the buildout in non-newest or offline modes:
+
+    >>> print system(buildout+' -N'),
+    Develop: '/sample-buildout/demo'
+    Updating extdemo.
+    Updating demo.
+
+    >>> print system(buildout+' -o'),
+    Develop: '/sample-buildout/demo'
+    Updating extdemo.
+    Updating demo.
+
+We won't get an update.
+
+    >>> ls(sample_buildout, 'develop-eggs')
+    -  demo.egg-link
+    d  extdemo-1.4-py2.4-unix-i686.egg
+    -  repoze.recipe.egg.egg-link
+
+But if we run the buildout in the default on-line and newest modes, we
+will:
+
+    >>> print system(buildout),
+    Develop: '/sample-buildout/demo'
+    Updating extdemo.
+    zip_safe flag not set; analyzing archive contents...
+    Updating demo.
+    Generated script '/sample-buildout/bin/demo'.
+
+    >>> ls(sample_buildout, 'develop-eggs')
+    -  demo.egg-link
+    d  extdemo-1.4-py2.4-linux-i686.egg
+    d  extdemo-1.5-py2.4-linux-i686.egg
+    -  repoze.recipe.egg.egg-link
+
+Controlling the version used
+----------------------------
+
+We can specify a specific version using the egg option:
+
+    >>> write('buildout.cfg',
+    ... """
+    ... [buildout]
+    ... develop = demo
+    ... parts = extdemo demo
+    ...
+    ... [extdemo]
+    ... recipe = repoze.recipe.egg:custom
+    ... egg = extdemo ==1.4
+    ... find-links = %(server)s
+    ... index = %(server)s/index
+    ... include-dirs = include
+    ...
+    ... [demo]
+    ... recipe = repoze.recipe.egg
+    ... eggs = demo 
+    ...        extdemo ==1.4
+    ... entry-points = demo=demo:main
+    ... """ % dict(server=link_server))
+
+    >>> print system(buildout+' -D'),
+    Develop: '/sample-buildout/demo'
+    Uninstalling demo.
+    Uninstalling extdemo.
+    Installing extdemo.
+    zip_safe flag not set; analyzing archive contents...
+    Installing demo.
+    Generated script '/sample-buildout/bin/demo'.
+
+    >>> ls(sample_buildout, 'develop-eggs')
+    -  demo.egg-link
+    d  extdemo-1.4-py2.4-linux-i686.egg
+    -  repoze.recipe.egg.egg-link
+
+Controlling develop-egg generation
+==================================
+
+If you want to provide custom build options for a develop egg, you can
+use the develop recipe.  The recipe has the following options:
+
+path
+   The path to a setup script or directory containing a startup
+   script. This is required.
+
+include-dirs
+   A new-line separated list of directories to search for include
+   files.
+
+library-dirs
+   A new-line separated list of directories to search for libraries
+   to link with.
+
+rpath
+   A new-line separated list of directories to search for dynamic libraries
+   at run time.
+
+define
+   A comma-separated list of names of C preprocessor variables to
+   define.
+
+undef
+   A comman separated list of names of C preprocessor variables to
+   undefine.
+
+libraries
+   The name of an additional library to link with.  Due to limitations
+   in distutils and desprite the option name, only a single library
+   can be specified.
+
+link-objects
+   The name of an link object to link afainst.  Due to limitations
+   in distutils and desprite the option name, only a single link object
+   can be specified.
+
+debug
+   Compile/link with debugging information
+
+force
+   Forcibly build everything (ignore file timestamps)
+
+compiler
+   Specify the compiler type
+
+swig
+   The path to the swig executable
+
+swig-cpp           
+   Make SWIG create C++ files (default is C)
+
+swig-opts
+   List of SWIG command line options
+
+python
+   The name of a section to get the Python executable from.
+   If not specified, then the buildout python option is used.  The
+   Python executable is found in the executable option of the named
+   section. 
+
+To illustrate this, we'll use a directory containing the extdemo
+example from the earlier section:
+
+    >>> ls(extdemo)
+    -  MANIFEST
+    -  MANIFEST.in
+    -  README
+    -  extdemo.c
+    -  setup.py
+
+    >>> write('buildout.cfg',
+    ... """
+    ... [buildout]
+    ... develop = demo
+    ... parts = extdemo demo
+    ...
+    ... [extdemo]
+    ... setup = %(extdemo)s
+    ... recipe = repoze.recipe.egg:develop
+    ... include-dirs = include
+    ... define = TWO
+    ...
+    ... [demo]
+    ... recipe = repoze.recipe.egg
+    ... eggs = demo 
+    ...        extdemo
+    ... entry-points = demo=demo:main
+    ... """ % dict(extdemo=extdemo))
+
+Note that we added a define option to cause the preprocessor variable
+TWO to be defined.  This will cause the module-variable, 'val', to be
+set with a value of 2.
+
+    >>> print system(buildout),
+    Develop: '/sample-buildout/demo'
+    Uninstalling demo.
+    Uninstalling extdemo.
+    Installing extdemo.
+    Installing demo.
+    Generated script '/sample-buildout/bin/demo'.
+
+Our develop-eggs now includes an egg link for extdemo:
+
+    >>> ls('develop-eggs')
+    -  demo.egg-link
+    -  extdemo.egg-link
+    -  repoze.recipe.egg.egg-link
+
+and the extdemo now has a built extension:
+
+    >>> ls(extdemo)
+    -  MANIFEST
+    -  MANIFEST.in
+    -  README
+    d  build
+    -  extdemo.c
+    d  extdemo.egg-info
+    -  extdemo.so
+    -  setup.py
+
+Because develop eggs take precedence over non-develop eggs, the demo
+script will use the new develop egg:
+
+    >>> print system(join('bin', 'demo')),
+    2

Added: repoze.recipe.egg/trunk/repoze/recipe/egg/egg.py
==============================================================================
--- (empty file)
+++ repoze.recipe.egg/trunk/repoze/recipe/egg/egg.py	Sat Mar  1 02:04:50 2008
@@ -0,0 +1,303 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+"""Install packages as eggs
+
+$Id: egg.py 72431 2007-02-07 23:43:36Z jim $
+"""
+
+import logging
+import os
+import pkg_resources
+import re
+import sys
+
+import zc.buildout.easy_install
+
+class Eggs(object):
+
+    def __init__(self, buildout, name, options):
+        self.buildout = buildout
+        self.name = name
+        self.options = options
+        links = options.get('find-links',
+                            buildout['buildout'].get('find-links'))
+        if links:
+            links = links.split()
+            options['find-links'] = '\n'.join(links)
+        else:
+            links = ()
+        self.links = links
+
+        index = options.get('index', buildout['buildout'].get('index'))
+        if index is not None:
+            options['index'] = index
+        self.index = index
+
+        options['eggs-directory'] = buildout['buildout']['eggs-directory']
+        options['_e'] = options['eggs-directory'] # backward compat.
+        options['develop-eggs-directory'
+                ] = buildout['buildout']['develop-eggs-directory']
+        options['_d'] = options['develop-eggs-directory'] # backward compat.
+        
+        assert options.get('unzip') in ('true', 'false', None)
+
+        python = options.get('python', buildout['buildout']['python'])
+        options['executable'] = buildout[python]['executable']
+
+    def working_set(self, extra=()):
+        """Separate method to just get the working set
+
+        This is intended for reuse by similar recipes.
+        """
+        options = self.options
+
+        distributions = [
+            r.strip()
+            for r in options.get('eggs', self.name).split('\n')
+            if r.strip()]
+        orig_distributions = distributions[:]
+        distributions.extend(extra)
+
+        if self.buildout['buildout'].get('offline') == 'true':
+            ws = zc.buildout.easy_install.working_set(
+                distributions, options['executable'],
+                [options['develop-eggs-directory'], options['eggs-directory']]
+                )
+        else:
+            ws = zc.buildout.easy_install.install(
+                distributions, options['eggs-directory'],
+                links = self.links,
+                index = self.index, 
+                executable = options['executable'],
+                always_unzip=options.get('unzip') == 'true',
+                path=[options['develop-eggs-directory']],
+                newest=self.buildout['buildout'].get('newest') == 'true',
+                )
+
+        return orig_distributions, ws
+
+    def install(self):
+        reqs, ws = self.working_set()
+        return ()
+
+    update = install
+
+class Scripts(Eggs):
+
+    def __init__(self, buildout, name, options):
+        super(Scripts, self).__init__(buildout, name, options)
+
+        options['bin-directory'] = buildout['buildout']['bin-directory']
+        options['_b'] = options['bin-directory'] # backward compat.
+
+        self.extra_paths = [
+            os.path.join(buildout['buildout']['directory'], p.strip())
+            for p in options.get('extra-paths', '').split('\n')
+            if p.strip()
+            ]
+        if self.extra_paths:
+            options['extra-paths'] = '\n'.join(self.extra_paths)
+
+    parse_entry_point = re.compile(
+        '([^=]+)=(\w+(?:[.]\w+)*):(\w+(?:[.]\w+)*)$'
+        ).match
+    def install(self):
+        reqs, ws = self.working_set()
+        options = self.options
+
+        scripts = options.get('scripts')
+        if scripts or scripts is None:
+            if scripts is not None:
+                scripts = scripts.split()
+                scripts = dict([
+                    ('=' in s) and s.split('=', 1) or (s, s)
+                    for s in scripts
+                    ])
+
+            for s in options.get('entry-points', '').split():
+                parsed = self.parse_entry_point(s)
+                if not parsed:
+                    logging.getLogger(self.name).error(
+                        "Cannot parse the entry point %s.", s)
+                    raise zc.buildout.UserError("Invalid entry point")
+                reqs.append(parsed.groups())
+
+            return scripts__(
+                reqs, ws, options['executable'],
+                options['bin-directory'],
+                scripts=scripts,
+                extra_paths=self.extra_paths,
+                interpreter=options.get('interpreter'),
+                initialization=options.get('initialization', ''),
+                arguments=options.get('arguments', ''),
+                dependent_scripts=asbool(options.get('dependent_scripts',True))
+                )
+
+        return ()
+
+    update = install
+
+Egg = Scripts
+
+def asbool(value):
+    value = str(value)
+    if value.strip().lower() in ['1','true']:
+        return True
+    elif value.strip().lower() in ['0','false']:
+        return False
+    else: 
+        raise Exception("Unrecognised option %s for bool"% value)
+
+
+py_script_template = '''\
+#!%(python)s
+import sys, os
+    
+sys.path[0:0] = [
+  %(path)s,
+  os.getcwd(),
+  ]
+
+_interactive = True
+if len(sys.argv) > 1:
+    import getopt
+    _options, _args = getopt.getopt(sys.argv[1:], 'ic:')
+    _interactive = False
+    for (_opt, _val) in _options:
+        if _opt == '-i':
+            _interactive = True
+        elif _opt == '-c':
+            exec _val
+            
+    if _args:
+        sys.argv[:] = _args
+        execfile(sys.argv[0])
+
+if _interactive:
+    import code
+    code.interact(banner="", local=globals())
+'''
+
+def scripts__(reqs, working_set, executable, dest,
+            scripts=None,
+            extra_paths=(),
+            arguments='',
+            interpreter=None,
+            initialization='',
+            launcher=None,
+            dependent_scripts=False
+            ):
+    path = [dist.location for dist in working_set]
+    path.extend(extra_paths)
+    path = repr(path)[1:-1].replace(', ', ',\n  ')
+    generated = []
+
+    if isinstance(reqs, str):
+        raise TypeError('Expected iterable of requirements or entry points,'
+                        ' got string.')
+
+    if initialization:
+        initialization = '\n'+initialization+'\n'
+
+    entry_points = []
+    if dependent_scripts:
+        requirements = [x[1][0] for x in working_set.entry_keys.items()]
+    else:
+        requirements = []
+    
+    for req in reqs:
+        if req not in requirements:
+            requirements.append(req)
+    for req in requirements:
+        if isinstance(req, str):
+            req = pkg_resources.Requirement.parse(req)
+            dist = working_set.find(req)
+            for name in pkg_resources.get_entry_map(dist, 'console_scripts'):
+                entry_point = dist.get_entry_info('console_scripts', name)
+                entry_points.append(
+                    (name, entry_point.module_name,
+                     '.'.join(entry_point.attrs))
+                    )
+        else:
+            entry_points.append(req)
+
+    for name, module_name, attrs in entry_points:
+        if name.startswith('easy_install'):
+            continue
+        if scripts is not None:
+            sname = scripts.get(name)
+            if sname is None:
+                continue
+        else:
+            sname = name
+
+        sname = os.path.join(dest, sname)
+        generated.extend(
+            zc.buildout.easy_install._script(module_name, attrs, path,
+                                             sname, executable, arguments,
+                                             initialization)
+            )
+
+    if interpreter:
+        sname = os.path.join(dest, interpreter)
+        generated.extend(_pyscript(path, sname, executable, launcher))
+
+    return generated
+
+def _pyscript(path, dest, executable, launcher):
+    generated = []
+    script = dest
+    if sys.platform == 'win32':
+        script+='-script'
+    if launcher:
+        dest += '.buildout'
+
+    contents = py_script_template % dict(
+        python = executable,
+        path = path,
+        )
+    changed = not (os.path.exists(dest) and open(dest).read() == contents)
+
+    if sys.platform == 'win32':
+        # generate exe file and give the script a magic name:
+        exe = script + '.exe'
+        open(exe, 'wb').write(
+            pkg_resources.resource_string('setuptools', 'cli.exe')
+            )
+        generated.append(exe)
+    elif launcher:
+        exe = script
+        open(exe, 'wb').write(
+            open(launcher, 'rb').read()
+        )
+        generated.append(exe)
+        try:
+            os.chmod(exe,0755)
+        except (AttributeError, os.error):
+            pass
+        logging.getLogger('buildout').error(
+                        "Generated launcher %r.", exe)
+
+
+    if changed:
+        open(dest, 'w').write(contents)
+        try:
+            os.chmod(dest,0755)
+        except (AttributeError, os.error):
+            pass
+        logging.getLogger('buildout').info(
+            "Generated interpreter %r.", script)
+
+    generated.append(dest)
+    return generated

Added: repoze.recipe.egg/trunk/repoze/recipe/egg/selecting-python.txt
==============================================================================
--- (empty file)
+++ repoze.recipe.egg/trunk/repoze/recipe/egg/selecting-python.txt	Sat Mar  1 02:04:50 2008
@@ -0,0 +1,128 @@
+Controlling which Python to use
+-------------------------------
+
+The following assumes that you have Python 2.3 installed.
+
+We can specify the python to use by specifying the name of a section
+to read the Python executable from.  The default is the section
+defined by the python buildout option.
+
+We have a link server:
+
+    >>> print get(link_server),
+    <html><body>
+    <a href="demo-0.1-py2.3.egg">demo-0.1-py2.3.egg</a><br>
+    <a href="demo-0.2-py2.3.egg">demo-0.2-py2.3.egg</a><br>
+    <a href="demo-0.3-py2.3.egg">demo-0.3-py2.3.egg</a><br>
+    <a href="demo-0.4c1-py2.3.egg">demo-0.4c1-py2.3.egg</a><br>
+    <a href="demoneeded-1.0.zip">demoneeded-1.0.zip</a><br>
+    <a href="demoneeded-1.1.zip">demoneeded-1.1.zip</a><br>
+    <a href="demoneeded-1.2c1.zip">demoneeded-1.2c1.zip</a><br>
+    <a href="extdemo-1.4.zip">extdemo-1.4.zip</a><br>
+    <a href="index/">index/</a><br>
+    <a href="other-1.0-py2.3.egg">other-1.0-py2.3.egg</a><br>
+    </body></html>
+
+We have a sample buildout.  Let's update it's configuration file to
+install the demo package using Python 2.3. 
+
+    >>> write(sample_buildout, 'buildout.cfg',
+    ... """
+    ... [buildout]
+    ... parts = demo
+    ... eggs-directory = eggs
+    ... index = http://www.python.org/pypi/
+    ...
+    ... [python2.3]
+    ... executable = %(python23)s
+    ...
+    ... [demo]
+    ... recipe = repoze.recipe.egg
+    ... eggs = demo <0.3
+    ... find-links = %(server)s
+    ... python = python2.3
+    ... interpreter = py-demo
+    ... """ % dict(server=link_server, python23=python2_3_executable))
+
+Now, if we run the buildout:
+
+   >>> import os
+   >>> os.chdir(sample_buildout)
+   >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
+   >>> print system(buildout),
+   Installing demo.
+   Getting distribution for 'demo<0.3'.
+   Got demo 0.2.
+   Getting distribution for 'demoneeded'.
+   Getting distribution for 'setuptools'.
+   Got setuptools 0.6.
+   Got demoneeded 1.2c1.
+   Generated script '/sample-buildout/bin/demo'.
+   Generated interpreter '/sample-buildout/bin/py-demo'.
+
+we'll get the Python 2.3 eggs for demo and demoneeded:
+
+    >>> ls(sample_buildout, 'eggs')
+    -  demo-0.2-py2.3.egg
+    -  demoneeded-1.2c1-py2.3.egg
+    d  setuptools-0.6-py2.3.egg
+    d  setuptools-0.6-py2.4.egg
+    -  zc.buildout-1.0-py2.4.egg
+ 
+And the generated scripts invoke Python 2.3:
+
+    >>> import sys
+    >>> if sys.platform == 'win32':
+    ...    script_name = 'demo-script.py'
+    ... else:
+    ...    script_name = 'demo'
+    >>> f = open(os.path.join(sample_buildout, 'bin', script_name))
+    >>> f.readline().strip() == '#!' + python2_3_executable
+    True
+    >>> print f.read(), # doctest: +NORMALIZE_WHITESPACE
+    <BLANKLINE>
+    import sys
+    sys.path[0:0] = [
+      '/sample-buildout/eggs/demo-0.2-py2.3.egg',
+      '/sample-buildout/eggs/demoneeded-1.2c1-py2.3.egg',
+      ]
+    <BLANKLINE>
+    import eggrecipedemo
+    <BLANKLINE>
+    if __name__ == '__main__':
+        eggrecipedemo.main()
+
+    >>> if sys.platform == 'win32':
+    ...     f = open(os.path.join(sample_buildout, 'bin', 'py-demo-script.py'))
+    ... else:
+    ...     f = open(os.path.join(sample_buildout, 'bin', 'py-demo'))
+    >>> f.readline().strip() == '#!' + python2_3_executable
+    True
+    >>> print f.read(), # doctest: +NORMALIZE_WHITESPACE
+    import sys
+    <BLANKLINE>
+    sys.path[0:0] = [
+      '/sample-buildout/eggs/demo-0.2-py2.3.egg',
+      '/sample-buildout/eggs/demoneeded-1.2c1-py2.3.egg',
+      ]
+    <BLANKLINE>
+    _interactive = True
+    if len(sys.argv) > 1:
+        import getopt
+        _options, _args = getopt.getopt(sys.argv[1:], 'ic:')
+        _interactive = False
+        for (_opt, _val) in _options:
+            if _opt == '-i':
+                _interactive = True
+            elif _opt == '-c':
+                exec _val
+    <BLANKLINE>
+        if _args:
+            sys.argv[:] = _args
+            execfile(sys.argv[0])
+    <BLANKLINE>
+    if _interactive:
+        import code
+        code.interact(banner="", local=globals())
+
+    >>> f.close()

Added: repoze.recipe.egg/trunk/repoze/recipe/egg/tests.py
==============================================================================
--- (empty file)
+++ repoze.recipe.egg/trunk/repoze/recipe/egg/tests.py	Sat Mar  1 02:04:50 2008
@@ -0,0 +1,118 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+
+import os, re, shutil, sys
+import zc.buildout.tests
+import zc.buildout.testselectingpython
+import zc.buildout.testing
+
+import unittest
+from zope.testing import doctest, renormalizing
+
+os_path_sep = os.path.sep
+if os_path_sep == '\\':
+    os_path_sep *= 2
+
+def dirname(d, level=1):
+    if level == 0:
+        return d
+    return dirname(os.path.dirname(d), level-1)
+
+def setUp(test):
+    zc.buildout.tests.easy_install_SetUp(test)
+    zc.buildout.testing.install_develop('repoze.recipe.egg', test)
+
+def setUpSelecting(test):
+    zc.buildout.testselectingpython.setup(test)
+    zc.buildout.testing.install_develop('repoze.recipe.egg', test)
+    
+def test_suite():
+    suite = unittest.TestSuite((
+        doctest.DocFileSuite(
+            'README.txt',
+            setUp=setUp, tearDown=zc.buildout.testing.buildoutTearDown,
+            checker=renormalizing.RENormalizing([
+               zc.buildout.testing.normalize_path,
+               zc.buildout.testing.normalize_script,
+               zc.buildout.testing.normalize_egg_py,
+               zc.buildout.tests.normalize_bang,
+               (re.compile('zc.buildout(-\S+)?[.]egg(-link)?'),
+                'zc.buildout.egg'),
+               (re.compile('[-d]  setuptools-[^-]+-'), 'setuptools-X-')
+               ])
+            ),
+        doctest.DocFileSuite(
+            'api.txt',
+            setUp=setUp, tearDown=zc.buildout.testing.buildoutTearDown,
+            checker=renormalizing.RENormalizing([
+               zc.buildout.testing.normalize_path,
+               (re.compile('__buildout_signature__ = '
+                           'sample-\S+\s+'
+                           'repoze.recipe.egg-\S+\s+'
+                           'setuptools-\S+\s+'
+                           'zc.buildout-\S+\s*'
+                           ),
+                '__buildout_signature__ = sample- repoze.recipe.egg-'),
+               (re.compile('executable = \S+python\S*'),
+                'executable = python'),
+               (re.compile('index = \S+python\S+'),
+                'executable = python'),
+               (re.compile('find-links = http://localhost:\d+/'),
+                'find-links = http://localhost:8080/'),
+               (re.compile('index = http://localhost:\d+/index'),
+                'index = http://localhost:8080/index'),
+               ])
+            ),
+        doctest.DocFileSuite(
+            'custom.txt',
+            setUp=setUp, tearDown=zc.buildout.testing.buildoutTearDown,
+            checker=renormalizing.RENormalizing([
+               zc.buildout.testing.normalize_path,
+               (re.compile("(d  ((ext)?demo(needed)?|other)"
+                           "-\d[.]\d-py)\d[.]\d(-\S+)?[.]egg"),
+                '\\1V.V.egg'),
+               (re.compile('extdemo.c\n.+\\extdemo.exp\n'), ''),
+               (re.compile('extdemo[.]pyd'), 'extdemo.so')
+               ]),
+            ),
+        
+        ))
+
+    if sys.version_info[:2] != (2, 3):
+        # Only run selecting python tests if not 2.3, since
+        # 2.3 is the alternate python used in the tests.
+        suite.addTest(
+            doctest.DocFileSuite(
+                'selecting-python.txt',
+                setUp=setUpSelecting,
+                tearDown=zc.buildout.testing.buildoutTearDown,
+                checker=renormalizing.RENormalizing([
+                   zc.buildout.testing.normalize_path,
+                   zc.buildout.testing.normalize_script,
+                   (re.compile('Got setuptools \S+'), 'Got setuptools V'),
+                   (re.compile('([d-]  )?setuptools-\S+-py'), 'setuptools-V-py'),
+                   (re.compile('-py2[.][0-24-9][.]'), 'py2.4.'),
+                   (re.compile('zc.buildout-\S+[.]egg'),
+                    'zc.buildout.egg'),
+                   (re.compile('zc.buildout[.]egg-link'),
+                    'zc.buildout.egg'),
+                   ]),
+                ),
+            )
+    
+    return suite
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
+

Added: repoze.recipe.egg/trunk/setup.py
==============================================================================
--- (empty file)
+++ repoze.recipe.egg/trunk/setup.py	Sat Mar  1 02:04:50 2008
@@ -0,0 +1,98 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Setup for repoze.recipe.egg package
+
+$Id: setup.py 81447 2007-11-03 19:14:30Z srichter $
+"""
+import os
+from setuptools import setup, find_packages
+
+def read(*rnames):
+    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+def alltests():
+    import pdb; pdb.set_trace()
+    # use the zope.testing testrunner machinery to find all the
+    # test suites we've put under ourselves
+    from zope.testing.testrunner import get_options
+    from zope.testing.testrunner import find_suites
+    from zope.testing.testrunner import configure_logging
+    configure_logging()
+    from unittest import TestSuite
+    import sys
+    here = os.path.abspath(os.path.dirname(sys.argv[0]))
+    args = sys.argv[:]
+    defaults = ['--test-path', here]
+    options = get_options(args, defaults)
+    suites = list(find_suites(options))
+    return TestSuite(suites)
+
+name = "repoze.recipe.egg"
+setup(
+    name = name,
+    version = "0.1",
+    author = "Jim Fulton (forked by Chris McDonough)",
+    author_email = "chrism at plope.com",
+    description = "Recipe for installing Python package distributions as eggs",
+    long_description = (
+        read('README.txt')
+        + '\n' +
+        read('CHANGES.txt')
+        + '\n' +
+        'Detailed Documentation\n'
+        '**********************\n'
+        + '\n' +
+        read('repoze', 'recipe', 'egg', 'README.txt')
+        + '\n' +
+        read('repoze', 'recipe', 'egg', 'selecting-python.txt')
+        + '\n' +
+        read('repoze', 'recipe', 'egg', 'custom.txt')
+        + '\n' +
+        read('repoze', 'recipe', 'egg', 'api.txt')
+        + '\n' +
+        'Download\n'
+        '*********\n'
+        ),
+    keywords = "development build",
+    classifiers = [
+       'Development Status :: 5 - Production/Stable',
+       'Framework :: Buildout',
+       'Intended Audience :: Developers',
+       'License :: OSI Approved :: Zope Public License',
+       'Topic :: Software Development :: Build Tools',
+       'Topic :: Software Development :: Libraries :: Python Modules',
+       ],
+    url='http://dist.repoze.org/simple/repoze.recipe.egg',
+    license = "ZPL 2.1",
+
+    packages = find_packages(),
+    namespace_packages = ['repoze', 'repoze.recipe'],
+    install_requires = [
+        'zc.buildout >=1.0.0b3',
+        'setuptools',
+        'virtualenv'],
+    tests_require = ['zope.testing', 'zc.buildout >=1.0.0b3'],
+    #test_suite = name+'.tests.test_suite',
+    test_suite = '__main__.alltests',
+    entry_points = {'zc.buildout': ['default = %s:Scripts' % name,
+                                    'script = %s:Scripts' % name,
+                                    'scripts = %s:Scripts' % name,
+                                    'eggs = %s:Eggs' % name,
+                                    'custom = %s:Custom' % name,
+                                    'develop = %s:Develop' % name,
+                                    ]
+                    },
+    include_package_data = True,
+    zip_safe=False,
+    )


More information about the Repoze-checkins mailing list