Commit 4066f7f6 authored by Xavier Thompson's avatar Xavier Thompson

[feat] Prevent pip installing setup_requires

Use a special .pydistutils.cfg in a temporary HOME directory for
the duration of the pip wheel run to prevent build dependencies
specified in a setup_requires from being installed on the fly
without respecting pinned versions.
parent 085baf94
...@@ -1737,63 +1737,81 @@ def call_pip_wheel(spec, dest, options): ...@@ -1737,63 +1737,81 @@ def call_pip_wheel(spec, dest, options):
distribution specified by `spec` into `dest`. distribution specified by `spec` into `dest`.
Returns all the paths inside `dest` created by the above. Returns all the paths inside `dest` created by the above.
""" """
args = [sys.executable, '-m', 'pip', 'wheel', '--no-deps', '-w', dest] cleanup = []
level = logger.getEffectiveLevel()
if level >= logging.INFO:
args.append('-q')
else:
args.append('-v')
# Try to prevent pip from installing build dependencies implicitly
# and without respecting pinned versions, on the fly
if not options._allow_picked_versions:
args.append('--no-index')
args.append('--no-build-isolation')
args.append(spec)
try: try:
from pip._internal.cli.cmdoptions import no_python_version_warning args = [sys.executable, '-m', 'pip', 'wheel', '--no-deps', '-w', dest]
HAS_WARNING_OPTION = True level = logger.getEffectiveLevel()
except ImportError: if level >= logging.INFO:
HAS_WARNING_OPTION = False args.append('-q')
if HAS_WARNING_OPTION:
if not hasattr(call_pip_wheel, 'displayed'):
call_pip_wheel.displayed = True
else: else:
args.append('--no-python-version-warning') args.append('-v')
env = os.environ.copy() # Prevent pip from installing build dependencies on the fly
python_path = pip_path[:] # without respecting pinned versions. This only works for
env_paths = env.get('PYTHONPATH') # PEP 517 specifications using pyproject.toml and not for
if env_paths: # dependencies in setup_requires option in legacy setup.py
python_path.append(env_paths) if not options._allow_picked_versions:
extra_env_path = env.get('PYTHONEXTRAPATH') args.append('--no-index')
if extra_env_path: args.append('--no-build-isolation')
python_path.append(extra_env_path)
env['PYTHONPATH'] = os.pathsep.join(python_path)
if level <= logging.DEBUG: args.append(spec)
logger.debug('Running pip install:\n"%s"\npath=%s\n',
'" "'.join(args), pip_path)
sys.stdout.flush() # We want any pending output first try:
from pip._internal.cli.cmdoptions import no_python_version_warning
subprocess.check_call(list(args), env=env) HAS_WARNING_OPTION = True
except ImportError:
entries = os.listdir(dest) HAS_WARNING_OPTION = False
try: if HAS_WARNING_OPTION:
assert len(entries) == 1, "Got multiple entries afer pip wheel" if not hasattr(call_pip_wheel, 'displayed'):
wheel = entries[0] call_pip_wheel.displayed = True
assert os.path.splitext(wheel)[1] == '.whl', "Expected a .whl" else:
except AssertionError: args.append('--no-python-version-warning')
logger.error(
"No .whl after successful pip wheel of %s", env = os.environ.copy()
spec) python_path = pip_path[:]
raise env_paths = env.get('PYTHONPATH')
if env_paths:
return make_egg_after_pip_wheel(dest, wheel) python_path.append(env_paths)
extra_env_path = env.get('PYTHONEXTRAPATH')
if extra_env_path:
python_path.append(extra_env_path)
env['PYTHONPATH'] = os.pathsep.join(python_path)
if level <= logging.DEBUG:
logger.debug('Running pip install:\n"%s"\npath=%s\n',
'" "'.join(args), pip_path)
sys.stdout.flush() # We want any pending output first
# Prevent setuptools from downloading and thus installing
# build dependencies specified in setup_requires option of
# legacy setup.py by providing a crafted .pydistutils.cfg.
# This is used in complement to --no-build-isolation.
if not options._allow_picked_versions:
pip_home = tempfile.mkdtemp('pip-pydistutils-home')
cleanup.append(lambda: zc.buildout.rmtree.rmtree(pip_home))
with open(os.path.join(pip_home, '.pydistutils.cfg'), 'w') as f:
f.write("[easy_install]\n"
"index_url = file:///dev/null")
env['HOME'] = pip_home
subprocess.check_call(args, env=env)
entries = os.listdir(dest)
try:
assert len(entries) == 1, "Got multiple entries afer pip wheel"
wheel = entries[0]
assert os.path.splitext(wheel)[1] == '.whl', "Expected a .whl"
except AssertionError:
logger.error(
"No .whl after successful pip wheel of %s",
spec)
raise
return make_egg_after_pip_wheel(dest, wheel)
finally:
for f in cleanup:
f()
def make_egg_after_pip_wheel(dest, wheel): def make_egg_after_pip_wheel(dest, wheel):
unpack_wheel(os.path.join(dest, wheel), dest) unpack_wheel(os.path.join(dest, wheel), dest)
......
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