[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