Fix pip freeze workaround with virtualenv (#4951)

This commit is contained in:
Toshio Kuratomi 2016-09-20 18:20:13 -07:00 committed by Matt Clay
parent d1ef5f947e
commit 77975c232b

View file

@ -187,6 +187,14 @@ import os
import sys import sys
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
#: Python one-liners to be run at the command line that will determine the
# installed version for these special libraries. These are libraries that
# don't end up in the output of pip freeze.
_SPECIAL_PACKAGE_CHECKERS = {'setuptools': 'import setuptools; print(setuptools.__version__)',
'pip': 'import pkg_resources; print(pkg_resources.get_distribution("pip").version)'}
def _get_cmd_options(module, cmd): def _get_cmd_options(module, cmd):
@ -196,7 +204,7 @@ def _get_cmd_options(module, cmd):
module.fail_json(msg="Could not get output from %s: %s" % (thiscmd, stdout + stderr)) module.fail_json(msg="Could not get output from %s: %s" % (thiscmd, stdout + stderr))
words = stdout.strip().split() words = stdout.strip().split()
cmd_options = [ x for x in words if x.startswith('--') ] cmd_options = [x for x in words if x.startswith('--')]
return cmd_options return cmd_options
@ -292,6 +300,31 @@ def _fail(module, cmd, out, err):
module.fail_json(cmd=cmd, msg=msg) module.fail_json(cmd=cmd, msg=msg)
def _get_package_info(module, package, env=None):
"""This is only needed for special packages which do not show up in pip freeze
pip and setuptools fall into this category.
:returns: a string containing the version number if the package is
installed. None if the package is not installed.
"""
if env:
opt_dirs = ['%s/bin' % env]
else:
opt_dirs = []
python_bin = module.get_bin_path('python', False, opt_dirs)
if python_bin is None:
formatted_dep = None
else:
rc, out, err = module.run_command([python_bin, '-c', _SPECIAL_PACKAGE_CHECKERS[package]])
if rc:
formatted_dep = None
else:
formatted_dep = '%s==%s' % (package, out.strip())
return formatted_dep
def main(): def main():
state_map = dict( state_map = dict(
present='install', present='install',
@ -306,9 +339,9 @@ def main():
name=dict(type='list'), name=dict(type='list'),
version=dict(type='str'), version=dict(type='str'),
requirements=dict(), requirements=dict(),
virtualenv=dict(), virtualenv=dict(type='path'),
virtualenv_site_packages=dict(default=False, type='bool'), virtualenv_site_packages=dict(default=False, type='bool'),
virtualenv_command=dict(default='virtualenv'), virtualenv_command=dict(default='virtualenv', type='path'),
virtualenv_python=dict(type='str'), virtualenv_python=dict(type='str'),
use_mirrors=dict(default=True, type='bool'), use_mirrors=dict(default=True, type='bool'),
extra_args=dict(), extra_args=dict(),
@ -336,7 +369,7 @@ def main():
umask = int(umask, 8) umask = int(umask, 8)
except Exception: except Exception:
module.fail_json(msg="umask must be an octal integer", module.fail_json(msg="umask must be an octal integer",
details=str(sys.exc_info()[1])) details=to_native(sys.exc_info()[1]))
old_umask = None old_umask = None
if umask is not None: if umask is not None:
@ -353,17 +386,15 @@ def main():
out = '' out = ''
env = module.params['virtualenv'] env = module.params['virtualenv']
virtualenv_command = module.params['virtualenv_command']
if env: if env:
env = os.path.expanduser(env)
if not os.path.exists(os.path.join(env, 'bin', 'activate')): if not os.path.exists(os.path.join(env, 'bin', 'activate')):
if module.check_mode: if module.check_mode:
module.exit_json(changed=True) module.exit_json(changed=True)
cmd = os.path.expanduser(virtualenv_command) cmd = module.params['virtualenv_command']
if os.path.basename(cmd) == cmd: if os.path.basename(cmd) == cmd:
cmd = module.get_bin_path(virtualenv_command, True) cmd = module.get_bin_path(cmd, True)
if module.params['virtualenv_site_packages']: if module.params['virtualenv_site_packages']:
cmd += ' --system-site-packages' cmd += ' --system-site-packages'
@ -438,30 +469,15 @@ def main():
changed = False changed = False
if name: if name:
pkg_list = [p for p in out.split('\n') if not p.startswith('You are using') and not p.startswith('You should consider') and p] pkg_list = [p for p in out.split('\n') if not p.startswith('You are using') and not p.startswith('You should consider') and p]
if pkg_cmd.endswith(' freeze') and ('pip' in name or 'setuptools' in name): if pkg_cmd.endswith(' freeze') and ('pip' in name or 'setuptools' in name):
# Older versions of pip (pre-1.3) do not have pip list. # Older versions of pip (pre-1.3) do not have pip list.
# pip freeze does not list setuptools or pip in its output # pip freeze does not list setuptools or pip in its output
# So we need to get those via a specialcase # So we need to get those via a specialcase
if 'setuptools' in name: for pkg in ('setuptools', 'pip'):
try: if pkg in name:
import setuptools formatted_dep = _get_package_info(module, pkg, env)
except ImportError: if formatted_dep is not None:
# Could not import, assume that it is not installed
pass
else:
formatted_dep = 'setuptools==%s' % setuptools.__version__
pkg_list.append(formatted_dep)
out += '%s\n' % formatted_dep
if 'pip' in name:
try:
import pkg_resources
except ImportError:
# Could not import pkg_resources. pip requires
# pkg_resources so assume that it is not installed
pass
else:
formatted_dep = 'pip==%s' % pkg_resources.get_distribution('pip').version
pkg_list.append(formatted_dep) pkg_list.append(formatted_dep)
out += '%s\n' % formatted_dep out += '%s\n' % formatted_dep