2020-03-09 10:11:07 +01:00
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2013, Johan Wiren <johan.wiren.se@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import , division , print_function
__metaclass__ = type
DOCUMENTATION = '''
- - -
module : gem
short_description : Manage Ruby gems
description :
- Manage installation and uninstallation of Ruby gems .
options :
name :
2020-11-13 13:41:11 +01:00
type : str
2020-03-09 10:11:07 +01:00
description :
- The name of the gem to be managed .
required : true
state :
2020-11-13 13:41:11 +01:00
type : str
2020-03-09 10:11:07 +01:00
description :
- The desired state of the gem . C ( latest ) ensures that the latest version is installed .
required : false
choices : [ present , absent , latest ]
default : present
gem_source :
2020-11-13 13:41:11 +01:00
type : path
2020-03-09 10:11:07 +01:00
description :
- The path to a local gem used as installation source .
required : false
include_dependencies :
description :
- Whether to include dependencies or not .
required : false
type : bool
default : " yes "
repository :
2020-11-13 13:41:11 +01:00
type : str
2020-03-09 10:11:07 +01:00
description :
- The repository from which the gem will be installed
required : false
aliases : [ source ]
user_install :
description :
- Install gem in user ' s local gems cache or for all users
required : false
type : bool
default : " yes "
executable :
2020-11-13 13:41:11 +01:00
type : path
2020-03-09 10:11:07 +01:00
description :
- Override the path to the gem executable
required : false
install_dir :
2020-11-13 13:41:11 +01:00
type : path
2020-03-09 10:11:07 +01:00
description :
- Install the gems into a specific directory .
These gems will be independent from the global installed ones .
Specifying this requires user_install to be false .
required : false
2021-06-21 12:41:40 +02:00
bindir :
type : path
description :
- Install executables into a specific directory .
version_added : 3.3 .0
norc :
type : bool
default : false
description :
- Avoid loading any C ( . gemrc ) file . Ignored for RubyGems prior to 2.5 .2 .
- " The current default value will be deprecated in community.general 4.0.0: if the value is not explicitly specified, a deprecation message will be shown. "
- From community . general 5.0 .0 on , the default will be changed to C ( true ) .
version_added : 3.3 .0
2020-03-09 10:11:07 +01:00
env_shebang :
description :
- Rewrite the shebang line on installed scripts to use / usr / bin / env .
required : false
default : " no "
type : bool
version :
2020-11-13 13:41:11 +01:00
type : str
2020-03-09 10:11:07 +01:00
description :
- Version of the gem to be installed / removed .
required : false
pre_release :
description :
- Allow installation of pre - release versions of the gem .
required : false
default : " no "
type : bool
include_doc :
description :
- Install with or without docs .
required : false
default : " no "
type : bool
build_flags :
2020-11-13 13:41:11 +01:00
type : str
2020-03-09 10:11:07 +01:00
description :
- Allow adding build flags for gem compilation
required : false
force :
description :
- Force gem to install , bypassing dependency checks .
required : false
default : " no "
type : bool
author :
- " Ansible Core Team "
- " Johan Wiren (@johanwiren) "
'''
EXAMPLES = '''
2020-05-15 12:12:41 +02:00
- name : Install version 1.0 of vagrant
2020-07-13 21:50:31 +02:00
community . general . gem :
2020-03-09 10:11:07 +01:00
name : vagrant
version : 1.0
state : present
2020-05-15 12:12:41 +02:00
- name : Install latest available version of rake
2020-07-13 21:50:31 +02:00
community . general . gem :
2020-03-09 10:11:07 +01:00
name : rake
state : latest
2020-05-15 12:12:41 +02:00
- name : Install rake version 1.0 from a local gem on disk
2020-07-13 21:50:31 +02:00
community . general . gem :
2020-03-09 10:11:07 +01:00
name : rake
gem_source : / path / to / gems / rake - 1.0 . gem
state : present
'''
import re
from ansible . module_utils . basic import AnsibleModule
def get_rubygems_path ( module ) :
if module . params [ ' executable ' ] :
result = module . params [ ' executable ' ] . split ( ' ' )
else :
result = [ module . get_bin_path ( ' gem ' , True ) ]
return result
def get_rubygems_version ( module ) :
2021-06-21 12:41:40 +02:00
if hasattr ( get_rubygems_version , " ver " ) :
return get_rubygems_version . ver
2020-03-09 10:11:07 +01:00
cmd = get_rubygems_path ( module ) + [ ' --version ' ]
( rc , out , err ) = module . run_command ( cmd , check_rc = True )
match = re . match ( r ' ^( \ d+) \ .( \ d+) \ .( \ d+) ' , out )
if not match :
return None
2021-06-21 12:41:40 +02:00
ver = tuple ( int ( x ) for x in match . groups ( ) )
get_rubygems_version . ver = ver
return ver
2020-03-09 10:11:07 +01:00
def get_rubygems_environ ( module ) :
if module . params [ ' install_dir ' ] :
return { ' GEM_HOME ' : module . params [ ' install_dir ' ] }
return None
def get_installed_versions ( module , remote = False ) :
cmd = get_rubygems_path ( module )
cmd . append ( ' query ' )
2021-06-21 12:41:40 +02:00
cmd . extend ( common_opts ( module ) )
2020-03-09 10:11:07 +01:00
if remote :
cmd . append ( ' --remote ' )
if module . params [ ' repository ' ] :
cmd . extend ( [ ' --source ' , module . params [ ' repository ' ] ] )
cmd . append ( ' -n ' )
cmd . append ( ' ^ %s $ ' % module . params [ ' name ' ] )
environ = get_rubygems_environ ( module )
( rc , out , err ) = module . run_command ( cmd , environ_update = environ , check_rc = True )
installed_versions = [ ]
for line in out . splitlines ( ) :
2020-09-03 07:47:34 +02:00
match = re . match ( r " \ S+ \ s+ \ ((?:default: )?(.+) \ ) " , line )
2020-03-09 10:11:07 +01:00
if match :
versions = match . group ( 1 )
for version in versions . split ( ' , ' ) :
installed_versions . append ( version . split ( ) [ 0 ] )
return installed_versions
def exists ( module ) :
if module . params [ ' state ' ] == ' latest ' :
remoteversions = get_installed_versions ( module , remote = True )
if remoteversions :
module . params [ ' version ' ] = remoteversions [ 0 ]
installed_versions = get_installed_versions ( module )
if module . params [ ' version ' ] :
if module . params [ ' version ' ] in installed_versions :
return True
else :
if installed_versions :
return True
return False
2021-06-21 12:41:40 +02:00
def common_opts ( module ) :
opts = [ ]
ver = get_rubygems_version ( module )
if module . params [ ' norc ' ] and ver and ver > = ( 2 , 5 , 2 ) :
opts . append ( ' --norc ' )
return opts
2020-03-09 10:11:07 +01:00
def uninstall ( module ) :
if module . check_mode :
return
cmd = get_rubygems_path ( module )
environ = get_rubygems_environ ( module )
cmd . append ( ' uninstall ' )
2021-06-21 12:41:40 +02:00
cmd . extend ( common_opts ( module ) )
2020-03-09 10:11:07 +01:00
if module . params [ ' install_dir ' ] :
cmd . extend ( [ ' --install-dir ' , module . params [ ' install_dir ' ] ] )
2021-06-21 12:41:40 +02:00
if module . params [ ' bindir ' ] :
cmd . extend ( [ ' --bindir ' , module . params [ ' bindir ' ] ] )
2020-03-09 10:11:07 +01:00
if module . params [ ' version ' ] :
cmd . extend ( [ ' --version ' , module . params [ ' version ' ] ] )
else :
cmd . append ( ' --all ' )
cmd . append ( ' --executable ' )
cmd . append ( module . params [ ' name ' ] )
module . run_command ( cmd , environ_update = environ , check_rc = True )
def install ( module ) :
if module . check_mode :
return
ver = get_rubygems_version ( module )
cmd = get_rubygems_path ( module )
cmd . append ( ' install ' )
2021-06-21 12:41:40 +02:00
cmd . extend ( common_opts ( module ) )
2020-03-09 10:11:07 +01:00
if module . params [ ' version ' ] :
cmd . extend ( [ ' --version ' , module . params [ ' version ' ] ] )
if module . params [ ' repository ' ] :
cmd . extend ( [ ' --source ' , module . params [ ' repository ' ] ] )
if not module . params [ ' include_dependencies ' ] :
cmd . append ( ' --ignore-dependencies ' )
else :
2021-06-21 12:41:40 +02:00
if ver and ver < ( 2 , 0 , 0 ) :
2020-03-09 10:11:07 +01:00
cmd . append ( ' --include-dependencies ' )
if module . params [ ' user_install ' ] :
cmd . append ( ' --user-install ' )
else :
cmd . append ( ' --no-user-install ' )
if module . params [ ' install_dir ' ] :
cmd . extend ( [ ' --install-dir ' , module . params [ ' install_dir ' ] ] )
2021-06-21 12:41:40 +02:00
if module . params [ ' bindir ' ] :
cmd . extend ( [ ' --bindir ' , module . params [ ' bindir ' ] ] )
2020-03-09 10:11:07 +01:00
if module . params [ ' pre_release ' ] :
cmd . append ( ' --pre ' )
if not module . params [ ' include_doc ' ] :
2021-06-21 12:41:40 +02:00
if ver and ver < ( 2 , 0 , 0 ) :
2020-03-09 10:11:07 +01:00
cmd . append ( ' --no-rdoc ' )
cmd . append ( ' --no-ri ' )
else :
cmd . append ( ' --no-document ' )
if module . params [ ' env_shebang ' ] :
cmd . append ( ' --env-shebang ' )
cmd . append ( module . params [ ' gem_source ' ] )
if module . params [ ' build_flags ' ] :
cmd . extend ( [ ' -- ' , module . params [ ' build_flags ' ] ] )
if module . params [ ' force ' ] :
cmd . append ( ' --force ' )
module . run_command ( cmd , check_rc = True )
def main ( ) :
module = AnsibleModule (
argument_spec = dict (
executable = dict ( required = False , type = ' path ' ) ,
gem_source = dict ( required = False , type = ' path ' ) ,
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 , default = ' present ' , choices = [ ' present ' , ' absent ' , ' latest ' ] , type = ' str ' ) ,
user_install = dict ( required = False , default = True , type = ' bool ' ) ,
install_dir = dict ( required = False , type = ' path ' ) ,
2021-06-21 12:41:40 +02:00
bindir = dict ( type = ' path ' ) ,
norc = dict ( default = False , type = ' bool ' ) ,
2020-03-09 10:11:07 +01:00
pre_release = dict ( required = False , default = False , type = ' bool ' ) ,
include_doc = dict ( required = False , default = False , type = ' bool ' ) ,
env_shebang = dict ( required = False , default = False , type = ' bool ' ) ,
version = dict ( required = False , type = ' str ' ) ,
build_flags = dict ( required = False , type = ' str ' ) ,
force = dict ( required = False , default = False , type = ' bool ' ) ,
) ,
supports_check_mode = True ,
mutually_exclusive = [ [ ' gem_source ' , ' repository ' ] , [ ' gem_source ' , ' version ' ] ] ,
)
if module . params [ ' version ' ] and module . params [ ' state ' ] == ' latest ' :
module . fail_json ( msg = " Cannot specify version when state=latest " )
if module . params [ ' gem_source ' ] and module . params [ ' state ' ] == ' latest ' :
module . fail_json ( msg = " Cannot maintain state=latest when installing from local source " )
if module . params [ ' user_install ' ] and module . params [ ' install_dir ' ] :
module . fail_json ( msg = " install_dir requires user_install=false " )
if not module . params [ ' gem_source ' ] :
module . params [ ' gem_source ' ] = module . params [ ' name ' ]
changed = False
if module . params [ ' state ' ] in [ ' present ' , ' latest ' ] :
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 )
if __name__ == ' __main__ ' :
main ( )