Skip to content

Commit

Permalink
Run pip in isolated env by building zip
Browse files Browse the repository at this point in the history
  • Loading branch information
uranusjr committed Mar 5, 2021
1 parent 3ab760a commit 96c02ff
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 33 deletions.
2 changes: 2 additions & 0 deletions news/8214.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Prevent packages already-installed alongside with pip to be injected into an
isolated build environment during build-time dependency population.
109 changes: 76 additions & 33 deletions src/pip/_internal/build_env.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
"""Build Environment used for isolation during sdist building
"""

import contextlib
import logging
import os
import pathlib
import sys
import textwrap
import zipfile
from collections import OrderedDict
from sysconfig import get_paths
from types import TracebackType
from typing import TYPE_CHECKING, Iterable, List, Optional, Set, Tuple, Type
from typing import (
TYPE_CHECKING,
Iterable,
Iterator,
List,
Optional,
Set,
Tuple,
Type,
)

from pip._vendor.pkg_resources import Requirement, VersionConflict, WorkingSet

Expand Down Expand Up @@ -37,6 +49,61 @@ def __init__(self, path):
self.lib_dirs = get_prefixed_libs(path)


@contextlib.contextmanager
def _create_standalone_pip() -> Iterator[str]:
"""Create a zip file containing specified pip installation."""
source = pathlib.Path(pip_location).resolve().parent
with TempDirectory() as tmp_dir:
pip_zip = os.path.join(tmp_dir.path, "pip.zip")
with zipfile.ZipFile(pip_zip, "w") as zf:
for child in source.rglob("*"):
arcname = child.relative_to(source.parent)
zf.write(child, arcname.as_posix())
yield os.path.join(pip_zip, "pip")


def _install_requirements(
standalone_pip: str,
finder: "PackageFinder",
requirements: Iterable[str],
prefix: _Prefix,
message: str,
) -> None:
args = [
sys.executable, standalone_pip, 'install',
'--ignore-installed', '--no-user', '--prefix', prefix.path,
'--no-warn-script-location',
] # type: List[str]
if logger.getEffectiveLevel() <= logging.DEBUG:
args.append('-v')
for format_control in ('no_binary', 'only_binary'):
formats = getattr(finder.format_control, format_control)
args += [
'--' + format_control.replace('_', '-'),
','.join(sorted(formats or {':none:'}))
]
index_urls = finder.index_urls
if index_urls:
args.extend(['-i', index_urls[0]])
for extra_index in index_urls[1:]:
args.extend(['--extra-index-url', extra_index])
else:
args.append('--no-index')
for link in finder.find_links:
args.extend(['--find-links', link])

for host in finder.trusted_hosts:
args.extend(['--trusted-host', host])
if finder.allow_all_prereleases:
args.append('--pre')
if finder.prefer_binary:
args.append('--prefer-binary')
args.append('--')
args.extend(requirements)
with open_spinner(message) as spinner:
call_subprocess(args, spinner=spinner)


class BuildEnvironment:
"""Creates and manages an isolated environment to install build deps
"""
Expand Down Expand Up @@ -160,38 +227,14 @@ def install_requirements(
prefix.setup = True
if not requirements:
return
args = [
sys.executable, os.path.dirname(pip_location), 'install',
'--ignore-installed', '--no-user', '--prefix', prefix.path,
'--no-warn-script-location',
] # type: List[str]
if logger.getEffectiveLevel() <= logging.DEBUG:
args.append('-v')
for format_control in ('no_binary', 'only_binary'):
formats = getattr(finder.format_control, format_control)
args.extend(('--' + format_control.replace('_', '-'),
','.join(sorted(formats or {':none:'}))))

index_urls = finder.index_urls
if index_urls:
args.extend(['-i', index_urls[0]])
for extra_index in index_urls[1:]:
args.extend(['--extra-index-url', extra_index])
else:
args.append('--no-index')
for link in finder.find_links:
args.extend(['--find-links', link])

for host in finder.trusted_hosts:
args.extend(['--trusted-host', host])
if finder.allow_all_prereleases:
args.append('--pre')
if finder.prefer_binary:
args.append('--prefer-binary')
args.append('--')
args.extend(requirements)
with open_spinner(message) as spinner:
call_subprocess(args, spinner=spinner)
with _create_standalone_pip() as standalone_pip:
_install_requirements(
standalone_pip,
finder,
requirements,
prefix,
message,
)


class NoOpBuildEnvironment(BuildEnvironment):
Expand Down

0 comments on commit 96c02ff

Please sign in to comment.