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",
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
......@@ -102,13 +83,6 @@ except ImportError:
if path not in pkg_resources.working_set.entries:
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
......
......@@ -26,8 +26,6 @@ for d in 'eggs', 'develop-eggs', 'bin', 'parts':
if os.path.isdir('build'):
shutil.rmtree('build')
nosite = 'site' not in sys.modules
######################################################################
# Make sure we have a relatively clean environment
try:
......@@ -37,41 +35,7 @@ except ImportError:
else:
raise SystemError(
"Buildout development with a pre-installed setuptools or "
"distribute is not supported.%s"
% ((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)
"distribute is not supported.")
######################################################################
# Install distribute
......@@ -87,13 +51,6 @@ ez['use_setuptools'](to_dir='eggs', download_delay=0)
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
......
......@@ -14,11 +14,8 @@
"""Buildout main script
"""
# handle -S
import zc.buildout.easy_install
no_site = zc.buildout.easy_install.no_site
from zc.buildout.rmtree import rmtree
import zc.buildout.easy_install
try:
from hashlib import md5
......@@ -903,8 +900,6 @@ class Buildout(DictMixin):
args.insert(1, '-W')
if not __debug__:
args.insert(0, '-O')
if no_site:
args.insert(0, '-S')
args.insert(0, zc.buildout.easy_install._safe_arg (sys.executable))
os.execv(sys.executable, args)
......@@ -928,8 +923,6 @@ class Buildout(DictMixin):
args = sys.argv[:]
if not __debug__:
args.insert(0, '-O')
if no_site:
args.insert(0, '-S')
args.insert(0, sys.executable)
sys.exit(subprocess.call(args))
......@@ -991,8 +984,6 @@ class Buildout(DictMixin):
__file__ = setup,
)).encode())
args = [sys.executable, tsetup] + args
if no_site:
args.insert(1, '-S')
zc.buildout.easy_install.call_subprocess(args)
finally:
os.close(fd)
......
......@@ -18,29 +18,10 @@ It doesn't install scripts. It uses distribute and requires it to be
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 glob
import logging
import os
import pkg_resources
import py_compile
import re
......@@ -49,6 +30,7 @@ import setuptools.command.setopt
import setuptools.package_index
import shutil
import subprocess
import sys
import tempfile
import zc.buildout
import zipimport
......@@ -291,8 +273,6 @@ class Installer:
path = distribute_loc
args = [sys.executable, '-c', _easy_install_cmd, '-mZUNxd', tmp]
if no_site:
args.insert(1, '-S')
level = logger.getEffectiveLevel()
if level > 0:
args.append('-q')
......@@ -839,9 +819,6 @@ def develop(setup, dest,
if log_level < logging.DEBUG:
logger.debug("in: %r\n%s", directory, ' '.join(args))
if no_site:
args.insert(1, '-S')
call_subprocess(args)
return _copyeggs(tmp3, dest, '.egg-link', undo)
......@@ -1019,8 +996,6 @@ def _script(module_name, attrs, path, dest, arguments, initialization, rsetup):
dest += '-script.py'
python = _safe_arg(sys.executable)
if no_site:
python += ' -S'
contents = script_template % dict(
python = python,
......@@ -1043,8 +1018,6 @@ def _distutils_script(path, dest, script_content, initialization, rsetup):
original_content = ''.join(lines[1:])
python = _safe_arg(sys.executable)
if no_site:
python += ' -S'
contents = distutils_script_template % dict(
python = python,
......@@ -1126,8 +1099,6 @@ def _pyscript(path, dest, rsetup):
dest += '-script.py'
python = _safe_arg(sys.executable)
if no_site:
python += ' -S'
contents = py_script_template % dict(
python = python,
......@@ -1197,15 +1168,8 @@ import sys
sys.path.insert(0, %(setupdir)r)
sys.path.insert(0, %(distribute)r)
nosite = 'site' not in sys.modules
original_path = sys.path[:]
import os, setuptools
if nosite and ('site' in sys.modules):
sys.path[:] = original_path
del sys.modules['site']
__file__ = %(__file__)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():
'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
if os.path.exists(bootstrap_py):
test_suite.append(doctest.DocFileSuite(
'bootstrap.txt', 'isolation.txt',
'bootstrap.txt',
setUp=bootstrapSetup,
tearDown=zc.buildout.testing.buildoutTearDown,
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