[Checkins] SVN: zc.buildout/branches/dev/ Added a develop recipe.

Jim Fulton jim at zope.com
Mon Dec 4 15:01:33 EST 2006


Log message for revision 71394:
  Added a develop recipe.
  
  Added support for all reasonable build_ext options to the build and
  develop recipes.
  
  The build and develop functions and recipes now return the paths
  created.
  

Changed:
  U   zc.buildout/branches/dev/src/zc/buildout/easy_install.py
  U   zc.buildout/branches/dev/src/zc/buildout/easy_install.txt
  U   zc.buildout/branches/dev/src/zc/buildout/tests.py
  U   zc.buildout/branches/dev/zc.recipe.egg_/setup.py
  U   zc.buildout/branches/dev/zc.recipe.egg_/src/zc/recipe/egg/__init__.py
  U   zc.buildout/branches/dev/zc.recipe.egg_/src/zc/recipe/egg/custom.py
  U   zc.buildout/branches/dev/zc.recipe.egg_/src/zc/recipe/egg/custom.txt

-=-
Modified: zc.buildout/branches/dev/src/zc/buildout/easy_install.py
===================================================================
--- zc.buildout/branches/dev/src/zc/buildout/easy_install.py	2006-12-04 16:28:38 UTC (rev 71393)
+++ zc.buildout/branches/dev/src/zc/buildout/easy_install.py	2006-12-04 20:01:32 UTC (rev 71394)
@@ -407,12 +407,15 @@
 
     dist = _satisfied(requirement, env, dest, executable, index_url, links)
     if dist is not None:
-        return dist
+        return [dist.location]
 
-    # Get an editable version of the package to a temporary directory:
-    tmp = tempfile.mkdtemp('build')
-    tmp2 = tempfile.mkdtemp('build')
+    undo = []
     try:
+        tmp = tempfile.mkdtemp('build')
+        undo.append(lambda : shutil.rmtree(tmp)) 
+        tmp2 = tempfile.mkdtemp('build')
+        undo.append(lambda : shutil.rmtree(tmp2))
+
         index = _get_index(executable, index_url, links)
         dist = index.fetch_distribution(requirement, tmp2, False, True)
         if dist is None:
@@ -445,13 +448,40 @@
         setuptools.command.setopt.edit_config(
             setup_cfg, dict(build_ext=build_ext))
 
-        # Now run easy_install for real:
+        tmp3 = tempfile.mkdtemp('build', dir=dest)
+        undo.append(lambda : shutil.rmtree(tmp3)) 
+
         _call_easy_install(base, env, pkg_resources.WorkingSet(),
-                           dest, links, index_url, executable, True)
+                           tmp3, links, index_url, executable, True)
+
+        return _copyeggs(tmp3, dest, '.egg', undo)
+        
     finally:
-        shutil.rmtree(tmp)
-        shutil.rmtree(tmp2)
+        undo.reverse()
+        [f() for f in undo]
+        
 
+def _rm(*paths):
+    for path in paths:
+        if os.path.isdir(path):
+            shutil.rmtree(path)
+        else:
+            os.remove(path)
+
+def _copyeggs(src, dest, suffix, undo):
+    result = []
+    undo.append(lambda : _rm(*result))
+    for name in os.listdir(src):
+        if name.endswith(suffix):
+            new = os.path.join(dest, name)
+            os.rename(os.path.join(src, name), new)
+            result.append(new)
+
+    assert len(result) == 1
+    undo.pop()
+    
+    return result[0]
+
 def develop(setup, dest,
             build_ext=None,
             executable=sys.executable):
@@ -490,10 +520,13 @@
             __file__ = setup,
             ))
 
+        tmp3 = tempfile.mkdtemp('build', dir=dest)
+        undo.append(lambda : shutil.rmtree(tmp3)) 
+
         args = [
             zc.buildout.easy_install._safe_arg(tsetup),
             '-q', 'develop', '-mxN',
-            '-d', _safe_arg(dest),
+            '-d', _safe_arg(tmp3),
             ]
 
         log_level = logger.getEffectiveLevel()
@@ -506,6 +539,8 @@
 
         assert os.spawnl(os.P_WAIT, executable, executable, *args) == 0
 
