[Checkins] SVN: zc.buildout/branches/dev/src/zc/buildout/ Added a function for creating develop eggs and changed the buildout to

Jim Fulton jim at zope.com
Sun Dec 3 17:56:06 EST 2006


Log message for revision 71389:
  Added a function for creating develop eggs and changed the buildout to
  use it.
  
  Simplified the develop logging output a little.
  

Changed:
  U   zc.buildout/branches/dev/src/zc/buildout/buildout.py
  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

-=-
Modified: zc.buildout/branches/dev/src/zc/buildout/buildout.py
===================================================================
--- zc.buildout/branches/dev/src/zc/buildout/buildout.py	2006-12-03 22:56:02 UTC (rev 71388)
+++ zc.buildout/branches/dev/src/zc/buildout/buildout.py	2006-12-03 22:56:05 UTC (rev 71389)
@@ -334,46 +334,8 @@
             try:
                 for setup in develop.split():
                     setup = self._buildout_path(setup)
-                    if os.path.isdir(setup):
-                        setup = os.path.join(setup, 'setup.py')
-
                     self._logger.info("Develop: %s", setup)
-
-
-                    fd, tsetup = tempfile.mkstemp()
-                    try:
-                        os.write(fd, runsetup_template % dict(
-                            setuptools=pkg_resources_loc,
-                            setupdir=os.path.dirname(setup),
-                            setup=setup,
-                            __file__ = setup,
-                            ))
-
-                        args = [
-                            zc.buildout.easy_install._safe_arg(tsetup),
-                            '-q', 'develop', '-mxN',
-                            '-f', zc.buildout.easy_install._safe_arg(
-                                ' '.join(self._links)
-                                ),
-                            '-d', zc.buildout.easy_install._safe_arg(dest),
-                            ]
-
-                        if self._log_level <= logging.DEBUG:
-                            if self._log_level == logging.DEBUG:
-                                del args[1]
-                            else:
-                                args[1] == '-v'
-                            self._logger.debug("in: %s\n%r",
-                                               os.path.dirname(setup), args)
-
-                        assert os.spawnl(
-                            os.P_WAIT, sys.executable, sys.executable,
-                            *args) == 0
-
-                    finally:
-                        os.close(fd)
-                        os.remove(tsetup)
-
+                    zc.buildout.easy_install.develop(setup, dest)
             except:
                 # if we had an error, we need to roll back changes, by
                 # removing any files we created.
@@ -531,8 +493,11 @@
         if (realpath(os.path.abspath(sys.argv[0]))
             !=
             realpath(
-                os.path.join(os.path.abspath(self['buildout']['bin-directory']),
-                             'buildout')
+                os.path.join(os.path.abspath(
+                                 self['buildout']['bin-directory']
+                                 ),
+                             'buildout',
+                             )
                 )
             ):
             self._logger.debug("Running %r", realpath(sys.argv[0]))
@@ -608,7 +573,7 @@
 
         fd, tsetup = tempfile.mkstemp()
         try:
