Commit 66fee301 authored by Jim Fulton's avatar Jim Fulton

Merge pull request #16 from buildout/de-isolate

removed failed attempt at isolation via -S
parents 4d5f3f33 76f8a02b
...@@ -53,25 +53,6 @@ parser.add_option("-c", None, action="store", dest="config_file", ...@@ -53,25 +53,6 @@ parser.add_option("-c", None, action="store", dest="config_file",
options, args = parser.parse_args() options, args = parser.parse_args()
######################################################################
# handle -S
def normpath(p):
if p.endswith(os.path.sep):
return p[:-1]
else:
return p
nosite = 'site' not in sys.modules
if nosite:
# They've asked not to import site. Cool, but distribute is going to
# import it anyway, so we're going to have to clean up. :(
initial_paths = set(map(normpath, sys.path))
import site
to_remove = set(map(normpath, sys.path)) - initial_paths
else:
to_remove = ()
###################################################################### ######################################################################
# load/install distribute # load/install distribute
...@@ -102,13 +83,6 @@ except ImportError: ...@@ -102,13 +83,6 @@ except ImportError:
if path not in pkg_resources.working_set.entries: if path not in pkg_resources.working_set.entries:
pkg_resources.working_set.add_entry(path) pkg_resources.working_set.add_entry(path)
# Clean up
if nosite and 'site' in sys.modules:
del sys.modules['site']
sys.path[:] = [p for p in sys.path[:]
if normpath(p) not in to_remove
]
###################################################################### ######################################################################
# Install buildout # Install buildout
......
...@@ -26,8 +26,6 @@ for d in 'eggs', 'develop-eggs', 'bin', 'parts': ...@@ -26,8 +26,6 @@ for d in 'eggs', 'develop-eggs', 'bin', 'parts':
if os.path.isdir('build'): if os.path.isdir('build'):
shutil.rmtree('build') shutil.rmtree('build')
nosite = 'site' not in sys.modules
###################################################################### ######################################################################
# Make sure we have a relatively clean environment # Make sure we have a relatively clean environment
try: try:
...@@ -37,41 +35,7 @@ except ImportError: ...@@ -37,41 +35,7 @@ except ImportError:
else: else:
raise SystemError( raise SystemError(
"Buildout development with a pre-installed setuptools or " "Buildout development with a pre-installed setuptools or "
"distribute is not supported.%s" "distribute is not supported.")
% ((not nosite) and ' Try running with -S option to Python.' or ''))
######################################################################
# handle -S
def normpath(p):
if p.endswith(os.path.sep):
return p[:-1]
else:
return p
if nosite:
# They've asked not to import site. Cool, but distribute is going to
# import it anyway, so we're going to have to clean up. :(
initial_paths = set(map(normpath, sys.path))
import site
to_remove = set(map(normpath, sys.path)) - initial_paths
else:
to_remove = ()
######################################################################
# Make sure we have a relatively clean environment
try:
import pkg_resources, setuptools
except ImportError:
pass
else:
message = (
"Buildout development with a pre-installed setuptools or "
"distribute is not supported."
)
if not nosite:
message += ' Try running with -S option to Python.'
raise SystemError(message)
###################################################################### ######################################################################
# Install distribute # Install distribute
...@@ -87,13 +51,6 @@ ez['use_setuptools'](to_dir='eggs', download_delay=0) ...@@ -87,13 +51,6 @@ ez['use_setuptools'](to_dir='eggs', download_delay=0)
import pkg_resources import pkg_resources
# Clean up
if nosite and 'site' in sys.modules:
del sys.modules['site']
sys.path[:] = [p for p in sys.path[:]
if normpath(p) not in to_remove
]
###################################################################### ######################################################################
# Install buildout # Install buildout
......
...@@ -14,11 +14,8 @@ ...@@ -14,11 +14,8 @@
"""Buildout main script """Buildout main script
""" """
# handle -S
import zc.buildout.easy_install
no_site = zc.buildout.easy_install.no_site
from zc.buildout.rmtree import rmtree from zc.buildout.rmtree import rmtree
import zc.buildout.easy_install
try: try:
from hashlib import md5 from hashlib import md5
...@@ -903,8 +900,6 @@ class Buildout(DictMixin): ...@@ -903,8 +900,6 @@ class Buildout(DictMixin):
args.insert(1, '-W') args.insert(1, '-W')
if not __debug__: if not __debug__:
args.insert(0, '-O') args.insert(0, '-O')
if no_site:
args.insert(0, '-S')
args.insert(0, zc.buildout.easy_install._safe_arg (sys.executable)) args.insert(0, zc.buildout.easy_install._safe_arg (sys.executable))
os.execv(sys.executable, args) os.execv(sys.executable, args)
...@@ -928,8 +923,6 @@ class Buildout(DictMixin): ...@@ -928,8 +923,6 @@ class Buildout(DictMixin):
args = sys.argv[:] args = sys.argv[:]
if not __debug__: if not __debug__:
args.insert(0, '-O') args.insert(0, '-O')
if no_site:
args.insert(0, '-S')
args.insert(0, sys.executable) args.insert(0, sys.executable)
sys.exit(subprocess.call(args)) sys.exit(subprocess.call(args))
...@@ -991,8 +984,6 @@ class Buildout(DictMixin): ...@@ -991,8 +984,6 @@ class Buildout(DictMixin):
__file__ = setup, __file__ = setup,
)).encode()) )).encode())
args = [sys.executable, tsetup] + args args = [sys.executable, tsetup] + args
if no_site:
args.insert(1, '-S')
zc.buildout.easy_install.call_subprocess(args) zc.buildout.easy_install.call_subprocess(args)
finally: finally:
os.close(fd) os.close(fd)
......
...@@ -18,29 +18,10 @@ It doesn't install scripts. It uses distribute and requires it to be ...@@ -18,29 +18,10 @@ It doesn't install scripts. It uses distribute and requires it to be
installed. installed.
""" """
import os
import sys
######################################################################
# handle -S
def normpath(p):
if p.endswith(os.path.sep):
return p[:-1]
else:
return p
no_site = 'site' not in sys.modules
if no_site:
initial_paths = set(map(normpath, sys.path))
import site
sys.path[:] = [p for p in sys.path if normpath(p) in initial_paths]
#
######################################################################
import distutils.errors import distutils.errors
import glob import glob
import logging import logging
import os
import pkg_resources import pkg_resources
import py_compile import py_compile
import re import re
...@@ -49,6 +30,7 @@ import setuptools.command.setopt ...@@ -49,6 +30,7 @@ import setuptools.command.setopt
import setuptools.package_index import setuptools.package_index
import shutil import shutil
import subprocess import subprocess
import sys
import tempfile import tempfile
import zc.buildout import zc.buildout
import zipimport import zipimport
...@@ -291,8 +273,6 @@ class Installer: ...@@ -291,8 +273,6 @@ class Installer:
path = distribute_loc path = distribute_loc
args = [sys.executable, '-c', _easy_install_cmd, '-mZUNxd', tmp] args = [sys.executable, '-c', _easy_install_cmd, '-mZUNxd', tmp]
if no_site:
args.insert(1, '-S')
level = logger.getEffectiveLevel() level = logger.getEffectiveLevel()
if level > 0: if level > 0:
args.append('-q') args.append('-q')
...@@ -839,9 +819,6 @@ def develop(setup, dest, ...@@ -839,9 +819,6 @@ def develop(setup, dest,
if log_level < logging.DEBUG: if log_level < logging.DEBUG:
logger.debug("in: %r\n%s", directory, ' '.join(args)) logger.debug("in: %r\n%s", directory, ' '.join(args))
if no_site:
args.insert(1, '-S')
call_subprocess(args) call_subprocess(args)
return _copyeggs(tmp3, dest, '.egg-link', undo) return _copyeggs(tmp3, dest, '.egg-link', undo)
...@@ -1019,8 +996,6 @@ def _script(module_name, attrs, path, dest, arguments, initialization, rsetup): ...@@ -1019,8 +996,6 @@ def _script(module_name, attrs, path, dest, arguments, initialization, rsetup):
dest += '-script.py' dest += '-script.py'
python = _safe_arg(sys.executable) python = _safe_arg(sys.executable)
if no_site:
python += ' -S'
contents = script_template % dict( contents = script_template % dict(
python = python, python = python,
...@@ -1043,8 +1018,6 @@ def _distutils_script(path, dest, script_content, initialization, rsetup): ...@@ -1043,8 +1018,6 @@ def _distutils_script(path, dest, script_content, initialization, rsetup):
original_content = ''.join(lines[1:]) original_content = ''.join(lines[1:])
python = _safe_arg(sys.executable) python = _safe_arg(sys.executable)
if no_site:
python += ' -S'
contents = distutils_script_template % dict( contents = distutils_script_template % dict(
python = python, python = python,
...@@ -1126,8 +1099,6 @@ def _pyscript(path, dest, rsetup): ...@@ -1126,8 +1099,6 @@ def _pyscript(path, dest, rsetup):
dest += '-script.py' dest += '-script.py'
python = _safe_arg(sys.executable) python = _safe_arg(sys.executable)
if no_site:
python += ' -S'
contents = py_script_template % dict( contents = py_script_template % dict(
python = python, python = python,
...@@ -1197,15 +1168,8 @@ import sys ...@@ -1197,15 +1168,8 @@ import sys
sys.path.insert(0, %(setupdir)r) sys.path.insert(0, %(setupdir)r)
sys.path.insert(0, %(distribute)r) sys.path.insert(0, %(distribute)r)
nosite = 'site' not in sys.modules
original_path = sys.path[:]
import os, setuptools import os, setuptools
if nosite and ('site' in sys.modules):
sys.path[:] = original_path
del sys.modules['site']
__file__ = %(__file__)r __file__ = %(__file__)r
os.chdir(%(setupdir)r) os.chdir(%(setupdir)r)
......
Isolation
=========
When developing applications, we recommended that you work with a
minimal Python environment and let buildout install needed
dependencies. If you share a Python environment with other
applications [#simple]_, you're likely to have unexpected
interactions with the other applications, through extra modules or
module version clashes.
There are a number of ways to achive isolation from other
applications:
1. Use a "clean" Python installation that doesn't contain any
non-standard modules.
2. Use a 'virtual environment
<http://pypi.python.org/pypi/virtualenv>'_ that wraps a Python
installation in a way that hides 3rd-party modules. `This is built
into Python 3.3 <http://docs.python.org/dev/library/venv.html>`_
3. Use the -S Python option when bootstrapping buildout. This will
bypass the normal execution of the Python site.py file, which is
what usually causes directories containing third-party modules to be
added to the Python path on most platforms [#macos]_.
If the -S option is used when bootstrapping buildout, then it will
be remembered by buildout and any scripts generated by buildout
will also use the -S option.
The first option works best in our opinion because, in addition to
isolating you from extra third-party libraries, it protects you from
other changes that a preexisting build might have, such as missing
standard libraries or non-standard Python build options.
This document tests the 3rd option.
First, the non-isolated case:
>>> sample_buildout = tmpdir('sample')
>>> cd(sample_buildout)
>>> import sys
>>> print_('X' +
... system("%s %s init demo" % (sys.executable, bootstrap_py)),
... end='\n===')
... # doctest: +ELLIPSIS
X...
If we look at the scripts generated, we see that the -S option is **not**
provided to the Python executable:
>>> cat('bin', 'buildout') # doctest: +ELLIPSIS
#!/usr/local/bin/python2.7
...
>>> cat('bin', 'demo') # doctest: +ELLIPSIS
#!/usr/local/bin/python2.7
...
>>> cat('bin', 'py') # doctest: +ELLIPSIS
#!/usr/local/bin/python2.7
...
The -S option is also not used when invoking setup scripts.
>>> mkdir('proj')
>>> write('proj', 'setup.py', """
... from distutils.core import setup
... import sys
... sys.stdout.write('site: %s\\n' % ('site' in sys.modules))
... setup(name='hassite')
... """)
>>> print_(system(join('bin', 'buildout')+' setup proj sdist'))
... # doctest: +ELLIPSIS
Running setup script 'proj/setup.py'.
site: True
...
>>> write('buildout.cfg', """
... [buildout]
... parts = egg
... find-links = %s
... [egg]
... recipe = zc.recipe.egg
... eggs = hassite
... """ % join('proj', 'dist'))
>>> print_(system(join('bin', 'buildout')))
... # doctest: +ELLIPSIS
Uninstalling py.
Installing egg.
Getting distribution for 'hassite'.
site: True
...
>>> write('buildout.cfg', """
... [buildout]
... parts =
... develop = proj
... """)
>>> print_(system(join('bin', 'buildout')))
... # doctest: +ELLIPSIS
Develop: '/sample/proj'
site: True
...
Now, we'll re-bootstrap with -S, to get isolation:
>>> remove('buildout.cfg')
>>> remove('eggs')
>>> print_('X' +
... system("%s -S %s init demo" % (sys.executable, bootstrap_py)),
... end='\n===')
... # doctest: +ELLIPSIS
X...
If we look at the scripts generated, se see that the -S option is
provided to the Python executable:
>>> cat('bin', 'buildout') # doctest: +ELLIPSIS
#!/usr/local/bin/python2.7 -S
...
>>> cat('bin', 'demo') # doctest: +ELLIPSIS
#!/usr/local/bin/python2.7 -S
...
>>> cat('bin', 'py') # doctest: +ELLIPSIS
#!/usr/local/bin/python2.7 -S
...
The -S option is also used when invoking setup scripts.
>>> print_(system(join('bin', 'buildout')+' setup proj sdist'))
... # doctest: +ELLIPSIS
Running setup script 'proj/setup.py'.
site: False
...
>>> write('buildout.cfg', """
... [buildout]
... parts = egg
... find-links = %s
... [egg]
... recipe = zc.recipe.egg
... eggs = hassite
... """ % join('proj', 'dist'))
>>> print_(system(join('bin', 'buildout')))
... # doctest: +ELLIPSIS
Uninstalling py.
Installing egg.
Getting distribution for 'hassite'.
site: False
...
>>> write('buildout.cfg', """
... [buildout]
... parts =
... develop = proj
... """)
>>> print_(system(join('bin', 'buildout')))
... # doctest: +ELLIPSIS
Develop: '/sample/proj'
site: False
...
.. [#simple] It's worth noting that system Python builds can make
simple applications easier to build, as hard-to-build extension
modules are already installed or can be easily installed using
system packaging tools.
.. [#macos] On Mac OS X, there are some directories containing
3rd-party libraries that are added to the Python path regardless of
whether site.py is loaded. Still, even on Mac OS X, use of the -S
option prevents some 3rd-party modules from being added to the
Python path.
...@@ -3109,11 +3109,11 @@ def test_suite(): ...@@ -3109,11 +3109,11 @@ def test_suite():
'testing_bugfix.txt'), 'testing_bugfix.txt'),
] ]
# adding bootstrap.txt and isolation.txt doctest to the suite # adding bootstrap.txt doctest to the suite
# only if bootstrap.py is present # only if bootstrap.py is present
if os.path.exists(bootstrap_py): if os.path.exists(bootstrap_py):
test_suite.append(doctest.DocFileSuite( test_suite.append(doctest.DocFileSuite(
'bootstrap.txt', 'isolation.txt', 'bootstrap.txt',
setUp=bootstrapSetup, setUp=bootstrapSetup,
tearDown=zc.buildout.testing.buildoutTearDown, tearDown=zc.buildout.testing.buildoutTearDown,
checker=renormalizing.RENormalizing([ checker=renormalizing.RENormalizing([
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment