mirror of https://github.com/ansible/ansible.git
Add a --venv option to ansible-test. (#61422)
* Add --venv delegation to ansible-test. * Update import sanity test venv creation. * Fix import test when using --venv on Python 2.x. * Improve virtualenv setup overhead. * Hide pip noise for import sanity test. * Raise verbosity on venv info messages. * Get rid of base branch noise for collections. * Add missing --requirements check.pull/61476/head
parent
8ebed4002f
commit
830f995ed4
@ -0,0 +1,154 @@
|
||||
"""Virtual environment management."""
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import os
|
||||
|
||||
from . import types as t
|
||||
|
||||
from .config import (
|
||||
EnvironmentConfig,
|
||||
)
|
||||
|
||||
from .util import (
|
||||
find_python,
|
||||
SubprocessError,
|
||||
get_available_python_versions,
|
||||
SUPPORTED_PYTHON_VERSIONS,
|
||||
display,
|
||||
)
|
||||
|
||||
from .util_common import (
|
||||
run_command,
|
||||
)
|
||||
|
||||
|
||||
def create_virtual_environment(args, # type: EnvironmentConfig
|
||||
version, # type: str
|
||||
path, # type: str
|
||||
system_site_packages=False, # type: bool
|
||||
pip=True, # type: bool
|
||||
): # type: (...) -> bool
|
||||
"""Create a virtual environment using venv or virtualenv for the requested Python version."""
|
||||
if os.path.isdir(path):
|
||||
display.info('Using existing Python %s virtual environment: %s' % (version, path), verbosity=1)
|
||||
return True
|
||||
|
||||
python = find_python(version, required=False)
|
||||
python_version = tuple(int(v) for v in version.split('.'))
|
||||
|
||||
if not python:
|
||||
# the requested python version could not be found
|
||||
return False
|
||||
|
||||
if python_version >= (3, 0):
|
||||
# use the built-in 'venv' module on Python 3.x
|
||||
if run_venv(args, python, system_site_packages, pip, path):
|
||||
display.info('Created Python %s virtual environment using "venv": %s' % (version, path), verbosity=1)
|
||||
return True
|
||||
|
||||
# something went wrong, this shouldn't happen
|
||||
return False
|
||||
|
||||
# use the installed 'virtualenv' module on the Python requested version
|
||||
if run_virtualenv(args, python, python, system_site_packages, pip, path):
|
||||
display.info('Created Python %s virtual environment using "virtualenv": %s' % (version, path), verbosity=1)
|
||||
return True
|
||||
|
||||
available_pythons = get_available_python_versions(SUPPORTED_PYTHON_VERSIONS)
|
||||
|
||||
for available_python_version, available_python_interpreter in sorted(available_pythons.items()):
|
||||
virtualenv_version = get_virtualenv_version(args, available_python_interpreter)
|
||||
|
||||
if not virtualenv_version:
|
||||
# virtualenv not available for this Python or we were unable to detect the version
|
||||
continue
|
||||
|
||||
if python_version == (2, 6) and virtualenv_version >= (16, 0, 0):
|
||||
# virtualenv 16.0.0 dropped python 2.6 support: https://virtualenv.pypa.io/en/latest/changes/#v16-0-0-2018-05-16
|
||||
continue
|
||||
|
||||
# try using 'virtualenv' from another Python to setup the desired version
|
||||
if run_virtualenv(args, available_python_interpreter, python, system_site_packages, pip, path):
|
||||
display.info('Created Python %s virtual environment using "virtualenv" on Python %s: %s' % (version, available_python_version, path), verbosity=1)
|
||||
return True
|
||||
|
||||
# no suitable 'virtualenv' available
|
||||
return False
|
||||
|
||||
|
||||
def run_venv(args, # type: EnvironmentConfig
|
||||
run_python, # type: str
|
||||
system_site_packages, # type: bool
|
||||
pip, # type: bool
|
||||
path, # type: str
|
||||
): # type: (...) -> bool
|
||||
"""Create a virtual environment using the 'venv' module. Not available on Python 2.x."""
|
||||
cmd = [run_python, '-m', 'venv']
|
||||
|
||||
if system_site_packages:
|
||||
cmd.append('--system-site-packages')
|
||||
|
||||
if not pip:
|
||||
cmd.append('--without-pip')
|
||||
|
||||
cmd.append(path)
|
||||
|
||||
try:
|
||||
run_command(args, cmd, capture=True)
|
||||
except SubprocessError:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def run_virtualenv(args, # type: EnvironmentConfig
|
||||
run_python, # type: str
|
||||
env_python, # type: str
|
||||
system_site_packages, # type: bool
|
||||
pip, # type: bool
|
||||
path, # type: str
|
||||
): # type: (...) -> bool
|
||||
"""Create a virtual environment using the 'virtualenv' module."""
|
||||
cmd = [run_python, '-m', 'virtualenv', '--python', env_python]
|
||||
|
||||
if system_site_packages:
|
||||
cmd.append('--system-site-packages')
|
||||
|
||||
if not pip:
|
||||
cmd.append('--no-pip')
|
||||
|
||||
cmd.append(path)
|
||||
|
||||
try:
|
||||
run_command(args, cmd, capture=True)
|
||||
except SubprocessError:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def get_virtualenv_version(args, python): # type: (EnvironmentConfig, str) -> t.Optional[t.Tuple[int, ...]]
|
||||
"""Get the virtualenv version for the given python intepreter, if available."""
|
||||
try:
|
||||
return get_virtualenv_version.result
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
get_virtualenv_version.result = None
|
||||
|
||||
cmd = [python, '-m', 'virtualenv', '--version']
|
||||
|
||||
try:
|
||||
stdout = run_command(args, cmd, capture=True)[0]
|
||||
except SubprocessError:
|
||||
stdout = ''
|
||||
|
||||
if stdout:
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
get_virtualenv_version.result = tuple(int(v) for v in stdout.strip().split('.'))
|
||||
except Exception: # pylint: disable=broad-except
|
||||
pass
|
||||
|
||||
return get_virtualenv_version.result
|
Loading…
Reference in New Issue