omdev 0.0.0.dev181__py3-none-any.whl → 0.0.0.dev183__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omdev/interp/inject.py +1 -1
- omdev/interp/pyenv/inject.py +1 -1
- omdev/interp/pyenv/install.py +251 -0
- omdev/interp/pyenv/provider.py +144 -0
- omdev/interp/pyenv/pyenv.py +0 -383
- omdev/scripts/interp.py +104 -102
- omdev/scripts/pyproject.py +225 -212
- {omdev-0.0.0.dev181.dist-info → omdev-0.0.0.dev183.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev181.dist-info → omdev-0.0.0.dev183.dist-info}/RECORD +13 -11
- {omdev-0.0.0.dev181.dist-info → omdev-0.0.0.dev183.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev181.dist-info → omdev-0.0.0.dev183.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev181.dist-info → omdev-0.0.0.dev183.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev181.dist-info → omdev-0.0.0.dev183.dist-info}/top_level.txt +0 -0
omdev/interp/pyenv/pyenv.py
CHANGED
@@ -10,32 +10,14 @@ TODO:
|
|
10
10
|
- optionally install / upgrade pyenv itself
|
11
11
|
- new vers dont need these custom mac opts, only run on old vers
|
12
12
|
"""
|
13
|
-
import abc
|
14
|
-
import dataclasses as dc
|
15
|
-
import itertools
|
16
|
-
import logging
|
17
13
|
import os.path
|
18
14
|
import shutil
|
19
|
-
import sys
|
20
15
|
import typing as ta
|
21
16
|
|
22
17
|
from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
|
23
18
|
from omlish.lite.cached import async_cached_nullary
|
24
|
-
from omlish.lite.cached import cached_nullary
|
25
19
|
from omlish.lite.check import check
|
26
20
|
|
27
|
-
from ...packaging.versions import InvalidVersion
|
28
|
-
from ...packaging.versions import Version
|
29
|
-
from ..inspect import InterpInspector
|
30
|
-
from ..providers.base import InterpProvider
|
31
|
-
from ..types import Interp
|
32
|
-
from ..types import InterpOpts
|
33
|
-
from ..types import InterpSpecifier
|
34
|
-
from ..types import InterpVersion
|
35
|
-
|
36
|
-
|
37
|
-
##
|
38
|
-
|
39
21
|
|
40
22
|
class Pyenv:
|
41
23
|
def __init__(
|
@@ -102,368 +84,3 @@ class Pyenv:
|
|
102
84
|
return False
|
103
85
|
await asyncio_subprocesses.check_call('git', 'pull', cwd=root)
|
104
86
|
return True
|
105
|
-
|
106
|
-
|
107
|
-
##
|
108
|
-
|
109
|
-
|
110
|
-
@dc.dataclass(frozen=True)
|
111
|
-
class PyenvInstallOpts:
|
112
|
-
opts: ta.Sequence[str] = ()
|
113
|
-
conf_opts: ta.Sequence[str] = ()
|
114
|
-
cflags: ta.Sequence[str] = ()
|
115
|
-
ldflags: ta.Sequence[str] = ()
|
116
|
-
env: ta.Mapping[str, str] = dc.field(default_factory=dict)
|
117
|
-
|
118
|
-
def merge(self, *others: 'PyenvInstallOpts') -> 'PyenvInstallOpts':
|
119
|
-
return PyenvInstallOpts(
|
120
|
-
opts=list(itertools.chain.from_iterable(o.opts for o in [self, *others])),
|
121
|
-
conf_opts=list(itertools.chain.from_iterable(o.conf_opts for o in [self, *others])),
|
122
|
-
cflags=list(itertools.chain.from_iterable(o.cflags for o in [self, *others])),
|
123
|
-
ldflags=list(itertools.chain.from_iterable(o.ldflags for o in [self, *others])),
|
124
|
-
env=dict(itertools.chain.from_iterable(o.env.items() for o in [self, *others])),
|
125
|
-
)
|
126
|
-
|
127
|
-
|
128
|
-
# TODO: https://github.com/pyenv/pyenv/blob/master/plugins/python-build/README.md#building-for-maximum-performance
|
129
|
-
DEFAULT_PYENV_INSTALL_OPTS = PyenvInstallOpts(
|
130
|
-
opts=[
|
131
|
-
'-s',
|
132
|
-
'-v',
|
133
|
-
'-k',
|
134
|
-
],
|
135
|
-
conf_opts=[
|
136
|
-
# FIXME: breaks on mac for older py's
|
137
|
-
'--enable-loadable-sqlite-extensions',
|
138
|
-
|
139
|
-
# '--enable-shared',
|
140
|
-
|
141
|
-
'--enable-optimizations',
|
142
|
-
'--with-lto',
|
143
|
-
|
144
|
-
# '--enable-profiling', # ?
|
145
|
-
|
146
|
-
# '--enable-ipv6', # ?
|
147
|
-
],
|
148
|
-
cflags=[
|
149
|
-
# '-march=native',
|
150
|
-
# '-mtune=native',
|
151
|
-
],
|
152
|
-
)
|
153
|
-
|
154
|
-
DEBUG_PYENV_INSTALL_OPTS = PyenvInstallOpts(opts=['-g'])
|
155
|
-
|
156
|
-
THREADED_PYENV_INSTALL_OPTS = PyenvInstallOpts(conf_opts=['--disable-gil'])
|
157
|
-
|
158
|
-
|
159
|
-
#
|
160
|
-
|
161
|
-
|
162
|
-
class PyenvInstallOptsProvider(abc.ABC):
|
163
|
-
@abc.abstractmethod
|
164
|
-
def opts(self) -> ta.Awaitable[PyenvInstallOpts]:
|
165
|
-
raise NotImplementedError
|
166
|
-
|
167
|
-
|
168
|
-
class LinuxPyenvInstallOpts(PyenvInstallOptsProvider):
|
169
|
-
async def opts(self) -> PyenvInstallOpts:
|
170
|
-
return PyenvInstallOpts()
|
171
|
-
|
172
|
-
|
173
|
-
class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
174
|
-
@cached_nullary
|
175
|
-
def framework_opts(self) -> PyenvInstallOpts:
|
176
|
-
return PyenvInstallOpts(conf_opts=['--enable-framework'])
|
177
|
-
|
178
|
-
@cached_nullary
|
179
|
-
def has_brew(self) -> bool:
|
180
|
-
return shutil.which('brew') is not None
|
181
|
-
|
182
|
-
BREW_DEPS: ta.Sequence[str] = [
|
183
|
-
'openssl',
|
184
|
-
'readline',
|
185
|
-
'sqlite3',
|
186
|
-
'zlib',
|
187
|
-
]
|
188
|
-
|
189
|
-
@async_cached_nullary
|
190
|
-
async def brew_deps_opts(self) -> PyenvInstallOpts:
|
191
|
-
cflags = []
|
192
|
-
ldflags = []
|
193
|
-
for dep in self.BREW_DEPS:
|
194
|
-
dep_prefix = await asyncio_subprocesses.check_output_str('brew', '--prefix', dep)
|
195
|
-
cflags.append(f'-I{dep_prefix}/include')
|
196
|
-
ldflags.append(f'-L{dep_prefix}/lib')
|
197
|
-
return PyenvInstallOpts(
|
198
|
-
cflags=cflags,
|
199
|
-
ldflags=ldflags,
|
200
|
-
)
|
201
|
-
|
202
|
-
@async_cached_nullary
|
203
|
-
async def brew_tcl_opts(self) -> PyenvInstallOpts:
|
204
|
-
if await asyncio_subprocesses.try_output('brew', '--prefix', 'tcl-tk') is None:
|
205
|
-
return PyenvInstallOpts()
|
206
|
-
|
207
|
-
tcl_tk_prefix = await asyncio_subprocesses.check_output_str('brew', '--prefix', 'tcl-tk')
|
208
|
-
tcl_tk_ver_str = await asyncio_subprocesses.check_output_str('brew', 'ls', '--versions', 'tcl-tk')
|
209
|
-
tcl_tk_ver = '.'.join(tcl_tk_ver_str.split()[1].split('.')[:2])
|
210
|
-
|
211
|
-
return PyenvInstallOpts(conf_opts=[
|
212
|
-
f"--with-tcltk-includes='-I{tcl_tk_prefix}/include'",
|
213
|
-
f"--with-tcltk-libs='-L{tcl_tk_prefix}/lib -ltcl{tcl_tk_ver} -ltk{tcl_tk_ver}'",
|
214
|
-
])
|
215
|
-
|
216
|
-
# @cached_nullary
|
217
|
-
# def brew_ssl_opts(self) -> PyenvInstallOpts:
|
218
|
-
# pkg_config_path = subprocess_check_output_str('brew', '--prefix', 'openssl')
|
219
|
-
# if 'PKG_CONFIG_PATH' in os.environ:
|
220
|
-
# pkg_config_path += ':' + os.environ['PKG_CONFIG_PATH']
|
221
|
-
# return PyenvInstallOpts(env={'PKG_CONFIG_PATH': pkg_config_path})
|
222
|
-
|
223
|
-
async def opts(self) -> PyenvInstallOpts:
|
224
|
-
return PyenvInstallOpts().merge(
|
225
|
-
self.framework_opts(),
|
226
|
-
await self.brew_deps_opts(),
|
227
|
-
await self.brew_tcl_opts(),
|
228
|
-
# self.brew_ssl_opts(),
|
229
|
-
)
|
230
|
-
|
231
|
-
|
232
|
-
PLATFORM_PYENV_INSTALL_OPTS: ta.Dict[str, PyenvInstallOptsProvider] = {
|
233
|
-
'darwin': DarwinPyenvInstallOpts(),
|
234
|
-
'linux': LinuxPyenvInstallOpts(),
|
235
|
-
}
|
236
|
-
|
237
|
-
|
238
|
-
##
|
239
|
-
|
240
|
-
|
241
|
-
class PyenvVersionInstaller:
|
242
|
-
"""
|
243
|
-
Messy: can install freethreaded build with a 't' suffixed version str _or_ by THREADED_PYENV_INSTALL_OPTS - need
|
244
|
-
latter to build custom interp with ft, need former to use canned / blessed interps. Muh.
|
245
|
-
"""
|
246
|
-
|
247
|
-
def __init__(
|
248
|
-
self,
|
249
|
-
version: str,
|
250
|
-
opts: ta.Optional[PyenvInstallOpts] = None,
|
251
|
-
interp_opts: InterpOpts = InterpOpts(),
|
252
|
-
*,
|
253
|
-
pyenv: Pyenv,
|
254
|
-
|
255
|
-
install_name: ta.Optional[str] = None,
|
256
|
-
no_default_opts: bool = False,
|
257
|
-
) -> None:
|
258
|
-
super().__init__()
|
259
|
-
|
260
|
-
self._version = version
|
261
|
-
self._given_opts = opts
|
262
|
-
self._interp_opts = interp_opts
|
263
|
-
self._given_install_name = install_name
|
264
|
-
|
265
|
-
self._no_default_opts = no_default_opts
|
266
|
-
self._pyenv = pyenv
|
267
|
-
|
268
|
-
@property
|
269
|
-
def version(self) -> str:
|
270
|
-
return self._version
|
271
|
-
|
272
|
-
@async_cached_nullary
|
273
|
-
async def opts(self) -> PyenvInstallOpts:
|
274
|
-
opts = self._given_opts
|
275
|
-
if self._no_default_opts:
|
276
|
-
if opts is None:
|
277
|
-
opts = PyenvInstallOpts()
|
278
|
-
else:
|
279
|
-
lst = [self._given_opts if self._given_opts is not None else DEFAULT_PYENV_INSTALL_OPTS]
|
280
|
-
if self._interp_opts.debug:
|
281
|
-
lst.append(DEBUG_PYENV_INSTALL_OPTS)
|
282
|
-
if self._interp_opts.threaded:
|
283
|
-
lst.append(THREADED_PYENV_INSTALL_OPTS)
|
284
|
-
lst.append(await PLATFORM_PYENV_INSTALL_OPTS[sys.platform].opts())
|
285
|
-
opts = PyenvInstallOpts().merge(*lst)
|
286
|
-
return opts
|
287
|
-
|
288
|
-
@cached_nullary
|
289
|
-
def install_name(self) -> str:
|
290
|
-
if self._given_install_name is not None:
|
291
|
-
return self._given_install_name
|
292
|
-
return self._version + ('-debug' if self._interp_opts.debug else '')
|
293
|
-
|
294
|
-
@async_cached_nullary
|
295
|
-
async def install_dir(self) -> str:
|
296
|
-
return str(os.path.join(check.not_none(await self._pyenv.root()), 'versions', self.install_name()))
|
297
|
-
|
298
|
-
@async_cached_nullary
|
299
|
-
async def install(self) -> str:
|
300
|
-
opts = await self.opts()
|
301
|
-
env = {**os.environ, **opts.env}
|
302
|
-
for k, l in [
|
303
|
-
('CFLAGS', opts.cflags),
|
304
|
-
('LDFLAGS', opts.ldflags),
|
305
|
-
('PYTHON_CONFIGURE_OPTS', opts.conf_opts),
|
306
|
-
]:
|
307
|
-
v = ' '.join(l)
|
308
|
-
if k in os.environ:
|
309
|
-
v += ' ' + os.environ[k]
|
310
|
-
env[k] = v
|
311
|
-
|
312
|
-
conf_args = [
|
313
|
-
*opts.opts,
|
314
|
-
self._version,
|
315
|
-
]
|
316
|
-
|
317
|
-
full_args: ta.List[str]
|
318
|
-
if self._given_install_name is not None:
|
319
|
-
full_args = [
|
320
|
-
os.path.join(check.not_none(await self._pyenv.root()), 'plugins', 'python-build', 'bin', 'python-build'), # noqa
|
321
|
-
*conf_args,
|
322
|
-
await self.install_dir(),
|
323
|
-
]
|
324
|
-
else:
|
325
|
-
full_args = [
|
326
|
-
await self._pyenv.exe(),
|
327
|
-
'install',
|
328
|
-
*conf_args,
|
329
|
-
]
|
330
|
-
|
331
|
-
await asyncio_subprocesses.check_call(
|
332
|
-
*full_args,
|
333
|
-
env=env,
|
334
|
-
)
|
335
|
-
|
336
|
-
exe = os.path.join(await self.install_dir(), 'bin', 'python')
|
337
|
-
if not os.path.isfile(exe):
|
338
|
-
raise RuntimeError(f'Interpreter not found: {exe}')
|
339
|
-
return exe
|
340
|
-
|
341
|
-
|
342
|
-
##
|
343
|
-
|
344
|
-
|
345
|
-
class PyenvInterpProvider(InterpProvider):
|
346
|
-
@dc.dataclass(frozen=True)
|
347
|
-
class Options:
|
348
|
-
inspect: bool = False
|
349
|
-
|
350
|
-
try_update: bool = False
|
351
|
-
|
352
|
-
def __init__(
|
353
|
-
self,
|
354
|
-
options: Options = Options(),
|
355
|
-
*,
|
356
|
-
pyenv: Pyenv,
|
357
|
-
inspector: InterpInspector,
|
358
|
-
log: ta.Optional[logging.Logger] = None,
|
359
|
-
) -> None:
|
360
|
-
super().__init__()
|
361
|
-
|
362
|
-
self._options = options
|
363
|
-
|
364
|
-
self._pyenv = pyenv
|
365
|
-
self._inspector = inspector
|
366
|
-
self._log = log
|
367
|
-
|
368
|
-
#
|
369
|
-
|
370
|
-
@staticmethod
|
371
|
-
def guess_version(s: str) -> ta.Optional[InterpVersion]:
|
372
|
-
def strip_sfx(s: str, sfx: str) -> ta.Tuple[str, bool]:
|
373
|
-
if s.endswith(sfx):
|
374
|
-
return s[:-len(sfx)], True
|
375
|
-
return s, False
|
376
|
-
ok = {}
|
377
|
-
s, ok['debug'] = strip_sfx(s, '-debug')
|
378
|
-
s, ok['threaded'] = strip_sfx(s, 't')
|
379
|
-
try:
|
380
|
-
v = Version(s)
|
381
|
-
except InvalidVersion:
|
382
|
-
return None
|
383
|
-
return InterpVersion(v, InterpOpts(**ok))
|
384
|
-
|
385
|
-
class Installed(ta.NamedTuple):
|
386
|
-
name: str
|
387
|
-
exe: str
|
388
|
-
version: InterpVersion
|
389
|
-
|
390
|
-
async def _make_installed(self, vn: str, ep: str) -> ta.Optional[Installed]:
|
391
|
-
iv: ta.Optional[InterpVersion]
|
392
|
-
if self._options.inspect:
|
393
|
-
try:
|
394
|
-
iv = check.not_none(await self._inspector.inspect(ep)).iv
|
395
|
-
except Exception as e: # noqa
|
396
|
-
return None
|
397
|
-
else:
|
398
|
-
iv = self.guess_version(vn)
|
399
|
-
if iv is None:
|
400
|
-
return None
|
401
|
-
return PyenvInterpProvider.Installed(
|
402
|
-
name=vn,
|
403
|
-
exe=ep,
|
404
|
-
version=iv,
|
405
|
-
)
|
406
|
-
|
407
|
-
async def installed(self) -> ta.Sequence[Installed]:
|
408
|
-
ret: ta.List[PyenvInterpProvider.Installed] = []
|
409
|
-
for vn, ep in await self._pyenv.version_exes():
|
410
|
-
if (i := await self._make_installed(vn, ep)) is None:
|
411
|
-
if self._log is not None:
|
412
|
-
self._log.debug('Invalid pyenv version: %s', vn)
|
413
|
-
continue
|
414
|
-
ret.append(i)
|
415
|
-
return ret
|
416
|
-
|
417
|
-
#
|
418
|
-
|
419
|
-
async def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
420
|
-
return [i.version for i in await self.installed()]
|
421
|
-
|
422
|
-
async def get_installed_version(self, version: InterpVersion) -> Interp:
|
423
|
-
for i in await self.installed():
|
424
|
-
if i.version == version:
|
425
|
-
return Interp(
|
426
|
-
exe=i.exe,
|
427
|
-
version=i.version,
|
428
|
-
)
|
429
|
-
raise KeyError(version)
|
430
|
-
|
431
|
-
#
|
432
|
-
|
433
|
-
async def _get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
434
|
-
lst = []
|
435
|
-
|
436
|
-
for vs in await self._pyenv.installable_versions():
|
437
|
-
if (iv := self.guess_version(vs)) is None:
|
438
|
-
continue
|
439
|
-
if iv.opts.debug:
|
440
|
-
raise Exception('Pyenv installable versions not expected to have debug suffix')
|
441
|
-
for d in [False, True]:
|
442
|
-
lst.append(dc.replace(iv, opts=dc.replace(iv.opts, debug=d)))
|
443
|
-
|
444
|
-
return lst
|
445
|
-
|
446
|
-
async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
447
|
-
lst = await self._get_installable_versions(spec)
|
448
|
-
|
449
|
-
if self._options.try_update and not any(v in spec for v in lst):
|
450
|
-
if self._pyenv.update():
|
451
|
-
lst = await self._get_installable_versions(spec)
|
452
|
-
|
453
|
-
return lst
|
454
|
-
|
455
|
-
async def install_version(self, version: InterpVersion) -> Interp:
|
456
|
-
inst_version = str(version.version)
|
457
|
-
inst_opts = version.opts
|
458
|
-
if inst_opts.threaded:
|
459
|
-
inst_version += 't'
|
460
|
-
inst_opts = dc.replace(inst_opts, threaded=False)
|
461
|
-
|
462
|
-
installer = PyenvVersionInstaller(
|
463
|
-
inst_version,
|
464
|
-
interp_opts=inst_opts,
|
465
|
-
pyenv=self._pyenv,
|
466
|
-
)
|
467
|
-
|
468
|
-
exe = await installer.install()
|
469
|
-
return Interp(exe, version)
|
omdev/scripts/interp.py
CHANGED
@@ -4262,6 +4262,88 @@ class InterpInspector:
|
|
4262
4262
|
return ret
|
4263
4263
|
|
4264
4264
|
|
4265
|
+
########################################
|
4266
|
+
# ../pyenv/pyenv.py
|
4267
|
+
"""
|
4268
|
+
TODO:
|
4269
|
+
- custom tags
|
4270
|
+
- 'aliases'
|
4271
|
+
- https://github.com/pyenv/pyenv/pull/2966
|
4272
|
+
- https://github.com/pyenv/pyenv/issues/218 (lol)
|
4273
|
+
- probably need custom (temp?) definition file
|
4274
|
+
- *or* python-build directly just into the versions dir?
|
4275
|
+
- optionally install / upgrade pyenv itself
|
4276
|
+
- new vers dont need these custom mac opts, only run on old vers
|
4277
|
+
"""
|
4278
|
+
|
4279
|
+
|
4280
|
+
class Pyenv:
|
4281
|
+
def __init__(
|
4282
|
+
self,
|
4283
|
+
*,
|
4284
|
+
root: ta.Optional[str] = None,
|
4285
|
+
) -> None:
|
4286
|
+
if root is not None and not (isinstance(root, str) and root):
|
4287
|
+
raise ValueError(f'pyenv_root: {root!r}')
|
4288
|
+
|
4289
|
+
super().__init__()
|
4290
|
+
|
4291
|
+
self._root_kw = root
|
4292
|
+
|
4293
|
+
@async_cached_nullary
|
4294
|
+
async def root(self) -> ta.Optional[str]:
|
4295
|
+
if self._root_kw is not None:
|
4296
|
+
return self._root_kw
|
4297
|
+
|
4298
|
+
if shutil.which('pyenv'):
|
4299
|
+
return await asyncio_subprocesses.check_output_str('pyenv', 'root')
|
4300
|
+
|
4301
|
+
d = os.path.expanduser('~/.pyenv')
|
4302
|
+
if os.path.isdir(d) and os.path.isfile(os.path.join(d, 'bin', 'pyenv')):
|
4303
|
+
return d
|
4304
|
+
|
4305
|
+
return None
|
4306
|
+
|
4307
|
+
@async_cached_nullary
|
4308
|
+
async def exe(self) -> str:
|
4309
|
+
return os.path.join(check.not_none(await self.root()), 'bin', 'pyenv')
|
4310
|
+
|
4311
|
+
async def version_exes(self) -> ta.List[ta.Tuple[str, str]]:
|
4312
|
+
if (root := await self.root()) is None:
|
4313
|
+
return []
|
4314
|
+
ret = []
|
4315
|
+
vp = os.path.join(root, 'versions')
|
4316
|
+
if os.path.isdir(vp):
|
4317
|
+
for dn in os.listdir(vp):
|
4318
|
+
ep = os.path.join(vp, dn, 'bin', 'python')
|
4319
|
+
if not os.path.isfile(ep):
|
4320
|
+
continue
|
4321
|
+
ret.append((dn, ep))
|
4322
|
+
return ret
|
4323
|
+
|
4324
|
+
async def installable_versions(self) -> ta.List[str]:
|
4325
|
+
if await self.root() is None:
|
4326
|
+
return []
|
4327
|
+
ret = []
|
4328
|
+
s = await asyncio_subprocesses.check_output_str(await self.exe(), 'install', '--list')
|
4329
|
+
for l in s.splitlines():
|
4330
|
+
if not l.startswith(' '):
|
4331
|
+
continue
|
4332
|
+
l = l.strip()
|
4333
|
+
if not l:
|
4334
|
+
continue
|
4335
|
+
ret.append(l)
|
4336
|
+
return ret
|
4337
|
+
|
4338
|
+
async def update(self) -> bool:
|
4339
|
+
if (root := await self.root()) is None:
|
4340
|
+
return False
|
4341
|
+
if not os.path.isdir(os.path.join(root, '.git')):
|
4342
|
+
return False
|
4343
|
+
await asyncio_subprocesses.check_call('git', 'pull', cwd=root)
|
4344
|
+
return True
|
4345
|
+
|
4346
|
+
|
4265
4347
|
########################################
|
4266
4348
|
# ../resolvers.py
|
4267
4349
|
|
@@ -4500,88 +4582,7 @@ class SystemInterpProvider(InterpProvider):
|
|
4500
4582
|
|
4501
4583
|
|
4502
4584
|
########################################
|
4503
|
-
# ../pyenv/
|
4504
|
-
"""
|
4505
|
-
TODO:
|
4506
|
-
- custom tags
|
4507
|
-
- 'aliases'
|
4508
|
-
- https://github.com/pyenv/pyenv/pull/2966
|
4509
|
-
- https://github.com/pyenv/pyenv/issues/218 (lol)
|
4510
|
-
- probably need custom (temp?) definition file
|
4511
|
-
- *or* python-build directly just into the versions dir?
|
4512
|
-
- optionally install / upgrade pyenv itself
|
4513
|
-
- new vers dont need these custom mac opts, only run on old vers
|
4514
|
-
"""
|
4515
|
-
|
4516
|
-
|
4517
|
-
##
|
4518
|
-
|
4519
|
-
|
4520
|
-
class Pyenv:
|
4521
|
-
def __init__(
|
4522
|
-
self,
|
4523
|
-
*,
|
4524
|
-
root: ta.Optional[str] = None,
|
4525
|
-
) -> None:
|
4526
|
-
if root is not None and not (isinstance(root, str) and root):
|
4527
|
-
raise ValueError(f'pyenv_root: {root!r}')
|
4528
|
-
|
4529
|
-
super().__init__()
|
4530
|
-
|
4531
|
-
self._root_kw = root
|
4532
|
-
|
4533
|
-
@async_cached_nullary
|
4534
|
-
async def root(self) -> ta.Optional[str]:
|
4535
|
-
if self._root_kw is not None:
|
4536
|
-
return self._root_kw
|
4537
|
-
|
4538
|
-
if shutil.which('pyenv'):
|
4539
|
-
return await asyncio_subprocesses.check_output_str('pyenv', 'root')
|
4540
|
-
|
4541
|
-
d = os.path.expanduser('~/.pyenv')
|
4542
|
-
if os.path.isdir(d) and os.path.isfile(os.path.join(d, 'bin', 'pyenv')):
|
4543
|
-
return d
|
4544
|
-
|
4545
|
-
return None
|
4546
|
-
|
4547
|
-
@async_cached_nullary
|
4548
|
-
async def exe(self) -> str:
|
4549
|
-
return os.path.join(check.not_none(await self.root()), 'bin', 'pyenv')
|
4550
|
-
|
4551
|
-
async def version_exes(self) -> ta.List[ta.Tuple[str, str]]:
|
4552
|
-
if (root := await self.root()) is None:
|
4553
|
-
return []
|
4554
|
-
ret = []
|
4555
|
-
vp = os.path.join(root, 'versions')
|
4556
|
-
if os.path.isdir(vp):
|
4557
|
-
for dn in os.listdir(vp):
|
4558
|
-
ep = os.path.join(vp, dn, 'bin', 'python')
|
4559
|
-
if not os.path.isfile(ep):
|
4560
|
-
continue
|
4561
|
-
ret.append((dn, ep))
|
4562
|
-
return ret
|
4563
|
-
|
4564
|
-
async def installable_versions(self) -> ta.List[str]:
|
4565
|
-
if await self.root() is None:
|
4566
|
-
return []
|
4567
|
-
ret = []
|
4568
|
-
s = await asyncio_subprocesses.check_output_str(await self.exe(), 'install', '--list')
|
4569
|
-
for l in s.splitlines():
|
4570
|
-
if not l.startswith(' '):
|
4571
|
-
continue
|
4572
|
-
l = l.strip()
|
4573
|
-
if not l:
|
4574
|
-
continue
|
4575
|
-
ret.append(l)
|
4576
|
-
return ret
|
4577
|
-
|
4578
|
-
async def update(self) -> bool:
|
4579
|
-
if (root := await self.root()) is None:
|
4580
|
-
return False
|
4581
|
-
if not os.path.isdir(os.path.join(root, '.git')):
|
4582
|
-
return False
|
4583
|
-
await asyncio_subprocesses.check_call('git', 'pull', cwd=root)
|
4584
|
-
return True
|
4585
|
+
# ../pyenv/install.py
|
4585
4586
|
|
4586
4587
|
|
4587
4588
|
##
|
@@ -4819,7 +4820,27 @@ class PyenvVersionInstaller:
|
|
4819
4820
|
return exe
|
4820
4821
|
|
4821
4822
|
|
4822
|
-
|
4823
|
+
########################################
|
4824
|
+
# ../providers/inject.py
|
4825
|
+
|
4826
|
+
|
4827
|
+
def bind_interp_providers() -> InjectorBindings:
|
4828
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
4829
|
+
inj.bind_array(InterpProvider),
|
4830
|
+
inj.bind_array_type(InterpProvider, InterpProviders),
|
4831
|
+
|
4832
|
+
inj.bind(RunningInterpProvider, singleton=True),
|
4833
|
+
inj.bind(InterpProvider, to_key=RunningInterpProvider, array=True),
|
4834
|
+
|
4835
|
+
inj.bind(SystemInterpProvider, singleton=True),
|
4836
|
+
inj.bind(InterpProvider, to_key=SystemInterpProvider, array=True),
|
4837
|
+
]
|
4838
|
+
|
4839
|
+
return inj.as_bindings(*lst)
|
4840
|
+
|
4841
|
+
|
4842
|
+
########################################
|
4843
|
+
# ../pyenv/provider.py
|
4823
4844
|
|
4824
4845
|
|
4825
4846
|
class PyenvInterpProvider(InterpProvider):
|
@@ -4949,25 +4970,6 @@ class PyenvInterpProvider(InterpProvider):
|
|
4949
4970
|
return Interp(exe, version)
|
4950
4971
|
|
4951
4972
|
|
4952
|
-
########################################
|
4953
|
-
# ../providers/inject.py
|
4954
|
-
|
4955
|
-
|
4956
|
-
def bind_interp_providers() -> InjectorBindings:
|
4957
|
-
lst: ta.List[InjectorBindingOrBindings] = [
|
4958
|
-
inj.bind_array(InterpProvider),
|
4959
|
-
inj.bind_array_type(InterpProvider, InterpProviders),
|
4960
|
-
|
4961
|
-
inj.bind(RunningInterpProvider, singleton=True),
|
4962
|
-
inj.bind(InterpProvider, to_key=RunningInterpProvider, array=True),
|
4963
|
-
|
4964
|
-
inj.bind(SystemInterpProvider, singleton=True),
|
4965
|
-
inj.bind(InterpProvider, to_key=SystemInterpProvider, array=True),
|
4966
|
-
]
|
4967
|
-
|
4968
|
-
return inj.as_bindings(*lst)
|
4969
|
-
|
4970
|
-
|
4971
4973
|
########################################
|
4972
4974
|
# ../pyenv/inject.py
|
4973
4975
|
|