-            os.write(fd, runsetup_template % dict(
+            os.write(fd, zc.buildout.easy_install.runsetup_template % dict(
                 setuptools=pkg_resources_loc,
                 setupdir=os.path.dirname(setup),
                 setup=setup,
@@ -795,20 +760,7 @@
 
     def copy(self):
         return dict([(k, self[k]) for k in self.keys()])
-        
-runsetup_template = """
-import sys
-sys.path.insert(0, %(setuptools)r)
-import os, setuptools
 
-__file__ = %(__file__)r
-
-os.chdir(%(setupdir)r)
-sys.argv[0] = %(setup)r
-execfile(%(setup)r)
-"""
-
-
 _spacey_nl = re.compile('[ \t\r\f\v]*\n[ \t\r\f\v\n]*'
                         '|'
                         '^[ \t\r\f\v]+'

Modified: zc.buildout/branches/dev/src/zc/buildout/easy_install.py
===================================================================
--- zc.buildout/branches/dev/src/zc/buildout/easy_install.py	2006-12-03 22:56:02 UTC (rev 71388)
+++ zc.buildout/branches/dev/src/zc/buildout/easy_install.py	2006-12-03 22:56:05 UTC (rev 71389)
@@ -34,11 +34,14 @@
 
 url_match = re.compile('[a-z0-9+.-]+://').match
 
+setuptools_loc = pkg_resources.working_set.find(
+    pkg_resources.Requirement.parse('setuptools')
+    ).location
+
 # Include buildout and setuptools eggs in paths
 buildout_and_setuptools_path = [
+    setuptools_loc,
     pkg_resources.working_set.find(
-        pkg_resources.Requirement.parse('setuptools')).location,
-    pkg_resources.working_set.find(
         pkg_resources.Requirement.parse('zc.buildout')).location,
     ]
 
@@ -407,8 +410,8 @@
         return dist
 
     # Get an editable version of the package to a temporary directory:
-    tmp = tempfile.mkdtemp('editable')
-    tmp2 = tempfile.mkdtemp('editable')
+    tmp = tempfile.mkdtemp('build')
+    tmp2 = tempfile.mkdtemp('build')
     try:
         index = _get_index(executable, index_url, links)
         dist = index.fetch_distribution(requirement, tmp2, False, True)
@@ -449,6 +452,65 @@
         shutil.rmtree(tmp)
         shutil.rmtree(tmp2)
 
+def develop(setup, dest,
+            build_ext=None,
+            executable=sys.executable):
+
+    if os.path.isdir(setup):
+        directory = setup
+        setup = os.path.join(directory, 'setup.py')
+    else:
+        directory = os.path.dirname(setup)
+        
+    undo = []
+    try:
+        if build_ext:
+            setup_cfg = os.path.join(directory, 'setup.cfg')
+            if os.path.exists(setup_cfg):
+                os.rename(setup_cfg, setup_cfg+'-develop-aside')
+                def restore_old_setup():
+                    if os.path.exists(setup_cfg):
+                        os.remove(setup_cfg)
+                    os.rename(setup_cfg+'-develop-aside', setup_cfg)
+                undo.append(restore_old_setup)
+            else:
+                open(setup_cfg, 'w')
+                undo.append(lambda: os.remove(setup_cfg))
+            setuptools.command.setopt.edit_config(
+                setup_cfg, dict(build_ext=build_ext))
+
+        fd, tsetup = tempfile.mkstemp()
+        undo.append(lambda: os.remove(tsetup))
+        undo.append(lambda: os.close(fd))
+
+        os.write(fd, runsetup_template % dict(
+            setuptools=setuptools_loc,
+            setupdir=directory,
+            setup=setup,
+            __file__ = setup,
+            ))
+
+        args = [
+            zc.buildout.easy_install._safe_arg(tsetup),
+            '-q', 'develop', '-mxN',
+            '-d', _safe_arg(dest),
+            ]
+
+        log_level = logger.getEffectiveLevel()
+        if log_level <= logging.DEBUG:
+            if log_level == logging.DEBUG:
+                del args[1]
+            else:
+                args[1] == '-v'
+            logger.debug("in: %s\n%r", directory, args)
+
+        assert os.spawnl(os.P_WAIT, executable, executable, *args) == 0
+
+    finally:
+        undo.reverse()
+        [f() for f in undo]
+            
+            
 def working_set(specs, executable, path):
     return install(specs, None, executable=executable, path=path)
 
@@ -595,6 +657,15 @@
     import code
     code.interact(banner="", local=globals())
 '''
+        
+runsetup_template = """
+import sys
+sys.path.insert(0, %(setuptools)r)
+import os, setuptools
 
+__file__ = %(__file__)r
 
-
+os.chdir(%(setupdir)r)
+sys.argv[0] = %(setup)r
+execfile(%(setup)r)
+"""

Modified: zc.buildout/branches/dev/src/zc/buildout/easy_install.txt
===================================================================
--- zc.buildout/branches/dev/src/zc/buildout/easy_install.txt	2006-12-03 22:56:02 UTC (rev 71388)
+++ zc.buildout/branches/dev/src/zc/buildout/easy_install.txt	2006-12-03 22:56:05 UTC (rev 71389)
@@ -1,8 +1,9 @@
-Minimal Python interface to easy_install
-========================================
+Python API for egg and script installation
+==========================================
 
-The easy_install module provides a minimal interface to the setuptools
-easy_install command that provides some additional semantics:
+The easy_install module provides some functions to provide support for
+egg and script installation.  It provides functionality at the python
+level that is similar to easy_install, with a few exceptions:
 
 - By default, we look for new packages *and* the packages that
   they depend on.  This is somewhat like (and uses) the --upgrade
@@ -21,8 +22,8 @@
 - Distutils options for building extensions can be passed.
 
 The easy_install module provides a method, install, for installing one
-or more packages and their dependencies.  The
-install function takes 2 positional arguments:
+or more packages and their dependencies.  The install function takes 2
+positional arguments:
 
 - An iterable of setuptools requirement strings for the distributions
   to be installed, and
@@ -426,18 +427,18 @@
         eggrecipedemo.main(1, 2)
 
 
-Handling custom build options for extensions
---------------------------------------------
+Handling custom build options for extensions provided in source distributions
+-----------------------------------------------------------------------------
 
 Sometimes, we need to control how extension modules are built.  The
-build method provides this level of control.  It takes a single
+build function provides this level of control.  It takes a single
 package specification, downloads a source distribution, and builds it
 with specified custom build options.
 
-The build method takes 3 positional arguments:
+The build function takes 3 positional arguments:
 
 spec
-   A package specification
+   A package specification for a source distribution
 
 dest
    A destination directory
@@ -486,9 +487,12 @@
   PyMODINIT_FUNC
   initextdemo(void)
   {
-      PyObject *d;
-      d = Py_InitModule3("extdemo", methods, "");
-      PyDict_SetItemString(d, "val", PyInt_FromLong(EXTDEMO));    
+      PyObject *m;
+      m = Py_InitModule3("extdemo", methods, "");
+      PyModule_AddObject(m, "val", PyInt_FromLong(EXTDEMO));
+  #ifdef VAL2
+      PyModule_AddObject(m, "val2", PyInt_FromLong(2));
+  #endif
   }
 
 The extension depends on a system-dependnt include file, extdemo.h,
@@ -497,9 +501,11 @@
 We'll add an include directory to our sample buildout and add the
 needed include file to it:
 
-    >>> mkdir(sample_buildout, 'include')
-    >>> open(os.path.join(sample_buildout, 'include', 'extdemo.h'), 'w').write(
-    ...    "#define EXTDEMO 42\n")
+    >>> mkdir('include')
+    >>> write('include', 'extdemo.h',
+    ... """
+    ... #define EXTDEMO 42
+    ... """)
 
 Now, we can use the build function to create an egg from the source
 distribution:
@@ -516,3 +522,65 @@
     d  demoneeded-1.1-py2.4.egg
     d  extdemo-1.4-py2.4-unix-i686.egg
 
+Handling custom build options for extensions in develop eggs
+------------------------------------------------------------
+
+The develop function is similar to the build function, except that,
+rather than building an egg from a source directory containing a
+setup.py script.  
+
+The develop function takes 2 positional arguments:
+
+setup
+   The path to a setup script, typically named "setup.py", or a
+   directory containing a setup.py script.
+
+dest
+   The directory to install the egg link to
+
+It supports some optional keyword argument:
+
+build_ext
+   A dictionary of options to be passed to the distutils build_ext
+   command when building extensions.
+
+executable
+   A path to a Python executable.  Distributions will ne installed
+   using this executable and will be for the matching Python version.
+
+We have a local directory containing the extdemo source:
+
+    >>> ls(extdemo)
+    -  MANIFEST
+    -  MANIFEST.in
+    -  README
+    -  extdemo.c
+    -  setup.py
+
+Now, we can use the develop function to create a develop egg from the source
+distribution:
+
+    >>> zc.buildout.easy_install.develop(
+    ...   extdemo, dest, 
+    ...   {'include-dirs': os.path.join(sample_buildout, 'include')})
+
+Now if we look in our destination directory, we see we have an extdemo
+egg link:
+
+    >>> ls(dest)
+    d  demo-0.3-py2.4.egg
+    d  demoneeded-1.1-py2.4.egg
+    d  extdemo-1.4-py2.4-linux-i686.egg
+    -  extdemo.egg-link
+
+And that the source directory contains the compiled extension:
+
+    >>> ls(extdemo)
+    -  MANIFEST
+    -  MANIFEST.in
+    -  README
+    d  build
+    -  extdemo.c
+    d  extdemo.egg-info
+    -  extdemo.so
+    -  setup.py

Modified: zc.buildout/branches/dev/src/zc/buildout/tests.py
===================================================================
--- zc.buildout/branches/dev/src/zc/buildout/tests.py	2006-12-03 22:56:02 UTC (rev 71388)
+++ zc.buildout/branches/dev/src/zc/buildout/tests.py	2006-12-03 22:56:05 UTC (rev 71389)
@@ -45,7 +45,7 @@
     ... ''')
 
     >>> print system(join('bin', 'buildout')),
-    buildout: Develop: /sample-buildout/foo/setup.py
+    buildout: Develop: /sample-buildout/foo
 
     >>> ls('develop-eggs')
     -  foo.egg-link
@@ -72,7 +72,7 @@
 
     >>> print system(join('bin', 'buildout')+' -v'), # doctest: +ELLIPSIS
     zc.buildout...
-    buildout: Develop: /sample-buildout/foo/setup.py
+    buildout: Develop: /sample-buildout/foo
     ...
     Installed /sample-buildout/foo
     ...
@@ -263,15 +263,15 @@
     >>> os.chdir(sample_buildout)
     >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
 
-    >>> print system(buildout), # doctest: +ELLIPSIS
-    buildout: Develop: ...setup.py
+    >>> print system(buildout),
+    buildout: Develop: /sample-buildout/recipes
     buildout: Installing debug
 
 If we run the buildout again, we shoudn't get a message about
 uninstalling anything because the configuration hasn't changed.
 
-    >>> print system(buildout), # doctest: +ELLIPSIS
-    buildout: Develop: ...setup.py
+    >>> print system(buildout),
+    buildout: Develop: /sample-buildout/recipes
     buildout: Updating debug
 """
 
@@ -514,7 +514,7 @@
     ... """)
 
     >>> print system(join('bin', 'buildout')),
-    buildout: Develop: /sample-buildout/foo/setup.py
+    buildout: Develop: /sample-buildout/foo
 
     >>> ls('develop-eggs')
     -  foox.egg-link
@@ -535,8 +535,8 @@
     ... """)
 
     >>> print system(join('bin', 'buildout')),
-    buildout: Develop: /sample-buildout/foo/setup.py
-    buildout: Develop: /sample-buildout/bar/setup.py
+    buildout: Develop: /sample-buildout/foo
+    buildout: Develop: /sample-buildout/bar
 
     >>> ls('develop-eggs')
     -  foox.egg-link
@@ -551,7 +551,7 @@
     ... parts =
     ... """)
     >>> print system(join('bin', 'buildout')),
-    buildout: Develop: /sample-buildout/bar/setup.py
+    buildout: Develop: /sample-buildout/bar
 
 It is gone
 
@@ -610,7 +610,7 @@
     ... """)
 
     >>> print system(join('bin', 'buildout')),
-    buildout: Develop: /sample-buildout/foo/setup.py
+    buildout: Develop: /sample-buildout/foo
 
 Now, if we generate a working set using the egg link, we will get a warning
 and we will get setuptools included in the working set.
@@ -658,7 +658,6 @@
     ...     ])]
     ['foox', 'setuptools']
 
-
     >>> print handler,
 
 We get the same behavior if the it is a depedency that uses a
@@ -681,8 +680,8 @@
     ... """)
 
     >>> print system(join('bin', 'buildout')),
-    buildout: Develop: /sample-buildout/foo/setup.py
-    buildout: Develop: /sample-buildout/bar/setup.py
+    buildout: Develop: /sample-buildout/foo
+    buildout: Develop: /sample-buildout/bar
 
     >>> [dist.project_name
     ...  for dist in zc.buildout.easy_install.working_set(
@@ -702,7 +701,52 @@
     >>> handler.uninstall()
 
     '''
+
+def develop_preserves_existing_setup_cfg():
+    """
     
+See "Handling custom build options for extensions in develop eggs" in
+easy_install.txt.  This will be very similar except that we'll have an
+existing setup.cfg:
+
+    >>> write(extdemo, "setup.cfg",
+    ... '''
+    ... # sampe cfg file
+    ...
+    ... [foo]
+    ... bar = 1
+    ...
+    ... [build_ext]
+    ... define = X,Y
+    ... ''')
+
+    >>> mkdir('include')
+    >>> write('include', 'extdemo.h',
+    ... '''
+    ... #define EXTDEMO 42
+    ... ''')
+
+    >>> dest = tmpdir('dest')
+    >>> zc.buildout.easy_install.develop(
+    ...   extdemo, dest, 
+    ...   {'include-dirs': os.path.join(sample_buildout, 'include')})
+
+    >>> ls(dest)
+    -  extdemo.egg-link
+
+    >>> cat(extdemo, "setup.cfg")
+    <BLANKLINE>
+    # sampe cfg file
+    <BLANKLINE>
+    [foo]
+    bar = 1
+    <BLANKLINE>
+    [build_ext]
+    define = X,Y
+
+"""
+    
+    
 def create_sample_eggs(test, executable=sys.executable):
     write = test.globs['write']
     dest = test.globs['sample_eggs']
@@ -761,9 +805,12 @@
 PyMODINIT_FUNC
 initextdemo(void)
 {
-    PyObject *d;
-    d = Py_InitModule3("extdemo", methods, "");
-    PyDict_SetItemString(d, "val", PyInt_FromLong(EXTDEMO));    
+    PyObject *m;
+    m = Py_InitModule3("extdemo", methods, "");
+    PyModule_AddObject(m, "val", PyInt_FromLong(EXTDEMO));
+#ifdef VAL2
+    PyModule_AddObject(m, "val2", PyInt_FromLong(2));
+#endif
 }
 """
 
@@ -777,8 +824,8 @@
 """
 
 def add_source_dist(test):
-    import tarfile
-    tmp = tempfile.mkdtemp('test-sdist')
+    
+    tmp = test.globs['extdemo'] = test.globs['tmpdir']('extdemo')
     write = test.globs['write']
     try:
         write(tmp, 'extdemo.c', extdemo_c);
@@ -929,7 +976,7 @@
                ]),
             ),
         doctest.DocTestSuite(
-            setUp=zc.buildout.testing.buildoutSetUp,
+            setUp=easy_install_SetUp,
             tearDown=zc.buildout.testing.buildoutTearDown,
             checker=renormalizing.RENormalizing([
                zc.buildout.testing.normalize_path,



More information about the Checkins mailing list