Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add pip module #796

Merged
merged 2 commits into from
Aug 8, 2012
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
198 changes: 198 additions & 0 deletions library/pip
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2012, Matt Wright <matt@nobien.net>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#

PIP = None
VIRTUALENV = None
ENV = None


def _get_full_name(name, version=None):
return name if version is None else name + '==' + version


def _find_pip():
paths = ['/usr/local/bin', '/usr/bin']

if ENV:
paths = [os.path.join(ENV, 'bin')] + paths

for p in paths:
pe = p + '/pip'
if os.path.exists(pe):
return pe

module.fail_json(msg='pip is not installed')


def _find_virtualenv():
paths = ['/usr/local/bin', '/usr/bin']

for p in paths:
ve = p + '/virtualenv'
if os.path.exists(ve):
return ve

module.fail_json(msg='virtualenv is not installed')


def _ensure_virtualenv():
if os.path.exists(os.path.join(ENV, 'bin', 'activate')):
return 0, '', ''
else:
return _run('%s %s' % (VIRTUALENV, ENV))


def _is_package_installed(name, version=None):
rc, status_stdout, status_stderr = _run('%s freeze' % PIP)
return _get_full_name(name, version).lower() in status_stdout.lower()


def _did_install(out):
return 'Successfully installed' in out


def _run(cmd):
# returns (rc, stdout, stderr) from shell command
process = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True)
stdout, stderr = process.communicate()
return (process.returncode, stdout, stderr)


def main():
arg_spec = dict(
state=dict(default='present', choices=['absent', 'present', 'latest']),
name=dict(default=None, required=False),
version=dict(default=None, required=False),
requirements=dict(default=None, required=False),
virtualenv=dict(default=None, required=False)
)

module = AnsibleModule(argument_spec=arg_spec)

rc = 0
err = ''
out = ''

ENV = module.params['virtualenv']
PIP = _find_pip()

if ENV:
VIRTUALENV = _find_virtualenv()

rc_venv, out_venv, err_venv = _ensure_virtualenv()

rc += rc_venv
out += out_venv
err += err_venv

state = module.params['state']
name = module.params['name']
version = module.params['version']
requirements = module.params['requirements']
command_map = dict(present='install', absent='uninstall', latest='install')

if state == 'latest' and version is not None:
module.fail_json(msg='If `state` is set to `latest` the `version` '
'parameter must not be specified.')

if state == 'latest' and requirements is not None:
module.fail_json(msg='If `state` is set to `latest` the `requirements` '
'parameter must not be specified.')

if name is not None and '==' in name:
module.fail_json(msg='It looks like you specified the version number '
'in the library name. Use the `version` parameter '
'to specify version instead')

if version is not None and name is None:
module.fail_json(msg='The `version` parameter must be used with the '
'`name` parameter and not with the `requirements` '
'paramter')

if name is None and requirements is None:
module.fail_json(msg='You must specify a python library name via '
'the `name` parameter or a requirements file via '
'the `requirements` paramter')

if name and requirements:
module.fail_json(msg='Both `name` and `requirements` were specified. '
'Specify only the python library name via the '
'`name` parameter or a requirements file via the '
'`requirements` parameter')

cmd = None
installed = None

if requirements:
cmd = '%s %s -r %s --use-mirrors' % (PIP, command_map[state], requirements)
rc_pip, out_pip, err_pip = _run(cmd)

rc += rc_pip
out += out_pip
err += err_pip

changed = ((_did_install(out) and state == 'present') or
(not _did_install(out) and state == 'absent'))

if name and state == 'latest':
cmd = '%s %s %s --upgrade' % (PIP, command_map[state], name)

rc_pip, out_pip, err_pip = _run(cmd)

rc += rc_pip
out += out_pip
err += err_pip

changed = 'Successfully installed' in out_pip

elif name:
installed = _is_package_installed(name, version)

changed = ((installed and state == 'absent') or
(not installed and state == 'present'))

if changed:
full_name = _get_full_name(name, version) if state == 'present' else name

cmd = '%s %s %s' % (PIP, command_map[state], full_name)

if state == 'absent':
cmd = cmd + ' -y'
else:
cmd = cmd + ' --use-mirrors'

rc_pip, out_pip, err_pip = _run(cmd)

rc += rc_pip
out += out_pip
err += err_pip

if rc != 0:
module.fail_json(msg=err, cmd=cmd)

module.exit_json(changed=changed, cmd=cmd, name=name, version=version,
state=state, requirements=requirements, virtualenv=ENV)

# this is magic, see lib/ansible/module_common.py
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>

main()