pyenv and asdf installers

This commit is contained in:
James Stidard
2019-11-09 13:54:52 +00:00
committed by Tzu-ping Chung
parent 181c9648a0
commit 232e076e26
3 changed files with 94 additions and 34 deletions
+24 -16
View File
@@ -24,9 +24,9 @@ from ._compat import decode_for_output, fix_utf8
from .cmdparse import Script
from .environments import (
PIP_EXISTS_ACTION, PIPENV_CACHE_DIR, PIPENV_COLORBLIND,
PIPENV_DEFAULT_PYTHON_VERSION, PIPENV_DONT_USE_PYENV, PIPENV_HIDE_EMOJIS,
PIPENV_MAX_SUBPROCESS, PIPENV_PYUP_API_KEY, PIPENV_RESOLVE_VCS,
PIPENV_SHELL_FANCY, PIPENV_SKIP_VALIDATION, PIPENV_YES,
PIPENV_DEFAULT_PYTHON_VERSION, PIPENV_DONT_USE_PYENV, PIPENV_DONT_USE_ASDF,
PIPENV_HIDE_EMOJIS, PIPENV_MAX_SUBPROCESS, PIPENV_PYUP_API_KEY,
PIPENV_RESOLVE_VCS, PIPENV_SHELL_FANCY, PIPENV_SKIP_VALIDATION, PIPENV_YES,
SESSION_IS_INTERACTIVE, is_type_checking
)
from .patched import crayons
@@ -392,28 +392,36 @@ def ensure_python(three=None, python=None):
),
err=True,
)
# Pyenv is installed
from .vendor.pythonfinder.environment import PYENV_INSTALLED
# check for python installers
from .vendor.pythonfinder.environment import PYENV_INSTALLED, ASDF_INSTALLED
from .installers import Pyenv, Asdf, InstallerError
if not PYENV_INSTALLED:
# prefer pyenv if both pyenv and asdf are installed as it's
# dedicated to python installs so probably the preferred
# method of the user for new python installs.
if PYENV_INSTALLED and not PIPENV_DONT_USE_PYENV:
installer = Pyenv("pyenv")
elif ASDF_INSTALLED and not PIPENV_DONT_USE_ASDF:
installer = Asdf("asdf")
else:
installer = None
if not installer:
abort()
else:
if (not PIPENV_DONT_USE_PYENV) and (SESSION_IS_INTERACTIVE or PIPENV_YES):
from .pyenv import Runner, PyenvError
pyenv = Runner("pyenv")
if SESSION_IS_INTERACTIVE or PIPENV_YES:
try:
version = pyenv.find_version_to_install(python)
version = installer.find_version_to_install(python)
except ValueError:
abort()
except PyenvError as e:
except InstallerError as e:
click.echo(fix_utf8("Something went wrong…"))
click.echo(crayons.blue(e.err), err=True)
abort()
s = "{0} {1} {2}".format(
"Would you like us to install",
crayons.green("CPython {0}".format(version)),
"with pyenv?",
"with {0}?".format(installer),
)
# Prompt the user to continue…
if not (PIPENV_YES or click.confirm(s, default=True)):
@@ -424,15 +432,15 @@ def ensure_python(three=None, python=None):
u"{0} {1} {2} {3}{4}".format(
crayons.normal(u"Installing", bold=True),
crayons.green(u"CPython {0}".format(version), bold=True),
crayons.normal(u"with pyenv", bold=True),
crayons.normal(u"with {}".format(installer), bold=True),
crayons.normal(u"(this may take a few minutes)"),
crayons.normal(fix_utf8(""), bold=True),
)
)
with create_spinner("Installing python...") as sp:
try:
c = pyenv.install(version)
except PyenvError as e:
c = installer.install(version)
except InstallerError as e:
sp.fail(environments.PIPENV_SPINNER_FAIL_TEXT.format(
"Failed...")
)
+6
View File
@@ -68,6 +68,12 @@ PIPENV_DONT_USE_PYENV = bool(os.environ.get("PIPENV_DONT_USE_PYENV"))
Default is to install Python automatically via pyenv when needed, if possible.
"""
PIPENV_DONT_USE_ASDF = bool(os.environ.get("PIPENV_DONT_USE_ASDF"))
"""If set, Pipenv does not attempt to install Python with asdf.
Default is to install Python automatically via asdf when needed, if possible.
"""
PIPENV_DOTENV_LOCATION = os.environ.get("PIPENV_DOTENV_LOCATION")
"""If set, Pipenv loads the ``.env`` file at the specified location.
+64 -18
View File
@@ -48,19 +48,22 @@ class Version(object):
return (self.major, self.minor) == (other.major, other.minor)
class PyenvError(RuntimeError):
class InstallerError(RuntimeError):
def __init__(self, desc, c):
super(PyenvError, self).__init__(desc)
super(InstallerError, self).__init__(desc)
self.out = c.out
self.err = c.err
class Runner(object):
class Installer(object):
def __init__(self, pyenv):
self._cmd = pyenv
def __init__(self, cmd):
self._cmd = cmd
def _pyenv(self, *args, **kwargs):
def __str__(self):
return self._cmd
def _run(self, *args, **kwargs):
timeout = kwargs.pop('timeout', delegator.TIMEOUT)
if kwargs:
k = list(kwargs.keys())[0]
@@ -69,21 +72,16 @@ class Runner(object):
c = delegator.run(args, block=False, timeout=timeout)
c.block()
if c.return_code != 0:
raise PyenvError('faild to run {0}'.format(args), c)
raise InstallerError('faild to run {0}'.format(args), c)
return c
def iter_installable_versions(self):
"""Iterate through CPython versions available for Pipenv to install.
"""
for name in self._pyenv('install', '--list').out.splitlines():
try:
version = Version.parse(name.strip())
except ValueError:
continue
yield version
raise NotImplementedError
def find_version_to_install(self, name):
"""Find a version in pyenv from the version supplied.
"""Find a version in the installer from the version supplied.
A ValueError is raised if a matching version cannot be found.
"""
@@ -103,16 +101,64 @@ class Runner(object):
return best_match
def install(self, version):
"""Install the given version with pyenv.
"""Install the given version with runner implementation.
The version must be a ``Version`` instance representing a version
found in pyenv.
found in the Installer.
A ValueError is raised if the given version does not have a match in
pyenv. A PyenvError is raised if the pyenv command fails.
the runner. A InstallerError is raised if the runner command fails.
"""
c = self._pyenv(
raise NotImplementedError
class Pyenv(Installer):
def iter_installable_versions(self):
"""Iterate through CPython versions available for Pipenv to install.
"""
for name in self._run('install', '--list').out.splitlines():
try:
version = Version.parse(name.strip())
except ValueError:
continue
yield version
def install(self, version):
"""Install the given version with pyenv.
The version must be a ``Version`` instance representing a version
found in pyenv.
A ValueError is raised if the given version does not have a match in
pyenv. A InstallerError is raised if the pyenv command fails.
"""
c = self._run(
'install', '-s', str(version),
timeout=PIPENV_INSTALL_TIMEOUT,
)
return c
class Asdf(Installer):
def iter_installable_versions(self):
"""Iterate through CPython versions available for asdf to install.
"""
for name in self._run('list-all', 'python').out.splitlines():
try:
version = Version.parse(name.strip())
except ValueError:
continue
yield version
def install(self, version):
"""Install the given version with asdf.
The version must be a ``Version`` instance representing a version
found in asdf.
A ValueError is raised if the given version does not have a match in
asdf. A InstallerError is raised if the asdf command fails.
"""
c = self._run(
'install', 'python', str(version),
timeout=PIPENV_INSTALL_TIMEOUT,
)
return c