From 0d74ae33680a4a8c70a7c3fc1cdbb03774a470e0 Mon Sep 17 00:00:00 2001 From: Toshio Kuratomi Date: Tue, 1 Nov 2016 06:46:22 -0700 Subject: [PATCH] Need to locate a pip inside a venv when venv is specified Alternative to #5359 Fixes #5347 --- lib/ansible/modules/packaging/language/pip.py | 58 ++++++++++++------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/lib/ansible/modules/packaging/language/pip.py b/lib/ansible/modules/packaging/language/pip.py index 95cd7caf5f..7c8aa8cb78 100755 --- a/lib/ansible/modules/packaging/language/pip.py +++ b/lib/ansible/modules/packaging/language/pip.py @@ -190,7 +190,7 @@ import re import os import sys -from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.basic import AnsibleModule, is_executable from ansible.module_utils._text import to_native from ansible.module_utils.six import PY3 @@ -263,17 +263,14 @@ def _is_present(name, version, installed_pkgs, pkg_command): def _get_pip(module, env=None, executable=None): - # On Debian and Ubuntu, pip is pip. - # On Fedora18 and up, pip is python-pip. - # On Fedora17 and below, CentOS and RedHat 6 and 5, pip is pip-python. - # On Fedora, CentOS, and RedHat, the exception is in the virtualenv. - # There, pip is just pip. - # On python 3.4, pip should be default, cf PEP 453 - # By default, it will try to use pip required for the current python + # Older pip only installed under the "/usr/bin/pip" name. Many Linux + # distros install it there. + # By default, we try to use pip required for the current python # interpreter, so people can use pip to install modules dependencies - candidate_pip_basenames = ['pip2', 'pip', 'python-pip', 'pip-python'] + candidate_pip_basenames = ('pip2', 'pip') if PY3: - candidate_pip_basenames = ['pip3'] + # pip under python3 installs the "/usr/bin/pip3" name + candidate_pip_basenames = ('pip3',) pip = None if executable is not None: @@ -282,22 +279,39 @@ def _get_pip(module, env=None, executable=None): pip = executable else: # If you define your own executable that executable should be the only candidate. - candidate_pip_basenames = [executable] + # As noted in the docs, executable doesn't work with virtualenvs. + candidate_pip_basenames = (executable,) + if pip is None: if env is None: opt_dirs = [] + for basename in candidate_pip_basenames: + pip = module.get_bin_path(basename, False, opt_dirs) + if pip is not None: + break + else: + # For-else: Means that we did not break out of the loop + # (therefore, that pip was not found) + module.fail_json(msg='Unable to find any of %s to use. pip' + ' needs to be installed.' % ', '.join(candidate_pip_basenames)) else: - # Try pip with the virtualenv directory first. - opt_dirs = ['%s/bin' % env] - for basename in candidate_pip_basenames: - pip = module.get_bin_path(basename, False, opt_dirs) - if pip is not None: - break - # pip should have been found by now. The final call to get_bin_path will - # trigger fail_json. - if pip is None: - basename = candidate_pip_basenames[0] - pip = module.get_bin_path(basename, True, opt_dirs) + # If we're using a virtualenv we must use the pip from the + # virtualenv + venv_dir = os.path.join(env, 'bin') + candidate_pip_basenames = (candidate_pip_basenames[0], 'pip') + for basename in candidate_pip_basenames: + candidate = os.path.join(venv_dir, basename) + if os.path.exists(candidate) and is_executable(candidate): + pip = candidate + break + else: + # For-else: Means that we did not break out of the loop + # (therefore, that pip was not found) + module.fail_json(msg='Unable to find pip in the virtualenv,' + ' %s, under any of these names: %s. Make sure pip is' + ' present in the virtualenv.' % (env, + ', '.join(candidate_pip_basenames))) + return pip