comparison lib/python3.8/site-packages/pip/_internal/build_env.py @ 1:64071f2a4cf0 draft default tip

Deleted selected files
author guerler
date Mon, 27 Jul 2020 03:55:49 -0400
parents 9e54283cc701
children
comparison
equal deleted inserted replaced
0:9e54283cc701 1:64071f2a4cf0
1 """Build Environment used for isolation during sdist building
2 """
3
4 # The following comment should be removed at some point in the future.
5 # mypy: strict-optional=False
6 # mypy: disallow-untyped-defs=False
7
8 import logging
9 import os
10 import sys
11 import textwrap
12 from collections import OrderedDict
13 from distutils.sysconfig import get_python_lib
14 from sysconfig import get_paths
15
16 from pip._vendor.pkg_resources import Requirement, VersionConflict, WorkingSet
17
18 from pip import __file__ as pip_location
19 from pip._internal.utils.subprocess import call_subprocess
20 from pip._internal.utils.temp_dir import TempDirectory
21 from pip._internal.utils.typing import MYPY_CHECK_RUNNING
22 from pip._internal.utils.ui import open_spinner
23
24 if MYPY_CHECK_RUNNING:
25 from typing import Tuple, Set, Iterable, Optional, List
26 from pip._internal.index.package_finder import PackageFinder
27
28 logger = logging.getLogger(__name__)
29
30
31 class _Prefix:
32
33 def __init__(self, path):
34 # type: (str) -> None
35 self.path = path
36 self.setup = False
37 self.bin_dir = get_paths(
38 'nt' if os.name == 'nt' else 'posix_prefix',
39 vars={'base': path, 'platbase': path}
40 )['scripts']
41 # Note: prefer distutils' sysconfig to get the
42 # library paths so PyPy is correctly supported.
43 purelib = get_python_lib(plat_specific=False, prefix=path)
44 platlib = get_python_lib(plat_specific=True, prefix=path)
45 if purelib == platlib:
46 self.lib_dirs = [purelib]
47 else:
48 self.lib_dirs = [purelib, platlib]
49
50
51 class BuildEnvironment(object):
52 """Creates and manages an isolated environment to install build deps
53 """
54
55 def __init__(self):
56 # type: () -> None
57 self._temp_dir = TempDirectory(kind="build-env")
58
59 self._prefixes = OrderedDict((
60 (name, _Prefix(os.path.join(self._temp_dir.path, name)))
61 for name in ('normal', 'overlay')
62 ))
63
64 self._bin_dirs = [] # type: List[str]
65 self._lib_dirs = [] # type: List[str]
66 for prefix in reversed(list(self._prefixes.values())):
67 self._bin_dirs.append(prefix.bin_dir)
68 self._lib_dirs.extend(prefix.lib_dirs)
69
70 # Customize site to:
71 # - ensure .pth files are honored
72 # - prevent access to system site packages
73 system_sites = {
74 os.path.normcase(site) for site in (
75 get_python_lib(plat_specific=False),
76 get_python_lib(plat_specific=True),
77 )
78 }
79 self._site_dir = os.path.join(self._temp_dir.path, 'site')
80 if not os.path.exists(self._site_dir):
81 os.mkdir(self._site_dir)
82 with open(os.path.join(self._site_dir, 'sitecustomize.py'), 'w') as fp:
83 fp.write(textwrap.dedent(
84 '''
85 import os, site, sys
86
87 # First, drop system-sites related paths.
88 original_sys_path = sys.path[:]
89 known_paths = set()
90 for path in {system_sites!r}:
91 site.addsitedir(path, known_paths=known_paths)
92 system_paths = set(
93 os.path.normcase(path)
94 for path in sys.path[len(original_sys_path):]
95 )
96 original_sys_path = [
97 path for path in original_sys_path
98 if os.path.normcase(path) not in system_paths
99 ]
100 sys.path = original_sys_path
101
102 # Second, add lib directories.
103 # ensuring .pth file are processed.
104 for path in {lib_dirs!r}:
105 assert not path in sys.path
106 site.addsitedir(path)
107 '''
108 ).format(system_sites=system_sites, lib_dirs=self._lib_dirs))
109
110 def __enter__(self):
111 self._save_env = {
112 name: os.environ.get(name, None)
113 for name in ('PATH', 'PYTHONNOUSERSITE', 'PYTHONPATH')
114 }
115
116 path = self._bin_dirs[:]
117 old_path = self._save_env['PATH']
118 if old_path:
119 path.extend(old_path.split(os.pathsep))
120
121 pythonpath = [self._site_dir]
122
123 os.environ.update({
124 'PATH': os.pathsep.join(path),
125 'PYTHONNOUSERSITE': '1',
126 'PYTHONPATH': os.pathsep.join(pythonpath),
127 })
128
129 def __exit__(self, exc_type, exc_val, exc_tb):
130 for varname, old_value in self._save_env.items():
131 if old_value is None:
132 os.environ.pop(varname, None)
133 else:
134 os.environ[varname] = old_value
135
136 def cleanup(self):
137 # type: () -> None
138 self._temp_dir.cleanup()
139
140 def check_requirements(self, reqs):
141 # type: (Iterable[str]) -> Tuple[Set[Tuple[str, str]], Set[str]]
142 """Return 2 sets:
143 - conflicting requirements: set of (installed, wanted) reqs tuples
144 - missing requirements: set of reqs
145 """
146 missing = set()
147 conflicting = set()
148 if reqs:
149 ws = WorkingSet(self._lib_dirs)
150 for req in reqs:
151 try:
152 if ws.find(Requirement.parse(req)) is None:
153 missing.add(req)
154 except VersionConflict as e:
155 conflicting.add((str(e.args[0].as_requirement()),
156 str(e.args[1])))
157 return conflicting, missing
158
159 def install_requirements(
160 self,
161 finder, # type: PackageFinder
162 requirements, # type: Iterable[str]
163 prefix_as_string, # type: str
164 message # type: Optional[str]
165 ):
166 # type: (...) -> None
167 prefix = self._prefixes[prefix_as_string]
168 assert not prefix.setup
169 prefix.setup = True
170 if not requirements:
171 return
172 args = [
173 sys.executable, os.path.dirname(pip_location), 'install',
174 '--ignore-installed', '--no-user', '--prefix', prefix.path,
175 '--no-warn-script-location',
176 ] # type: List[str]
177 if logger.getEffectiveLevel() <= logging.DEBUG:
178 args.append('-v')
179 for format_control in ('no_binary', 'only_binary'):
180 formats = getattr(finder.format_control, format_control)
181 args.extend(('--' + format_control.replace('_', '-'),
182 ','.join(sorted(formats or {':none:'}))))
183
184 index_urls = finder.index_urls
185 if index_urls:
186 args.extend(['-i', index_urls[0]])
187 for extra_index in index_urls[1:]:
188 args.extend(['--extra-index-url', extra_index])
189 else:
190 args.append('--no-index')
191 for link in finder.find_links:
192 args.extend(['--find-links', link])
193
194 for host in finder.trusted_hosts:
195 args.extend(['--trusted-host', host])
196 if finder.allow_all_prereleases:
197 args.append('--pre')
198 args.append('--')
199 args.extend(requirements)
200 with open_spinner(message) as spinner:
201 call_subprocess(args, spinner=spinner)
202
203
204 class NoOpBuildEnvironment(BuildEnvironment):
205 """A no-op drop-in replacement for BuildEnvironment
206 """
207
208 def __init__(self):
209 pass
210
211 def __enter__(self):
212 pass
213
214 def __exit__(self, exc_type, exc_val, exc_tb):
215 pass
216
217 def cleanup(self):
218 pass
219
220 def install_requirements(self, finder, requirements, prefix, message):
221 raise NotImplementedError()