comparison planemo/lib/python3.7/site-packages/pip/_internal/build_env.py @ 1:56ad4e20f292 draft

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