|
|
|
|
@ -4,6 +4,7 @@ __metaclass__ = type
|
|
|
|
|
|
|
|
|
|
import json
|
|
|
|
|
import os
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
from . import types as t
|
|
|
|
|
|
|
|
|
|
@ -46,9 +47,13 @@ def create_virtual_environment(args, # type: EnvironmentConfig
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
# creating a virtual environment using 'venv' when running in a virtual environment created by 'virtualenv' results
|
|
|
|
|
# in a copy of the original virtual environment instead of creation of a new one
|
|
|
|
|
# avoid this issue by only using "real" python interpreters to invoke 'venv'
|
|
|
|
|
for real_python in iterate_real_pythons(args, version):
|
|
|
|
|
if run_venv(args, real_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, most likely the package maintainer for the Python installation removed ensurepip
|
|
|
|
|
# which will prevent creation of a virtual environment without installation of other OS packages
|
|
|
|
|
@ -80,6 +85,56 @@ def create_virtual_environment(args, # type: EnvironmentConfig
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def iterate_real_pythons(args, version): # type: (EnvironmentConfig, str) -> t.Iterable[str]
|
|
|
|
|
"""
|
|
|
|
|
Iterate through available real python interpreters of the requested version.
|
|
|
|
|
The current interpreter will be checked and then the path will be searched.
|
|
|
|
|
"""
|
|
|
|
|
version_info = tuple(int(n) for n in version.split('.'))
|
|
|
|
|
current_python = None
|
|
|
|
|
|
|
|
|
|
if version_info == sys.version_info[:len(version_info)]:
|
|
|
|
|
current_python = sys.executable
|
|
|
|
|
real_prefix = get_python_real_prefix(args, current_python)
|
|
|
|
|
|
|
|
|
|
if real_prefix:
|
|
|
|
|
current_python = find_python(version, os.path.join(real_prefix, 'bin'))
|
|
|
|
|
|
|
|
|
|
if current_python:
|
|
|
|
|
yield current_python
|
|
|
|
|
|
|
|
|
|
path = os.environ.get('PATH', os.path.defpath)
|
|
|
|
|
|
|
|
|
|
if not path:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
found_python = find_python(version, path)
|
|
|
|
|
|
|
|
|
|
if not found_python:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if found_python == current_python:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
real_prefix = get_python_real_prefix(args, found_python)
|
|
|
|
|
|
|
|
|
|
if real_prefix:
|
|
|
|
|
found_python = find_python(version, os.path.join(real_prefix, 'bin'))
|
|
|
|
|
|
|
|
|
|
if found_python:
|
|
|
|
|
yield found_python
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_python_real_prefix(args, path): # type: (EnvironmentConfig, str) -> t.Optional[str]
|
|
|
|
|
"""
|
|
|
|
|
Return the real prefix of the specified interpreter or None if the interpreter is not a virtual environment created by 'virtualenv'.
|
|
|
|
|
"""
|
|
|
|
|
cmd = [path, os.path.join(os.path.join(ANSIBLE_TEST_DATA_ROOT, 'virtualenvcheck.py'))]
|
|
|
|
|
check_result = json.loads(run_command(args, cmd, capture=True, always=True)[0])
|
|
|
|
|
real_prefix = check_result['real_prefix']
|
|
|
|
|
return real_prefix
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def run_venv(args, # type: EnvironmentConfig
|
|
|
|
|
run_python, # type: str
|
|
|
|
|
system_site_packages, # type: bool
|
|
|
|
|
@ -87,15 +142,6 @@ def run_venv(args, # type: EnvironmentConfig
|
|
|
|
|
path, # type: str
|
|
|
|
|
): # type: (...) -> bool
|
|
|
|
|
"""Create a virtual environment using the 'venv' module. Not available on Python 2.x."""
|
|
|
|
|
cmd = [run_python, os.path.join(os.path.join(ANSIBLE_TEST_DATA_ROOT, 'virtualenvcheck.py'))]
|
|
|
|
|
check_result = json.loads(run_command(args, cmd, capture=True, always=True)[0])
|
|
|
|
|
real_prefix = check_result['real_prefix']
|
|
|
|
|
|
|
|
|
|
if real_prefix:
|
|
|
|
|
# we must use the real python to create a virtual environment with venv
|
|
|
|
|
# attempting to use python from a virtualenv created virtual environment results in a copy of that environment instead
|
|
|
|
|
run_python = os.path.join(real_prefix, 'bin', 'python')
|
|
|
|
|
|
|
|
|
|
cmd = [run_python, '-m', 'venv']
|
|
|
|
|
|
|
|
|
|
if system_site_packages:
|
|
|
|
|
|