+        return _copyeggs(tmp3, dest, '.egg-link', undo)
+
     finally:
         undo.reverse()
         [f() for f in undo]

Modified: zc.buildout/branches/dev/src/zc/buildout/easy_install.txt
===================================================================
--- zc.buildout/branches/dev/src/zc/buildout/easy_install.txt	2006-12-04 16:28:38 UTC (rev 71393)
+++ zc.buildout/branches/dev/src/zc/buildout/easy_install.txt	2006-12-04 20:01:32 UTC (rev 71394)
@@ -489,9 +489,10 @@
   {
       PyObject *m;
       m = Py_InitModule3("extdemo", methods, "");
+  #ifdef TWO
+      PyModule_AddObject(m, "val", PyInt_FromLong(2));
+  #else
       PyModule_AddObject(m, "val", PyInt_FromLong(EXTDEMO));
-  #ifdef VAL2
-      PyModule_AddObject(m, "val2", PyInt_FromLong(2));
   #endif
   }
 
@@ -514,7 +515,10 @@
     ...   'extdemo', dest, 
     ...   {'include-dirs': os.path.join(sample_buildout, 'include')},
     ...   links=[link_server], index=link_server+'index/')
+    '/sample-install/extdemo-1.4-py2.4-unix-i686.egg'
 
+The function returns the list of eggs 
+
 Now if we look in our destination directory, we see we have an extdemo egg:
 
     >>> ls(dest)
@@ -563,7 +567,10 @@
     >>> zc.buildout.easy_install.develop(
     ...   extdemo, dest, 
     ...   {'include-dirs': os.path.join(sample_buildout, 'include')})
+    '/sample-install/extdemo.egg-link'
 
+The name of the egg link created is returned.
+
 Now if we look in our destination directory, we see we have an extdemo
 egg link:
 

Modified: zc.buildout/branches/dev/src/zc/buildout/tests.py
===================================================================
--- zc.buildout/branches/dev/src/zc/buildout/tests.py	2006-12-04 16:28:38 UTC (rev 71393)
+++ zc.buildout/branches/dev/src/zc/buildout/tests.py	2006-12-04 20:01:32 UTC (rev 71394)
@@ -730,6 +730,7 @@
     >>> zc.buildout.easy_install.develop(
     ...   extdemo, dest, 
     ...   {'include-dirs': os.path.join(sample_buildout, 'include')})
+    '/tmp/tmp7AFYXv/_TEST_/dest/extdemo.egg-link'
 
     >>> ls(dest)
     -  extdemo.egg-link
