File: //proc/self/root/usr/lib/python2.7/site-packages/salt/modules/cpan.py
# -*- coding: utf-8 -*-
'''
Manage Perl modules using CPAN
.. versionadded:: 2015.5.0
'''
from __future__ import absolute_import, print_function, unicode_literals
# Import python libs
import os
import os.path
import logging
# Import salt libs
import salt.utils.files
import salt.utils.path
log = logging.getLogger(__name__)
# Don't shadow built-ins.
__func_alias__ = {
'list_': 'list'
}
def __virtual__():
'''
Only work on supported POSIX-like systems
'''
if salt.utils.path.which('cpan'):
return True
return (False, 'Unable to locate cpan. Make sure it is installed and in the PATH.')
def install(module):
'''
Install a Perl module from CPAN
CLI Example:
.. code-block:: bash
salt '*' cpan.install Template::Alloy
'''
ret = {
'old': None,
'new': None,
}
old_info = show(module)
cmd = 'cpan -i {0}'.format(module)
out = __salt__['cmd.run'](cmd)
if "don't know what it is" in out:
ret['error'] = 'CPAN cannot identify this package'
return ret
new_info = show(module)
ret['old'] = old_info.get('installed version', None)
ret['new'] = new_info['installed version']
return ret
def remove(module, details=False):
'''
Attempt to remove a Perl module that was installed from CPAN. Because the
``cpan`` command doesn't actually support "uninstall"-like functionality,
this function will attempt to do what it can, with what it has from CPAN.
Until this function is declared stable, USE AT YOUR OWN RISK!
CLI Example:
.. code-block:: bash
salt '*' cpan.remove Old::Package
'''
ret = {
'old': None,
'new': None,
}
info = show(module)
if 'error' in info:
return {
'error': info['error']
}
version = info.get('installed version', None)
if version is None:
return ret
ret['old'] = version
if 'cpan build dirs' not in info:
return {
'error': 'No CPAN data available to use for uninstalling'
}
mod_pathfile = module.replace('::', '/') + '.pm'
ins_path = info['installed file'].replace(mod_pathfile, '')
files = []
for build_dir in info['cpan build dirs']:
contents = os.listdir(build_dir)
if 'MANIFEST' not in contents:
continue
mfile = os.path.join(build_dir, 'MANIFEST')
with salt.utils.files.fopen(mfile, 'r') as fh_:
for line in fh_.readlines():
line = salt.utils.stringutils.to_unicode(line)
if line.startswith('lib/'):
files.append(line.replace('lib/', ins_path).strip())
rm_details = {}
for file_ in files:
if file_ in rm_details:
continue
log.trace('Removing {0}'.format(file_))
if __salt__['file.remove'](file_):
rm_details[file_] = 'removed'
else:
rm_details[file_] = 'unable to remove'
if details:
ret['details'] = rm_details
return ret
def list_():
'''
List installed Perl modules, and the version installed
CLI Example:
.. code-block:: bash
salt '*' cpan.list
'''
ret = {}
cmd = 'cpan -l'
out = __salt__['cmd.run'](cmd).splitlines()
for line in out:
comps = line.split()
ret[comps[0]] = comps[1]
return ret
def show(module):
'''
Show information about a specific Perl module
CLI Example:
.. code-block:: bash
salt '*' cpan.show Template::Alloy
'''
ret = {}
ret['name'] = module
# This section parses out details from CPAN, if possible
cmd = 'cpan -D {0}'.format(module)
out = __salt__['cmd.run'](cmd).splitlines()
mode = 'skip'
info = []
for line in out:
if line.startswith('-------------'):
mode = 'parse'
continue
if mode == 'skip':
continue
info.append(line)
if len(info) == 6:
# If the module is not installed, we'll be short a line
info.insert(2, '')
if len(info) < 6:
# This must not be a real package
ret['error'] = 'This package does not seem to exist'
return ret
ret['description'] = info[0].strip()
ret['cpan file'] = info[1].strip()
if info[2].strip():
ret['installed file'] = info[2].strip()
else:
ret['installed file'] = None
comps = info[3].split(':')
if len(comps) > 1:
ret['installed version'] = comps[1].strip()
if 'installed version' not in ret or not ret['installed version']:
ret['installed version'] = None
comps = info[4].split(':')
comps = comps[1].split()
ret['cpan version'] = comps[0].strip()
ret['author name'] = info[5].strip()
ret['author email'] = info[6].strip()
# Check and see if there are cpan build directories
config = show_config()
build_dir = config.get('build_dir', None)
if build_dir is not None:
ret['cpan build dirs'] = []
builds = os.listdir(build_dir)
pfile = module.replace('::', '-')
for file_ in builds:
if file_.startswith(pfile):
ret['cpan build dirs'].append(os.path.join(build_dir, file_))
return ret
def show_config():
'''
Return a dict of CPAN configuration values
CLI Example:
.. code-block:: bash
salt '*' cpan.show_config
'''
ret = {}
cmd = 'cpan -J'
out = __salt__['cmd.run'](cmd).splitlines()
for line in out:
if '=>' not in line:
# TODO: Some options take up multiple lines, so this doesn't always work
continue
comps = line.split('=>')
key = comps[0].replace("'", '').strip()
val = comps[1].replace("',", '').replace("'", '').strip()
ret[key] = val
return ret