Commit 8aa6480a authored by Jason R. Coombs's avatar Jason R. Coombs

Extract sandboxing context as a series of encapsulated contexts.

parent ec90f46f
...@@ -5,6 +5,7 @@ import operator ...@@ -5,6 +5,7 @@ import operator
import functools import functools
import itertools import itertools
import re import re
import contextlib
import pkg_resources import pkg_resources
...@@ -42,20 +43,95 @@ def _execfile(filename, globals, locals=None): ...@@ -42,20 +43,95 @@ def _execfile(filename, globals, locals=None):
code = compile(script, filename, 'exec') code = compile(script, filename, 'exec')
exec(code, globals, locals) exec(code, globals, locals)
@contextlib.contextmanager
def save_argv():
saved = sys.argv[:]
try:
yield saved
finally:
sys.argv[:] = saved
@contextlib.contextmanager
def save_path():
saved = sys.path[:]
try:
yield saved
finally:
sys.path[:] = saved
@contextlib.contextmanager
def override_temp(replacement):
"""
Monkey-patch tempfile.tempdir with replacement, ensuring it exists
"""
if not os.path.isdir(replacement):
os.makedirs(replacement)
saved = tempfile.tempdir
tempfile.tempdir = replacement
try:
yield
finally:
tempfile.tempdir = saved
@contextlib.contextmanager
def pushd(target):
saved = os.getcwd()
os.chdir(target)
try:
yield saved
finally:
os.chdir(saved)
@contextlib.contextmanager
def save_modules():
saved = sys.modules.copy()
try:
yield saved
finally:
sys.modules.update(saved)
# remove any modules imported since
del_modules = [
mod_name for mod_name in sys.modules
if mod_name not in saved
# exclude any encodings modules. See #285
and not mod_name.startswith('encodings.')
]
list(map(sys.modules.__delitem__, del_modules))
@contextlib.contextmanager
def save_pkg_resources_state():
saved = pkg_resources.__getstate__()
try:
yield saved
finally:
pkg_resources.__setstate__(saved)
@contextlib.contextmanager
def setup_context(setup_dir):
temp_dir = os.path.join(setup_dir, 'temp')
with save_pkg_resources_state():
with save_modules():
with save_path():
with save_argv():
with override_temp(temp_dir):
with pushd(setup_dir):
yield
def run_setup(setup_script, args): def run_setup(setup_script, args):
"""Run a distutils setup script, sandboxed in its directory""" """Run a distutils setup script, sandboxed in its directory"""
old_dir = os.getcwd()
save_argv = sys.argv[:]
save_path = sys.path[:]
setup_dir = os.path.abspath(os.path.dirname(setup_script)) setup_dir = os.path.abspath(os.path.dirname(setup_script))
temp_dir = os.path.join(setup_dir,'temp') with setup_context(setup_dir):
if not os.path.isdir(temp_dir): os.makedirs(temp_dir)
save_tmp = tempfile.tempdir
save_modules = sys.modules.copy()
pr_state = pkg_resources.__getstate__()
try:
tempfile.tempdir = temp_dir
os.chdir(setup_dir)
try: try:
sys.argv[:] = [setup_script]+list(args) sys.argv[:] = [setup_script]+list(args)
sys.path.insert(0, setup_dir) sys.path.insert(0, setup_dir)
...@@ -71,21 +147,6 @@ def run_setup(setup_script, args): ...@@ -71,21 +147,6 @@ def run_setup(setup_script, args):
if v.args and v.args[0]: if v.args and v.args[0]:
raise raise
# Normal exit, just return # Normal exit, just return
finally:
pkg_resources.__setstate__(pr_state)
sys.modules.update(save_modules)
# remove any modules imported within the sandbox
del_modules = [
mod_name for mod_name in sys.modules
if mod_name not in save_modules
# exclude any encodings modules. See #285
and not mod_name.startswith('encodings.')
]
list(map(sys.modules.__delitem__, del_modules))
os.chdir(old_dir)
sys.path[:] = save_path
sys.argv[:] = save_argv
tempfile.tempdir = save_tmp
class AbstractSandbox: class AbstractSandbox:
......
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