gem 7.28 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
#!/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
26
description:
Johan Wirén committed
27 28 29 30
  - 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
    description:
36
      - The desired state of the gem. C(latest) ensures that the latest version is installed.
37
    required: false
Johan Wirén committed
38
    choices: [present, absent, latest]
39
    default: present
40
  gem_source:
41 42
    description:
      - The path to a local gem used as installation source.
Johan Wirén committed
43
    required: false
44
  include_dependencies:
45 46
    description:
      - Wheter to include dependencies or not.
Johan Wirén committed
47
    required: false
48 49
    choices: [ "yes", "no" ]
    default: "yes"
Johan Wirén committed
50
  repository:
51 52
    description:
      - The repository from which the gem will be installed
Johan Wirén committed
53 54
    required: false
    aliases: [source]
Dmitry Kolobaev committed
55 56 57 58 59
  user_install:
    description:
      - Install gem in user's local gems cache or for all users
    required: false
    default: "yes"
60
    version_added: "1.3"
61 62 63 64 65
  executable:
    description:
    - Override the path to the gem executable
    required: false
    version_added: "1.4"
Johan Wirén committed
66
  version:
67 68
    description:
      - Version of the gem to be installed/removed.
Johan Wirén committed
69
    required: false
70
  pre_release:
71
    description:
72
      - Allow installation of pre-release versions of the gem.
73 74 75
    required: false
    default: "no"
    version_added: "1.6"
Johan Wirén committed
76 77
author: Johan Wiren
'''
78 79 80

EXAMPLES = '''
# Installs version 1.0 of vagrant.
81
- gem: name=vagrant version=1.0 state=present
82 83

# Installs latest available version of rake.
84
- gem: name=rake state=latest
85 86

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

Johan Wirén committed
90 91
import re

92 93 94 95 96 97
def get_rubygems_path(module):
    if module.params['executable']:
        return module.params['executable']
    else:
        return module.get_bin_path('gem', True)

98
def get_rubygems_version(module):
99
    cmd = [ get_rubygems_path(module), '--version' ]
100 101 102 103 104 105 106 107
    (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())

108 109
def get_installed_versions(module, remote=False):

110
    cmd = [ get_rubygems_path(module) ]
Johan Wirén committed
111 112 113 114 115 116 117 118
    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)
119
    installed_versions = []
Johan Wirén committed
120 121 122 123 124
    for line in out.splitlines():
        match = re.match(r"\S+\s+\((.+)\)", line)
        if match:
            versions = match.group(1)
            for version in versions.split(', '):
125
                installed_versions.append(version.split()[0])
126
    return installed_versions
Johan Wirén committed
127 128

def exists(module):
129

Johan Wirén committed
130
    if module.params['state'] == 'latest':
131
        remoteversions = get_installed_versions(module, remote=True)
Johan Wirén committed
132 133
        if remoteversions:
            module.params['version'] = remoteversions[0]
134
    installed_versions = get_installed_versions(module)
Johan Wirén committed
135
    if module.params['version']:
136
        if module.params['version'] in installed_versions:
Johan Wirén committed
137 138
            return True
    else:
139
        if installed_versions:
Johan Wirén committed
140 141 142 143
            return True
    return False

def uninstall(module):
144

Johan Wirén committed
145 146
    if module.check_mode:
        return
147
    cmd = [ get_rubygems_path(module) ]
Johan Wirén committed
148 149 150 151 152
    cmd.append('uninstall')
    if module.params['version']:
        cmd.extend([ '--version', module.params['version'] ])
    else:
        cmd.append('--all')
153
        cmd.append('--executable')
Johan Wirén committed
154 155 156 157
    cmd.append(module.params['name'])
    module.run_command(cmd, check_rc=True)

def install(module):
158

Johan Wirén committed
159 160
    if module.check_mode:
        return
161 162

    ver = get_rubygems_version(module)
163 164 165 166
    if ver:
        major = ver[0]
    else:
        major = None
167

168
    cmd = [ get_rubygems_path(module) ]
Johan Wirén committed
169 170 171 172 173
    cmd.append('install')
    if module.params['version']:
        cmd.extend([ '--version', module.params['version'] ])
    if module.params['repository']:
        cmd.extend([ '--source', module.params['repository'] ])
174 175 176 177 178
    if not module.params['include_dependencies']:
        cmd.append('--ignore-dependencies')
    else:
        if major and major < 2:
            cmd.append('--include-dependencies')
179 180 181
    if module.params['user_install']:
        cmd.append('--user-install')
    else:
182
        cmd.append('--no-user-install')
183
    if module.params['pre_release']:
184
        cmd.append('--pre')
Johan Wirén committed
185 186
    cmd.append('--no-rdoc')
    cmd.append('--no-ri')
187
    cmd.append(module.params['gem_source'])
Johan Wirén committed
188 189 190
    module.run_command(cmd, check_rc=True)

def main():
191

Johan Wirén committed
192
    module = AnsibleModule(
193
        argument_spec = dict(
194
            executable           = dict(required=False, type='str'),
195 196 197 198
            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'),
199
            state                = dict(required=False, default='present', choices=['present','absent','latest'], type='str'),
Dmitry Kolobaev committed
200
            user_install         = dict(required=False, default=True, type='bool'),
201
            pre_release           = dict(required=False, default=False, type='bool'),
202 203
            version              = dict(required=False, type='str'),
        ),
Johan Wirén committed
204
        supports_check_mode = True,
205 206
        mutually_exclusive = [ ['gem_source','repository'], ['gem_source','version'] ],
    )
Johan Wirén committed
207 208 209

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

213
    if not module.params['gem_source']:
214
        module.params['gem_source'] = module.params['name']
Johan Wirén committed
215 216 217

    changed = False

218
    if module.params['state'] in [ 'present', 'latest']:
Johan Wirén committed
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
        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)

236 237
# import module snippets
from ansible.module_utils.basic import *
Johan Wirén committed
238
main()