gem 6.22 KB
Newer Older
Johan Wirén committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2013, Johan Wiren <johan.wiren.se@gmail.com>
#
# 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/>.
#

DOCUMENTATION = '''
---
module: gem
short_description: Manage Ruby gems
description: 
  - Manage installation and uninstallation of Ruby gems.
version_added: "1.1"
options:
  name:
31 32
    description:
      - The name of the gem to be managed.
Johan Wirén committed
33 34
    required: true
  state:
35 36
    description: 
      - The desired state of the gem. C(latest) ensures that the latest version is installed.
Johan Wirén committed
37 38
    required: true
    choices: [present, absent, latest]
39
  gem_source:
40 41
    description:
      - The path to a local gem used as installation source.
Johan Wirén committed
42
    required: false
43
  include_dependencies:
44 45
    description:
      - Wheter to include dependencies or not.
Johan Wirén committed
46
    required: false
47 48
    choices: [ "yes", "no" ]
    default: "yes"
Johan Wirén committed
49
  repository:
50 51
    description:
      - The repository from which the gem will be installed
Johan Wirén committed
52 53 54
    required: false
    aliases: [source]
  version:
55 56
    description:
      - Version of the gem to be installed/removed.
Johan Wirén committed
57 58 59
    required: false
author: Johan Wiren
'''
60 61 62 63 64 65 66 67 68 69 70 71

EXAMPLES = '''
# Installs version 1.0 of vagrant.
gem: name=vagrant version=1.0 state=present

# Installs latest available version of rake.
gem: name=rake state=latest

# Installs rake version 1.0 from a local gem on disk.
gem: name=rake gem_source=/path/to/gems/rake-1.0.gem state=present
'''

Johan Wirén committed
72 73
import re

74 75 76 77 78 79 80 81 82 83
def get_rubygems_version(module):
    cmd = [module.get_bin_path('gem', True), '--version']
    (rc, out, err) = module.run_command(cmd, check_rc=True)

    match = re.match(r'^(\d+)\.(\d+)\.(\d+)', out)
    if not match:
        return None

    return tuple(int(x) for x in match.groups())

84 85
def get_installed_versions(module, remote=False):

Johan Wirén committed
86 87 88 89 90 91 92 93 94
    cmd = [ module.get_bin_path('gem', True) ]
    cmd.append('query')
    if remote:
        cmd.append('--remote')
        if module.params['repository']:
            cmd.extend([ '--source', module.params['repository'] ])
    cmd.append('-n')
    cmd.append('^%s$' % module.params['name'])
    (rc, out, err) = module.run_command(cmd, check_rc=True)
95
    installed_versions = []
Johan Wirén committed
96 97 98 99 100
    for line in out.splitlines():
        match = re.match(r"\S+\s+\((.+)\)", line)
        if match:
            versions = match.group(1)
            for version in versions.split(', '):
101 102
                installed_versions.append(version)
    return installed_versions
Johan Wirén committed
103 104

def exists(module):
105

Johan Wirén committed
106
    if module.params['state'] == 'latest':
107
        remoteversions = get_installed_versions(module, remote=True)
Johan Wirén committed
108 109
        if remoteversions:
            module.params['version'] = remoteversions[0]
110
    installed_versions = get_installed_versions(module)
Johan Wirén committed
111
    if module.params['version']:
112
        if module.params['version'] in installed_versions:
Johan Wirén committed
113 114
            return True
    else:
115
        if installed_versions:
Johan Wirén committed
116 117 118 119
            return True
    return False

def uninstall(module):
120

Johan Wirén committed
121 122 123 124 125 126 127 128 129 130 131 132
    if module.check_mode:
        return
    cmd = [ module.get_bin_path('gem', True) ]
    cmd.append('uninstall')
    if module.params['version']:
        cmd.extend([ '--version', module.params['version'] ])
    else:
        cmd.append('--all')
    cmd.append(module.params['name'])
    module.run_command(cmd, check_rc=True)

def install(module):
133

Johan Wirén committed
134 135
    if module.check_mode:
        return
136 137

    ver = get_rubygems_version(module)
138 139 140 141
    if ver:
        major = ver[0]
    else:
        major = None
142

Johan Wirén committed
143 144 145 146 147 148
    cmd = [ module.get_bin_path('gem', True) ]
    cmd.append('install')
    if module.params['version']:
        cmd.extend([ '--version', module.params['version'] ])
    if module.params['repository']:
        cmd.extend([ '--source', module.params['repository'] ])
149 150 151 152 153
    if not module.params['include_dependencies']:
        cmd.append('--ignore-dependencies')
    else:
        if major and major < 2:
            cmd.append('--include-dependencies')
Johan Wirén committed
154 155
    cmd.append('--no-rdoc')
    cmd.append('--no-ri')
156
    cmd.append(module.params['gem_source'])
Johan Wirén committed
157 158 159
    module.run_command(cmd, check_rc=True)

def main():
160

Johan Wirén committed
161
    module = AnsibleModule(
162 163 164 165 166 167 168 169
        argument_spec = dict(
            gem_source           = dict(required=False, type='str'),
            include_dependencies = dict(required=False, default=True, type='bool'),
            name                 = dict(required=True, type='str'),
            repository           = dict(required=False, aliases=['source'], type='str'),
            state                = dict(required=False, choices=['present','absent','latest'], type='str'),
            version              = dict(required=False, type='str'),
        ),
Johan Wirén committed
170
        supports_check_mode = True,
171 172
        mutually_exclusive = [ ['gem_source','repository'], ['gem_source','version'] ],
    )
Johan Wirén committed
173 174 175

    if module.params['version'] and module.params['state'] == 'latest':
        module.fail_json(msg="Cannot specify version when state=latest")
176
    if module.params['gem_source'] and module.params['state'] == 'latest':
Johan Wirén committed
177 178
        module.fail_json(msg="Cannot maintain state=latest when installing from local source")

179
    if not module.params['gem_source']:
180
        module.params['gem_source'] = module.params['name']
Johan Wirén committed
181 182 183

    changed = False

184
    if module.params['state'] in [ 'present', 'latest']:
Johan Wirén committed
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
        if not exists(module):
            install(module)
            changed = True
    elif module.params['state'] == 'absent':
        if exists(module):
            uninstall(module)
            changed = True

    result = {}
    result['name'] = module.params['name']
    result['state'] = module.params['state']
    if module.params['version']:
        result['version'] = module.params['version']
    result['changed'] = changed

    module.exit_json(**result)

# include magic from lib/ansible/module_common.py
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
main()