@@ -807,9 +808,10 @@
 {
     PyObject *m;
     m = Py_InitModule3("extdemo", methods, "");
+#ifdef TWO
+    PyModule_AddObject(m, "val", PyInt_FromLong(2));
+#else
     PyModule_AddObject(m, "val", PyInt_FromLong(EXTDEMO));
-#ifdef VAL2
-    PyModule_AddObject(m, "val2", PyInt_FromLong(2));
 #endif
 }
 """

Modified: zc.buildout/branches/dev/zc.recipe.egg_/setup.py
===================================================================
--- zc.buildout/branches/dev/zc.recipe.egg_/setup.py	2006-12-04 16:28:38 UTC (rev 71393)
+++ zc.buildout/branches/dev/zc.recipe.egg_/setup.py	2006-12-04 20:01:32 UTC (rev 71394)
@@ -42,7 +42,9 @@
     tests_require = ['zope.testing'],
     test_suite = name+'.tests.test_suite',
     entry_points = {'zc.buildout': ['default = %s:Egg' % name,
+                                    'script = %s:Egg' % name,
                                     'custom = %s:Custom' % name,
+                                    'develop = %s:Develop' % name,
                                     ]
                     },
     zip_safe=False,

Modified: zc.buildout/branches/dev/zc.recipe.egg_/src/zc/recipe/egg/__init__.py
===================================================================
--- zc.buildout/branches/dev/zc.recipe.egg_/src/zc/recipe/egg/__init__.py	2006-12-04 16:28:38 UTC (rev 71393)
+++ zc.buildout/branches/dev/zc.recipe.egg_/src/zc/recipe/egg/__init__.py	2006-12-04 20:01:32 UTC (rev 71394)
@@ -1,2 +1,2 @@
 from zc.recipe.egg.egg import Egg
-from zc.recipe.egg.custom import Custom
+from zc.recipe.egg.custom import Custom, Develop

Modified: zc.buildout/branches/dev/zc.recipe.egg_/src/zc/recipe/egg/custom.py
===================================================================
--- zc.buildout/branches/dev/zc.recipe.egg_/src/zc/recipe/egg/custom.py	2006-12-04 16:28:38 UTC (rev 71393)
+++ zc.buildout/branches/dev/zc.recipe.egg_/src/zc/recipe/egg/custom.py	2006-12-04 20:01:32 UTC (rev 71394)
@@ -19,12 +19,27 @@
 import os, re, zipfile
 import zc.buildout.easy_install
 
-class Custom:
+class Base:
 
     def __init__(self, buildout, name, options):
-        self.buildout = buildout
-        self.name = name
-        self.options = 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:
@@ -39,47 +54,66 @@
             options['index'] = index
         self.index = index
 
-        options['_b'] = buildout['buildout']['bin-directory']
         options['_e'] = buildout['buildout']['eggs-directory']
-        options['_d'] = buildout['buildout']['develop-eggs-directory']
 
         assert options.get('unzip') in ('true', 'false', None)
 
-        python = options.get('python', buildout['buildout']['python'])
-        options['executable'] = buildout[python]['executable']
+        if buildout['buildout'].get('offline') == 'true':
+            self.install = lambda: ()
 
-        build_ext = {}
-        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()
-            ]
-            build_ext[be_option] = ':'.join(value)
-            options[be_option] = ':'.join(value)
-        self.build_ext = build_ext
-
     def install(self):
-        if self.buildout['buildout'].get('offline') == 'true':
-            return ()
         options = self.options
         distribution = options.get('eggs', self.name).strip()
-        build_ext = dict([
-            (k, options[k])
-            for k in ('include-dirs', 'library-dirs', 'rpath')
-            if k in options
-            ])
-        zc.buildout.easy_install.build(
+        return zc.buildout.easy_install.build(
             distribution, options['_d'], self.build_ext,
             self.links, self.index, options['executable'], [options['_e']],
             )
         
-        return ()
+class Develop(Base):
 
-    update = install
+    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

Modified: zc.buildout/branches/dev/zc.recipe.egg_/src/zc/recipe/egg/custom.txt
===================================================================
--- zc.buildout/branches/dev/zc.recipe.egg_/src/zc/recipe/egg/custom.txt	2006-12-04 16:28:38 UTC (rev 71393)
+++ zc.buildout/branches/dev/zc.recipe.egg_/src/zc/recipe/egg/custom.txt	2006-12-04 20:01:32 UTC (rev 71394)
@@ -1,5 +1,5 @@
-Custon eggs
-===========
+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
@@ -20,6 +20,42 @@
    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
@@ -59,9 +95,10 @@
   {
       PyObject *m;
       m = Py_InitModule3("extdemo", methods, "");
+  #ifdef TWO
+      PyModule_AddObject(m, "val", PyInt_FromLong(2));
+  #else
       PyModule_AddObject(m, "val", PyInt_FromLong(EXTDEMO));
-  #ifdef VAL2
-      PyModule_AddObject(m, "val2", PyInt_FromLong(2));
   #endif
   }
 
@@ -162,3 +199,131 @@
 
     >>> print system(join('bin', 'demo')),
     42
+
+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 = zc.recipe.egg:develop
+    ... include-dirs = include
+    ... define = TWO
+    ...
+    ... [demo]
+    ... recipe = zc.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),
+    buildout: Develop: /tmp/tmpCXjRps/_TEST_/sample-buildout/demo
+    buildout: Uninstalling extdemo
+    buildout: Installing extdemo
+    buildout: Updating demo
+
+Our develop-eggs now includes an egg link for extdemo:
+
+    >>> ls('develop-eggs')
+    -  demo.egg-link
+    -  extdemo.egg-link
+    -  zc.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



More information about the Checkins mailing list