diff --git a/src/zc/buildout/buildout.py b/src/zc/buildout/buildout.py index d655918fb5eb3abfb19fe0f4a0d3c33b67632b7f..92bd6de46caf13c1857b1997c6495289f66357f2 100644 --- a/src/zc/buildout/buildout.py +++ b/src/zc/buildout/buildout.py @@ -23,6 +23,7 @@ import pprint import re import shutil import sys +import tempfile import ConfigParser import pkg_resources @@ -618,7 +619,43 @@ class Buildout(dict): ) for ep in pkg_resources.iter_entry_points('zc.buildout.extension'): ep.load()(self) - + + def runsetup(self, args): + setup = args.pop(0) + if os.path.isdir(setup): + setup = os.path.join(setup, 'setup.py') + + self._logger.info("Running setup script %s", setup) + setup = os.path.abspath(setup) + + setuptools = pkg_resources.working_set.find( + pkg_resources.Requirement.parse('setuptools') + ).location + + + fd, tsetup = tempfile.mkstemp() + try: + os.write(fd, runsetup_template % dict( + setuptools=setuptools, + setupdir=os.path.dirname(setup), + setup=setup, + )) + os.spawnl(os.P_WAIT, sys.executable, sys.executable, tsetup, + *[zc.buildout.easy_install._safe_arg(a) + for a in args]) + finally: + os.close(fd) + os.remove(tsetup) + +runsetup_template = """ +import sys +sys.path.insert(0, %(setuptools)r) +import os, setuptools + +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]*' @@ -842,7 +879,7 @@ def main(args=None): if args: command = args.pop(0) - if command not in ('install', 'bootstrap'): + if command not in ('install', 'bootstrap', 'runsetup'): _error('invalid command:', command) else: command = 'install' diff --git a/src/zc/buildout/runsetup.txt b/src/zc/buildout/runsetup.txt new file mode 100644 index 0000000000000000000000000000000000000000..5ce4e1131c20b8e9441adc2bb3c71cb5d379c88e --- /dev/null +++ b/src/zc/buildout/runsetup.txt @@ -0,0 +1,46 @@ +Running setup scripts +===================== + +Buildouts are often used to work on packages that will be distributed +as eggs. During development, we use develop eggs. When you've +completed a development cycle, you'll need to run your setup script to +generate a distribution and, perhaps, uploaded it to the Python +package index. If your script uses setuptools, you'll need setuptools +in your Python path, which may be an issue if you haven't installed +setuptools into your Python installation. + +The buildout runsetup command is helpful in a situation like this. It +can be used to run a setup script and it does so with the setuptools +egg in the Python path and with setuptools already imported. The fact +that setuptools is imported means that you can use setuptools-based +commands, like bdist_egg even with packages that don't use setuptools. +To illustrate this, we'll create a package in a sample buildout: + + >>> mkdir(sample_buildout, 'hello') + >>> write(sample_buildout, 'hello', 'hello.py', 'print "Hello World!"') + >>> write(sample_buildout, 'hello', 'README', 'This is hello') + >>> write(sample_buildout, 'hello', 'setup.py', + ... """ + ... from distutils.core import setup + ... setup(name="hello", + ... version="1.0", + ... py_modules=["hello"], + ... author="Bob", + ... author_email="bob@foo.com", + ... ) + ... """) + +We can use the buildout command to generate the hello egg: + + >>> cd(sample_buildout) + >>> import os + >>> print system(os.path.join('bin', 'buildout') + ... +' runsetup hello -q bdist_egg'), + buildout: Running setup script hello/setup.py + zip_safe flag not set; analyzing archive contents... + +The hello directory now has a hello egg in it's dist directory: + + >>> ls(sample_buildout, 'hello', 'dist') + - hello-1.0-py2.4.egg + diff --git a/src/zc/buildout/tests.py b/src/zc/buildout/tests.py index bfbc5316193823502feb03c771d0cec2067b831d..a1167a0b622ab1732ea69f332af0ccf09618285d 100644 --- a/src/zc/buildout/tests.py +++ b/src/zc/buildout/tests.py @@ -512,7 +512,7 @@ def updateSetup(test): def test_suite(): return unittest.TestSuite(( doctest.DocFileSuite( - 'buildout.txt', + 'buildout.txt', 'runsetup.txt', setUp=zc.buildout.testing.buildoutSetUp, tearDown=zc.buildout.testing.buildoutTearDown, checker=renormalizing.RENormalizing([ @@ -530,6 +530,8 @@ def test_suite(): (re.compile('(\n?)- ([a-zA-Z_.-]+)-script.py\n- \\2.exe\n'), '\\1- \\2\n'), (re.compile("(\w)%s(\w)" % os_path_sep), r"\1/\2"), + (re.compile('hello-1[.]0-py\d[.]\d[.]egg'), + 'hello-1.0-py2.4.egg') ]) ),