[Checkins] SVN: zc.buildout/branches/gary-betafix/ fix virtualenv interaction by identfying broken virtualenv characteristic and reverting to previous behavior in that case.
Gary Poster
gary.poster at canonical.com
Fri Jun 18 19:56:15 EDT 2010
Log message for revision 113627:
fix virtualenv interaction by identfying broken virtualenv characteristic and reverting to previous behavior in that case.
Changed:
U zc.buildout/branches/gary-betafix/bootstrap/bootstrap.py
U zc.buildout/branches/gary-betafix/dev.py
U zc.buildout/branches/gary-betafix/src/zc/buildout/buildout.py
U zc.buildout/branches/gary-betafix/src/zc/buildout/easy_install.py
U zc.buildout/branches/gary-betafix/src/zc/buildout/testing.py
U zc.buildout/branches/gary-betafix/src/zc/buildout/tests.py
A zc.buildout/branches/gary-betafix/src/zc/buildout/virtualenv.txt
-=-
Modified: zc.buildout/branches/gary-betafix/bootstrap/bootstrap.py
===================================================================
--- zc.buildout/branches/gary-betafix/bootstrap/bootstrap.py 2010-06-18 23:56:12 UTC (rev 113626)
+++ zc.buildout/branches/gary-betafix/bootstrap/bootstrap.py 2010-06-18 23:56:15 UTC (rev 113627)
@@ -20,7 +20,7 @@
$Id$
"""
-import os, shutil, sys, tempfile, textwrap, urllib, urllib2
+import os, shutil, sys, tempfile, textwrap, urllib, urllib2, subprocess
from optparse import OptionParser
if sys.platform == 'win32':
@@ -32,11 +32,18 @@
else:
quote = str
+# Detect https://bugs.launchpad.net/virtualenv/+bug/572545 .
+proc = subprocess.Popen(
+ [sys.executable, '-Sc', 'import ConfigParser'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+proc.communicate()
+has_broken_dash_S = bool(proc.returncode)
+
# In order to be more robust in the face of system Pythons, we want to
# run without site-packages loaded. This is somewhat tricky, in
# particular because Python 2.6's distutils imports site, so starting
# with the -S flag is not sufficient. However, we'll start with that:
-if 'site' in sys.modules:
+if not has_broken_dash_S and 'site' in sys.modules:
# We will restart with python -S.
args = sys.argv[:]
args[0:0] = [sys.executable, '-S']
@@ -167,6 +174,9 @@
'-mqNxd',
quote(eggs_dir)]
+if not has_broken_dash_S:
+ cmd.insert(1, '-S')
+
if options.download_base:
cmd.extend(['-f', quote(options.download_base)])
Modified: zc.buildout/branches/gary-betafix/dev.py
===================================================================
--- zc.buildout/branches/gary-betafix/dev.py 2010-06-18 23:56:12 UTC (rev 113626)
+++ zc.buildout/branches/gary-betafix/dev.py 2010-06-18 23:56:15 UTC (rev 113627)
@@ -19,7 +19,7 @@
$Id$
"""
-import os, shutil, sys, subprocess, urllib2
+import os, shutil, sys, subprocess, urllib2, subprocess
from optparse import OptionParser
if sys.platform == 'win32':
@@ -31,11 +31,15 @@
else:
quote = str
+# Detect https://bugs.launchpad.net/virtualenv/+bug/572545 .
+has_broken_dash_S = subprocess.call(
+ [sys.executable, '-Sc', 'import ConfigParser'])
+
# In order to be more robust in the face of system Pythons, we want to
# run without site-packages loaded. This is somewhat tricky, in
# particular because Python 2.6's distutils imports site, so starting
# with the -S flag is not sufficient. However, we'll start with that:
-if 'site' in sys.modules:
+if not has_broken_dash_S and 'site' in sys.modules:
# We will restart with python -S.
args = sys.argv[:]
args[0:0] = [sys.executable, '-S']
@@ -117,11 +121,15 @@
env = os.environ.copy() # Windows needs yet-to-be-determined values from this.
env['PYTHONPATH'] = os.path.dirname(pkg_resources.__file__)
-subprocess.Popen(
- [sys.executable] +
- ['setup.py', '-q', 'develop', '-m', '-x', '-d', 'develop-eggs'],
- env=env).wait()
+cmd = [quote(sys.executable),
+ 'setup.py', '-q', 'develop', '-m', '-x', '-d', 'develop-eggs']
+
+if not has_broken_dash_S:
+ cmd.insert(1, '-S')
+
+subprocess.Popen(cmd, env=env).wait()
+
pkg_resources.working_set.add_entry('src')
import zc.buildout.easy_install
Modified: zc.buildout/branches/gary-betafix/src/zc/buildout/buildout.py
===================================================================
--- zc.buildout/branches/gary-betafix/src/zc/buildout/buildout.py 2010-06-18 23:56:12 UTC (rev 113626)
+++ zc.buildout/branches/gary-betafix/src/zc/buildout/buildout.py 2010-06-18 23:56:15 UTC (rev 113627)
@@ -34,6 +34,7 @@
import sys
import tempfile
import UserDict
+import warnings
import zc.buildout
import zc.buildout.download
import zc.buildout.easy_install
@@ -51,6 +52,9 @@
if is_jython:
import subprocess
+_sys_executable_has_broken_dash_S = (
+ zc.buildout.easy_install._has_broken_dash_S(sys.executable))
+
class MissingOption(zc.buildout.UserError, KeyError):
"""A required option was missing.
"""
@@ -359,7 +363,7 @@
distributions, options['executable'],
[options['develop-eggs-directory'],
options['eggs-directory']],
- include_site_packages=False,
+ include_site_packages=_sys_executable_has_broken_dash_S,
)
else:
ws = zc.buildout.easy_install.install(
@@ -370,7 +374,7 @@
path=[options['develop-eggs-directory']],
newest=self.newest,
allow_hosts=self._allow_hosts,
- include_site_packages=False,
+ include_site_packages=_sys_executable_has_broken_dash_S,
)
# Now copy buildout and setuptools eggs, and record destination eggs:
@@ -408,7 +412,8 @@
relative_paths = ''
zc.buildout.easy_install.sitepackage_safe_scripts(
options['bin-directory'], ws, options['executable'], partsdir,
- reqs=['zc.buildout'], relative_paths=relative_paths)
+ reqs=['zc.buildout'], relative_paths=relative_paths,
+ include_site_packages=_sys_executable_has_broken_dash_S)
init = bootstrap
@@ -854,7 +859,7 @@
index = options.get('index'),
path = [options['develop-eggs-directory']],
allow_hosts = self._allow_hosts,
- include_site_packages=False
+ include_site_packages=_sys_executable_has_broken_dash_S
)
upgraded = []
@@ -910,7 +915,8 @@
os.mkdir(partsdir)
zc.buildout.easy_install.sitepackage_safe_scripts(
options['bin-directory'], ws, sys.executable, partsdir,
- reqs=['zc.buildout'])
+ reqs=['zc.buildout'],
+ include_site_packages=_sys_executable_has_broken_dash_S)
# Restart
args = map(zc.buildout.easy_install._safe_arg, sys.argv)
@@ -951,7 +957,7 @@
links = self['buildout'].get('find-links', '').split(),
index = self['buildout'].get('index'),
newest=self.newest, allow_hosts=self._allow_hosts,
- include_site_packages=False)
+ include_site_packages=_sys_executable_has_broken_dash_S)
# Clear cache because extensions might now let us read pages we
# couldn't read before.
@@ -1069,8 +1075,7 @@
working_set=pkg_resources.working_set,
newest=buildout.newest,
allow_hosts=buildout._allow_hosts,
- include_site_packages=False,
- )
+ include_site_packages=_sys_executable_has_broken_dash_S)
__doing__ = 'Loading %s recipe entry %s:%s.', group, spec, entry
return pkg_resources.load_entry_point(
@@ -1577,6 +1582,11 @@
will be started. This is especially useful for debuging recipe
problems.
+ -s
+
+ Squelch warnings about using an executable with a broken -S
+ implementation.
+
Assignments are of the form: section:option=value and are used to
provide configuration options that override those given in the
configuration file. For example, to run the buildout in offline mode,
@@ -1642,11 +1652,12 @@
windows_restart = False
user_defaults = True
debug = False
+ ignore_broken_dash_s = False
while args:
if args[0][0] == '-':
op = orig_op = args.pop(0)
op = op[1:]
- while op and op[0] in 'vqhWUoOnNDA':
+ while op and op[0] in 'vqhWUoOnNDAs':
if op[0] == 'v':
verbosity += 10
elif op[0] == 'q':
@@ -1665,6 +1676,8 @@
options.append(('buildout', 'newest', 'false'))
elif op[0] == 'D':
debug = True
+ elif op[0] == 's':
+ ignore_broken_dash_s = True
else:
_help()
op = op[1:]
@@ -1708,6 +1721,17 @@
# The rest should be commands, so we'll stop here
break
+ if verbosity < 0 or ignore_broken_dash_s:
+ broken_dash_S_filter_action = 'ignore'
+ elif verbosity == 0: # This is the default.
+ broken_dash_S_filter_action = 'once'
+ else:
+ broken_dash_S_filter_action = 'default'
+ warnings.filterwarnings(
+ broken_dash_S_filter_action,
+ re.escape(
+ zc.buildout.easy_install.BROKEN_DASH_S_WARNING),
+ UserWarning)
if verbosity:
options.append(('buildout', 'verbosity', str(verbosity)))
Modified: zc.buildout/branches/gary-betafix/src/zc/buildout/easy_install.py
===================================================================
--- zc.buildout/branches/gary-betafix/src/zc/buildout/easy_install.py 2010-06-18 23:56:12 UTC (rev 113626)
+++ zc.buildout/branches/gary-betafix/src/zc/buildout/easy_install.py 2010-06-18 23:56:15 UTC (rev 113627)
@@ -33,6 +33,7 @@
import subprocess
import sys
import tempfile
+import warnings
import zc.buildout
import zipimport
@@ -54,6 +55,18 @@
is_distribute = (
pkg_resources.Requirement.parse('setuptools').key=='distribute')
+BROKEN_DASH_S_WARNING = (
+ 'Buildout has been asked to exclude or limit site-packages so that '
+ 'builds can be repeatable when using a system Python. However, '
+ 'the chosen Python executable has a broken implementation of -S (see '
+ 'https://bugs.launchpad.net/virtualenv/+bug/572545 for an example '
+ "problem) and this breaks buildout's ability to isolate site-packages. "
+ "If the executable already has a clean site-packages (e.g., "
+ "using virtualenv's ``--no-site-packages`` option) you may be getting "
+ 'equivalent repeatability. To silence this warning, use the -s argument '
+ 'to the buildout script. Alternatively, use a Python executable with a '
+ 'working -S (such as a standard Python binary).')
+
if is_jython:
import java.lang.System
jython_os_name = (java.lang.System.getProperties()['os.name']).lower()
@@ -70,6 +83,14 @@
if os.path.normpath(setuptools_loc) != os.path.normpath(buildout_loc):
buildout_and_setuptools_path.append(buildout_loc)
+def _has_broken_dash_S(executable):
+ """Detect https://bugs.launchpad.net/virtualenv/+bug/572545 ."""
+ proc = subprocess.Popen(
+ [executable, '-Sc', 'import ConfigParser'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ proc.communicate()
+ return bool(proc.returncode)
+
def _get_system_paths(executable):
"""Return lists of standard lib and site paths for executable.
"""
@@ -209,10 +230,10 @@
_safe_arg = str
# The following string is used to run easy_install in
-# Installer._call_easy_install. It is started with python -S (that is,
-# don't import site at start). That flag, and all of the code in this
-# snippet above the last two lines, exist to work around a relatively rare
-# problem. If
+# Installer._call_easy_install. It is usually started with python -S
+# (that is, don't import site at start). That flag, and all of the code
+# in this snippet above the last two lines, exist to work around a
+# relatively rare problem. If
#
# - your buildout configuration is trying to install a package that is within
# a namespace package, and
@@ -264,17 +285,16 @@
# unnecessary for site.py to preprocess these packages, so it should be
# fine, as far as can be guessed as of this writing.) Finally, it
# imports easy_install and runs it.
-
-_easy_install_cmd = _safe_arg('''\
+_easy_install_preface = '''\
import sys,os;\
p = sys.path[:];\
import site;\
sys.path[:] = p;\
[sys.modules.pop(k) for k, v in sys.modules.items()\
if hasattr(v, '__path__') and len(v.__path__)==1 and\
- not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))];\
-from setuptools.command.easy_install import main;\
-main()''')
+ not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))];'''
+_easy_install_cmd = (
+ 'from setuptools.command.easy_install import main;main()')
class Installer:
@@ -321,6 +341,7 @@
self._index_url = index
self._executable = executable
+ self._has_broken_dash_S = _has_broken_dash_S(self._executable)
if always_unzip is not None:
self._always_unzip = always_unzip
path = (path and path[:] or [])
@@ -329,6 +350,17 @@
if allowed_eggs_from_site_packages is not None:
self._allowed_eggs_from_site_packages = tuple(
allowed_eggs_from_site_packages)
+ if self._has_broken_dash_S:
+ if (not self._include_site_packages or
+ self._allowed_eggs_from_site_packages != ('*',)):
+ # We can't do this if the executable has a broken -S.
+ warnings.warn(BROKEN_DASH_S_WARNING)
+ self._include_site_packages = True
+ self._allowed_eggs_from_site_packages = ('*',)
+ self._easy_install_cmd = _easy_install_preface + _easy_install_cmd
+ else:
+ self._easy_install_cmd = _easy_install_cmd
+ self._easy_install_cmd = _safe_arg(self._easy_install_cmd)
stdlib, self._site_packages = _get_system_paths(executable)
version_info = _get_version_info(executable)
if version_info == sys.version_info:
@@ -487,7 +519,9 @@
try:
path = setuptools_loc
- args = ('-Sc', _easy_install_cmd, '-mUNxd', _safe_arg(tmp))
+ args = ('-c', self._easy_install_cmd, '-mUNxd', _safe_arg(tmp))
+ if not self._has_broken_dash_S:
+ args = ('-S',) + args
if self._always_unzip:
args += ('-Z', )
level = logger.getEffectiveLevel()
@@ -1176,6 +1210,11 @@
_pyscript(spath, sname, executable, rpsetup))
return generated
+# We need to give an alternate name to the ``scripts`` function so that it
+# can be referenced within sitepackage_safe_scripts, which uses ``scripts``
+# as an argument name.
+_original_scripts_function = scripts
+
def sitepackage_safe_scripts(
dest, working_set, executable, site_py_dest,
reqs=(), scripts=None, interpreter=None, extra_paths=(),
@@ -1188,6 +1227,12 @@
Python site packages, if desired, and choosing to execute the Python's
sitecustomize.
"""
+ if _has_broken_dash_S(executable):
+ if not include_site_packages:
+ warnings.warn(BROKEN_DASH_S_WARNING)
+ return _original_scripts_function(
+ reqs, working_set, executable, dest, scripts, extra_paths,
+ script_arguments, interpreter, initialization, relative_paths)
generated = []
generated.append(_generate_sitecustomize(
site_py_dest, executable, initialization, exec_sitecustomize))
Modified: zc.buildout/branches/gary-betafix/src/zc/buildout/testing.py
===================================================================
--- zc.buildout/branches/gary-betafix/src/zc/buildout/testing.py 2010-06-18 23:56:12 UTC (rev 113626)
+++ zc.buildout/branches/gary-betafix/src/zc/buildout/testing.py 2010-06-18 23:56:15 UTC (rev 113627)
@@ -596,7 +596,7 @@
sep = re.escape(os.path.sep)
normalize_path = (
re.compile(
- r'''[^'" \t\n\r]+%(sep)s_[Tt][Ee][Ss][Tt]_%(sep)s([^"' \t\n\r]+)'''
+ r'''[^'" \t\n\r!]+%(sep)s_[Tt][Ee][Ss][Tt]_%(sep)s([^"' \t\n\r]+)'''
% dict(sep=sep)),
_normalize_path,
)
Modified: zc.buildout/branches/gary-betafix/src/zc/buildout/tests.py
===================================================================
--- zc.buildout/branches/gary-betafix/src/zc/buildout/tests.py 2010-06-18 23:56:12 UTC (rev 113626)
+++ zc.buildout/branches/gary-betafix/src/zc/buildout/tests.py 2010-06-18 23:56:15 UTC (rev 113627)
@@ -3923,14 +3923,29 @@
setUp=easy_install_SetUp,
tearDown=zc.buildout.testing.buildoutTearDown,
checker=renormalizing.RENormalizing([
- zc.buildout.testing.normalize_path,
- zc.buildout.testing.normalize_endings,
- zc.buildout.testing.normalize_script,
- normalize_bang,
- (re.compile('Downloading.*setuptools.*egg\n'), ''),
- (re.compile('options:'), 'Options:'),
- (re.compile('usage:'), 'Usage:'),
- ]),
+ zc.buildout.testing.normalize_path,
+ zc.buildout.testing.normalize_endings,
+ zc.buildout.testing.normalize_script,
+ normalize_bang,
+ (re.compile('Downloading.*setuptools.*egg\n'), ''),
+ (re.compile('options:'), 'Options:'),
+ (re.compile('usage:'), 'Usage:'),
+ ]),
))
+ test_suite.append(doctest.DocFileSuite(
+ 'virtualenv.txt',
+ setUp=easy_install_SetUp,
+ tearDown=zc.buildout.testing.buildoutTearDown,
+ checker=renormalizing.RENormalizing([
+ zc.buildout.testing.normalize_path,
+ zc.buildout.testing.normalize_endings,
+ zc.buildout.testing.normalize_script,
+ zc.buildout.testing.normalize_egg_py,
+ (re.compile('(setuptools|distribute)-\S+-'),
+ 'setuptools.egg'),
+ (re.compile('zc.buildout-\S+-'),
+ 'zc.buildout.egg'),
+ ]),
+ ))
return unittest.TestSuite(test_suite)
Added: zc.buildout/branches/gary-betafix/src/zc/buildout/virtualenv.txt
===================================================================
--- zc.buildout/branches/gary-betafix/src/zc/buildout/virtualenv.txt (rev 0)
+++ zc.buildout/branches/gary-betafix/src/zc/buildout/virtualenv.txt 2010-06-18 23:56:15 UTC (rev 113627)
@@ -0,0 +1,240 @@
+Version 1.5.0 of buildout (and higher) provides the ability to use
+buildout directly with a system Python if you use z3c.recipe.scripts or
+other isolation-aware recipes that use the sitepackage_safe_scripts function.
+
+Some people use virtualenv to provide similar functionality.
+Unfortunately, a problem with the virtualenv executable as of this
+writing means that -S will not work properly with it (see
+https://bugs.launchpad.net/virtualenv/+bug/572545). This breaks
+buildout's approach to providing isolation.
+
+Because of this, if buildout detects an executable with a broken -S
+option, it will revert to its pre-1.5.0 behavior. If buildout has been
+asked to provide isolation, it will warn the user that isolation will
+not be provided by buildout, but proceed. This should give full
+backwards compatibility to virtualenv users.
+
+The only minor annoyance in the future may be recipes that explicitly
+use the new buildout functionality to provide isolation: as described
+above, the builds will proceed, but users will receive warnings that
+buildout is not providing isolation itself. The warnings themselves can
+be squelched when running bin/buildout with the ``-s`` option or with a
+lower verbosity than usual (e.g., one or more ``-q`` options).
+
+For tests, then, we can examine several things. We'll focus on four.
+
+- Running bootstrap with an executable broken in this way will not try to do
+ any -S tricks.
+
+- Running sitepackage_safe_scripts with a virtualenv will create an
+ old-style script. This will affect the bin/buildout script that is
+ created, for instance. If the sitepackage_safe_scripts function is asked
+ to provide isolation under these circumstances, it will warn that isolation
+ will not be available, but still create the desired script.
+
+- Using the easy_install Installer or install or build functions and trying
+ to request isolation will generate a warning and then the isolation request
+ will be ignored as it proceeds.
+
+- Passing -s (or -q) to the bin/buildout script will squelch warnings.
+
+Testing these involves first creating a Python that exhibits the same
+behavior as the problematic one we care about from virtualenv. Let's do that
+first.
+
+ >>> import os, sys
+ >>> py_path, site_packages_path = make_py()
+ >>> py_file = open(py_path)
+ >>> py_lines = py_file.readlines()
+ >>> py_file.close()
+ >>> py_file = open(py_path, 'w')
+ >>> extra = '''\
+ ... new_argv = argv[:1]
+ ... for ix, val in enumerate(argv[1:]):
+ ... if val.startswith('--'):
+ ... new_argv.append(val)
+ ... if val.startswith('-') and len(val) > 1:
+ ... if 'S' in val:
+ ... val = val.replace('S', '')
+ ... environ['BROKEN_DASH_S'] = 'Y'
+ ... if val != '-':
+ ... new_argv.append(val)
+ ... if 'c' in val:
+ ... new_argv.extend(argv[ix+2:])
+ ... break
+ ... else:
+ ... new_argv.extend(argv[ix+1:])
+ ... argv = new_argv
+ ... '''
+ >>> for line in py_lines:
+ ... py_file.write(line)
+ ... if line.startswith('environ = os.environ.copy()'):
+ ... py_file.write(extra)
+ ... print 'Rewritten.'
+ ...
+ Rewritten.
+ >>> py_file.close()
+ >>> sitecustomize_path = join(os.path.dirname(site_packages_path),
+ ... 'parts', 'py', 'sitecustomize.py')
+ >>> sitecustomize_file = open(sitecustomize_path, 'a')
+ >>> sitecustomize_file.write('''
+ ... import os, sys
+ ... sys.executable = %r
+ ... if 'BROKEN_DASH_S' in os.environ:
+ ... class ImportHook:
+ ... @staticmethod
+ ... def find_module(fullname, path=None):
+ ... if fullname == 'ConfigParser':
+ ... raise ImportError()
+ ...
+ ... sys.meta_path.append(ImportHook)
+ ... sys.modules.pop('site', None) # Keeps site out of sys.modules.
+ ... # This will be a close-enough approximation of site not being
+ ... # loaded for our tests--it lets us provoke the right errors when
+ ... # the fixes are absent, and works well enough when the fixes are
+ ... # present.
+ ... ''' % (py_path,))
+ >>> sitecustomize_file.close()
+ >>> print call_py(
+ ... py_path,
+ ... "import ConfigParser")
+ <BLANKLINE>
+ >>> print 'X'; print call_py(
+ ... py_path,
+ ... "import ConfigParser",
+ ... '-S') # doctest: +ELLIPSIS
+ X...Traceback (most recent call last):
+ ...
+ ImportError: No module named ConfigParser
+ <BLANKLINE>
+ >>> from zc.buildout.easy_install import _has_broken_dash_S
+ >>> _has_broken_dash_S(py_path)
+ True
+
+Well, that was ugly, but it seems to have done the trick. The
+executable represented by py_path has the same problematic
+characteristic as the virtualenv one: -S results in a Python that does
+not allow the import of some packages from the standard library. We'll
+test with this.
+
+First, let's try running bootstrap.
+
+ >>> from os.path import dirname, join
+ >>> import zc.buildout
+ >>> bootstrap_py = join(
+ ... dirname(
+ ... dirname(
+ ... dirname(
+ ... dirname(zc.buildout.__file__)
+ ... )
+ ... )
+ ... ),
+ ... 'bootstrap', 'bootstrap.py')
+ >>> broken_S_buildout = tmpdir('broken_S')
+ >>> os.chdir(broken_S_buildout)
+ >>> write('buildout.cfg',
+ ... '''
+ ... [buildout]
+ ... parts =
+ ... ''')
+ >>> write('bootstrap.py', open(bootstrap_py).read())
+ >>> print 'X'; print system(
+ ... zc.buildout.easy_install._safe_arg(py_path)+' '+
+ ... 'bootstrap.py'); print 'X' # doctest: +ELLIPSIS
+ X...
+ Generated script '/broken_S/bin/buildout'.
+ ...
+
+If bootstrap didn't look out for a broken -S, that would have failed. Moreover,
+take a look at bin/buildout:
+
+ >>> cat('bin', 'buildout')
+ #!/executable_buildout/bin/py
+ <BLANKLINE>
+ import sys
+ sys.path[0:0] = [
+ '/broken_S/eggs/setuptools-0.0-pyN.N.egg',
+ '/broken_S/eggs/zc.buildout-0.0-pyN.N.egg',
+ ]
+ <BLANKLINE>
+ import zc.buildout.buildout
+ <BLANKLINE>
+ if __name__ == '__main__':
+ zc.buildout.buildout.main()
+
+That's the old-style buildout script: no changes for users with this issue.
+
+Of course, they don't get the new features either, presumably because
+they don't need or want them. This means that if they use a recipe that
+tries to use a new feature, the behavior needs to degrade gracefully.
+
+Here's an example. We'll switch to another buildout in which it is easier to
+use local dev versions of zc.buildout and z3c.recipe.scripts.
+
+ >>> os.chdir(dirname(dirname(buildout)))
+ >>> write('buildout.cfg',
+ ... '''
+ ... [buildout]
+ ... parts = eggs
+ ... find-links = %(link_server)s
+ ...
+ ... [primed_python]
+ ... executable = %(py_path)s
+ ...
+ ... [eggs]
+ ... recipe = z3c.recipe.scripts
+ ... python = primed_python
+ ... interpreter = py
+ ... eggs = demo
+ ... ''' % globals())
+
+ >>> print system(buildout) # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
+ Installing eggs.
+ Getting distribution for 'demo'.
+ Got demo 0.4c1.
+ Getting distribution for 'demoneeded'.
+ Got demoneeded 1.2c1.
+ Generated script '/sample-buildout/bin/demo'.
+ Generated interpreter '/sample-buildout/bin/py'.
+ ...UserWarning: Buildout has been asked to exclude or limit site-packages
+ so that builds can be repeatable when using a system Python. However,
+ the chosen Python executable has a broken implementation of -S (see
+ https://bugs.launchpad.net/virtualenv/+bug/572545 for an example
+ problem) and this breaks buildout's ability to isolate site-packages.
+ If the executable already has a clean site-packages (e.g., using
+ virtualenv's ``--no-site-packages`` option) you may be getting
+ equivalent repeatability. To silence this warning, use the -s argument
+ to the buildout script. Alternatively, use a Python executable with a
+ working -S (such as a standard Python binary).
+ warnings.warn(BROKEN_DASH_S_WARNING)
+ <BLANKLINE>
+
+So, it did what we asked as best it could, but gave a big warning. If
+you don't want those warnings for those particular recipes that use the
+new features, you can use the "-s" option to squelch the warnings.
+
+ >>> print system(buildout + ' -s')
+ Updating eggs.
+ <BLANKLINE>
+
+A lower verbosity (one or more -q options) also quiets the warning.
+
+ >>> print system(buildout + ' -q')
+ <BLANKLINE>
+
+Notice that, as we saw before with bin/buildout, the generated scripts
+are old-style, because the new-style feature gracefully degrades to the
+previous implementation when it encounters an executable with a broken
+dash-S.
+
+ >>> print 'X'; cat('bin', 'py') # doctest: +ELLIPSIS
+ X...
+ <BLANKLINE>
+ import sys
+ <BLANKLINE>
+ sys.path[0:0] = [
+ '/sample-buildout/eggs/demo-0.4c1-pyN.N.egg',
+ '/sample-buildout/eggs/demoneeded-1.2c1-pyN.N.egg',
+ ]
+ ...
+
More information about the checkins
mailing list