Add cyg mirror support

This commit is contained in:
Gavin Swanson 2014-08-23 15:13:40 -07:00
parent 9f517c5ddf
commit 8d5879507c
2 changed files with 126 additions and 108 deletions

View File

@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-
'''
"""
Manage cygwin packages.
'''
Module file to accompany the cyg state.
"""
# Import python libs
import logging
@ -14,14 +15,15 @@ from salt.exceptions import SaltInvocationError
LOG = logging.getLogger(__name__)
DEFAULT_MIRROR = "ftp://mirrors.kernel.org/sourceware/cygwin/"
DEFAULT_MIRROR_KEY = ""
# Define the module's virtual name
__virtualname__ = 'cyg'
def __virtual__():
'''
Only works on Windows systems
'''
"""Only works on Windows systems."""
if salt.utils.is_windows():
return __virtualname__
return False
@ -32,9 +34,7 @@ __func_alias__ = {
def _get_cyg_dir(cyg_arch='x86_64'):
'''
Returns the cygwin install directory based on the architecture
'''
"""Return the cygwin install directory based on the architecture."""
if cyg_arch == 'x86_64':
return 'cygwin64'
elif cyg_arch == 'x86':
@ -45,12 +45,12 @@ def _get_cyg_dir(cyg_arch='x86_64'):
def _check_cygwin_installed(cyg_arch='x86_64'):
'''
Returns True or False if the given architecture of cygwin is installed
'''
# Use the cygcheck executable to check install.
# It is installed as part of the base package,
# and we use it to check packages
"""
Return True or False if cygwin is installed.
Use the cygcheck executable to check install. It is installed as part of
the base package, and we use it to check packages
"""
path_to_cygcheck = os.sep.join(['C:',
_get_cyg_dir(cyg_arch),
'bin', 'cygcheck.exe'])
@ -61,12 +61,9 @@ def _check_cygwin_installed(cyg_arch='x86_64'):
return True
def _get_all_packages(mirror="ftp://mirrors.kernel.org/sourceware/cygwin/",
def _get_all_packages(mirror=DEFAULT_MIRROR,
cyg_arch='x86_64'):
'''
Returns the list of packages based on the mirror
provided.
'''
"""Return the list of packages based on the mirror provided."""
if 'cyg.all_packages' not in __context__:
__context__['cyg.all_packages'] = {}
if mirror not in __context__['cyg.all_packages']:
@ -75,9 +72,9 @@ def _get_all_packages(mirror="ftp://mirrors.kernel.org/sourceware/cygwin/",
pkg_source = '/'.join([mirror, cyg_arch, 'setup.bz2'])
file_data = urlopen(pkg_source).read()
file_lines = bz2.decompress(file_data
).decode('utf_8',
errors='replace').splitlines()
file_lines = bz2.decompress(file_data).decode('utf_8',
errors='replace'
).splitlines()
packages = [re.search('^@ ([^ ]+)', line).group(1) for
line in file_lines if re.match('^@ [^ ]+', line)]
@ -88,13 +85,13 @@ def _get_all_packages(mirror="ftp://mirrors.kernel.org/sourceware/cygwin/",
def check_valid_package(package,
mirrors=None,
cyg_arch='x86_64'):
'''
Checks if the package is valid on the given mirrors
'''
cyg_arch='x86_64',
mirrors=None):
"""Check if the package is valid on the given mirrors."""
if mirrors is None:
mirrors = ['ftp://mirrors.kernel.org/sourceware/cygwin/']
mirrors = {DEFAULT_MIRROR: DEFAULT_MIRROR_KEY}
LOG.debug('Checking Valid Mirrors: {0}'.format(mirrors))
for mirror in mirrors:
if package in _get_all_packages(mirror, cyg_arch):
@ -102,11 +99,15 @@ def check_valid_package(package,
return False
def _run_silent_cygwin(cyg_arch='x86_64', args=None):
'''
Retrieves the correct setup.exe and runs it with the correct
arguments to get the bare minumum cygwin installation up and running.
'''
def _run_silent_cygwin(cyg_arch='x86_64',
args=None,
mirrors=None):
"""
Retrieve the correct setup.exe.
Run it with the correct arguments to get the bare minimum cygwin
installation up and running.
"""
cyg_cache_dir = os.sep.join(['c:', 'cygcache'])
cyg_setup = 'setup-{0}.exe'.format(cyg_arch)
cyg_setup_path = os.sep.join([cyg_cache_dir, cyg_setup])
@ -126,9 +127,13 @@ def _run_silent_cygwin(cyg_arch='x86_64', args=None):
setup_command = cyg_setup_path
options = []
options.append('--local-package-dir {0}'.format(cyg_cache_dir))
# options.append('--site ftp://ftp.cygwinports.org/pub/cygwinports/')
# options.append('--pubkey http://cygwinports.org/ports.gpg')
options.append('--site ftp://mirrors.kernel.org/sourceware/cygwin/')
if mirrors is None:
mirrors = {DEFAULT_MIRROR: DEFAULT_MIRROR_KEY}
for mirror, key in mirrors.items():
options.append('--site {}'.format(mirror))
if key:
options.append('--pubkey {}'.format(key))
options.append('--no-desktop')
options.append('--quiet-mode')
options.append('--disable-buggy-antivirus')
@ -150,9 +155,7 @@ def _run_silent_cygwin(cyg_arch='x86_64', args=None):
def _cygcheck(args, cyg_arch='x86_64'):
'''
Runs the cygcheck executable
'''
"""Run the cygcheck executable."""
bashcmd = ' '.join([
os.sep.join(['c:', _get_cyg_dir(cyg_arch), 'bin', 'bash']),
'--login', '-c'])
@ -170,9 +173,10 @@ def _cygcheck(args, cyg_arch='x86_64'):
def install(packages=None,
cyg_arch='x86_64'):
'''
Installs one or several packages.
cyg_arch='x86_64',
mirrors=None):
"""
Install one or several packages.
packages : None
The packages to install
@ -186,7 +190,7 @@ def install(packages=None,
.. code-block:: bash
salt '*' cyg.install dos2unix
'''
"""
args = []
# If we want to install packages
if packages is not None:
@ -196,12 +200,13 @@ def install(packages=None,
# install just the base system
_run_silent_cygwin(cyg_arch=cyg_arch)
return _run_silent_cygwin(cyg_arch=cyg_arch, args=args)
return _run_silent_cygwin(cyg_arch=cyg_arch, args=args, mirrors=mirrors)
def uninstall(packages,
cyg_arch='x86_64'):
'''
cyg_arch='x86_64',
mirrors=None):
"""
Uninstall one or several packages.
packages
@ -216,22 +221,20 @@ def uninstall(packages,
.. code-block:: bash
salt '*' cyg.uninstall dos2unix
'''
LOG.debug('Entered cyg.uninstall')
"""
args = []
if packages is not None:
LOG.debug('We have packages: {0}'.format(packages))
args.append('--remove-packages {pkgs}'.format(pkgs=packages))
LOG.debug('args: {0}'.format(args))
if not _check_cygwin_installed(cyg_arch):
LOG.debug('We\'re convinced cygwin isn\'t installed')
return True
return _run_silent_cygwin(cyg_arch=cyg_arch, args=args)
return _run_silent_cygwin(cyg_arch=cyg_arch, args=args, mirrors=mirrors)
def update(cyg_arch='x86_64'):
'''
def update(cyg_arch='x86_64', mirrors=None):
"""
Update all packages.
cyg_arch : x86_64
@ -243,7 +246,7 @@ def update(cyg_arch='x86_64'):
.. code-block:: bash
salt '*' cyg.update
'''
"""
args = []
args.append('--upgrade-also')
@ -253,11 +256,11 @@ def update(cyg_arch='x86_64'):
could not update'.format(cyg_arch))
return False
return _run_silent_cygwin(cyg_arch=cyg_arch, args=args)
return _run_silent_cygwin(cyg_arch=cyg_arch, args=args, mirrors=mirrors)
def list_(package='', cyg_arch='x86_64'):
'''
"""
List locally installed packages.
package : ''
@ -272,13 +275,13 @@ def list_(package='', cyg_arch='x86_64'):
.. code-block:: bash
salt '*' cyg.list
'''
"""
pkgs = {}
args = ' '.join(['-c', '-d', package])
stdout = _cygcheck(args, cyg_arch=cyg_arch)
lines = []
if isinstance(stdout, str):
lines = stdout.splitlines()
lines = str(stdout).splitlines()
for line in lines:
match = re.match(r'^([^ ]+) *([^ ]+)', line)
if match:
@ -289,7 +292,7 @@ def list_(package='', cyg_arch='x86_64'):
# def sources_add(source_uri, ruby=None, runas=None):
# '''
# """
# Add a gem source.
# source_uri
@ -304,13 +307,13 @@ def list_(package='', cyg_arch='x86_64'):
# .. code-block:: bash
# salt '*' gem.sources_add http://rubygems.org/
# '''
# """
# return _gem('sources --add {source_uri}'.
# format(source_uri=source_uri), ruby, runas=runas)
# def sources_remove(source_uri, ruby=None, runas=None):
# '''
# """
# Remove a gem source.
# source_uri
@ -325,13 +328,13 @@ def list_(package='', cyg_arch='x86_64'):
# .. code-block:: bash
# salt '*' gem.sources_remove http://rubygems.org/
# '''
# """
# return _gem('sources --remove {source_uri}'.
# format(source_uri=source_uri), ruby, runas=runas)
# def sources_list(ruby=None, runas=None):
# '''
# """
# List the configured gem sources.
# ruby : None
@ -344,6 +347,6 @@ def list_(package='', cyg_arch='x86_64'):
# .. code-block:: bash
# salt '*' gem.sources_list
# '''
# """
# ret = _gem('sources', ruby, runas=runas)
# return [] if ret is False else ret.splitlines()[2:]

View File

@ -1,7 +1,5 @@
# -*- coding: utf-8 -*-
'''
Installation of Cygwin packages
===============================
"""
Installation of Cygwin packages.
A state module to manage cygwin packages. Packages can be installed
or removed.
@ -10,22 +8,24 @@ or removed.
dos2unix:
cyg.installed
'''
"""
import logging
# Import salt libs
import salt.utils
LOG = logging.getLogger(__name__)
def __virtual__():
'''
Only load if cyg module is available in __salt__
'''
"""Only load if cyg module is available in __salt__."""
return 'cyg.list' in __salt__
def installed(name,
cyg_arch='x86_64'):
'''
cyg_arch='x86_64',
mirrors=None):
"""
Make sure that a package is installed.
name
@ -34,16 +34,23 @@ def installed(name,
cyg_arch : x86_64
The cygwin architecture to install the package into.
Current options are x86 and x86_64
'''
mirrors : None
List of mirrors to check.
None will use a default mirror (kernel.org)
"""
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
if cyg_arch not in ['x86', 'x86_64']:
return _fail(ret,
'The \'cyg_arch\' argument must\
be one of \'x86\' or \'x86_64\''
)
be one of \'x86\' or \'x86_64\'')
if not __salt__['cyg.check_valid_package'](name, cyg_arch=cyg_arch):
LOG.debug('Installed State: Initial Mirror list: {0}'.format(mirrors))
if not __salt__['cyg.check_valid_package'](name,
cyg_arch=cyg_arch,
mirrors=mirrors):
ret['result'] = False
ret['comment'] = 'Invalid package name.'
return ret
@ -60,7 +67,8 @@ def installed(name,
return ret
if __salt__['cyg.install'](name,
cyg_arch=cyg_arch):
cyg_arch=cyg_arch,
mirrors=mirrors):
ret['result'] = True
ret['changes'][name] = 'Installed'
ret['comment'] = 'Package was successfully installed'
@ -71,8 +79,8 @@ def installed(name,
return ret
def removed(name, cyg_arch='x86_64'):
'''
def removed(name, cyg_arch='x86_64', mirrors=None):
"""
Make sure that a package is not installed.
name
@ -81,21 +89,26 @@ def removed(name, cyg_arch='x86_64'):
cyg_arch : x86_64
The cygwin architecture to remove the package from.
Current options are x86 and x86_64
'''
mirrors : None
List of mirrors to check.
None will use a default mirror (kernel.org)
"""
ret = {'name': name, 'result': None, 'comment': '', 'changes': {}}
if cyg_arch not in ['x86', 'x86_64']:
return _fail(ret,
'The \'cyg_arch\' argument must\
be one of \'x86\' or \'x86_64\''
)
be one of \'x86\' or \'x86_64\'')
if not __salt__['cyg.check_valid_package'](name, cyg_arch=cyg_arch):
if not __salt__['cyg.check_valid_package'](name,
cyg_arch=cyg_arch,
mirrors=mirrors):
ret['result'] = False
ret['comment'] = 'Invalid package name.'
return ret
if name not in __salt__['cyg.list'](name, cyg_arch):
if name not in __salt__['cyg.list'](name, cyg_arch, mirrors):
ret['result'] = True
ret['comment'] = 'Package is not installed.'
return ret
@ -113,27 +126,37 @@ def removed(name, cyg_arch='x86_64'):
return ret
def updated(cyg_arch='x86_64'):
'''
def updated(name=None, cyg_arch='x86_64', mirrors=None):
"""
Make sure all packages are up to date.
name : None
No affect, salt fails poorly without the arg available
cyg_arch : x86_64
The cygwin architecture to update.
Current options are x86 and x86_64
'''
mirrors : None
List of mirrors to check.
None will use a default mirror (kernel.org)
"""
ret = {'name': 'cyg.updated', 'result': None, 'comment': '', 'changes': {}}
if cyg_arch not in ['x86', 'x86_64']:
return _fail(ret,
'The \'cyg_arch\' argument must\
be one of \'x86\' or \'x86_64\''
)
be one of \'x86\' or \'x86_64\'')
if __opts__['test']:
ret['comment'] = 'All packages would have been updated'
return ret
if not mirrors:
LOG.warn('No mirror given, using the default.')
before = __salt__['cyg.list'](cyg_arch=cyg_arch)
if __salt__['cyg.update'](cyg_arch):
if __salt__['cyg.update'](cyg_arch, mirrors=mirrors):
after = __salt__['cyg.list'](cyg_arch=cyg_arch)
differ = DictDiffer(after, before)
ret['result'] = True
@ -162,7 +185,8 @@ http://stackoverflow.com/questions/1165352/fast-comparison-between-two-python-di
class DictDiffer(object):
"""
Calculate the difference between two dictionaries as:
Calculate the difference between two dictionaries.
(1) items added
(2) items removed
(3) keys same in both but changed values
@ -170,6 +194,7 @@ class DictDiffer(object):
"""
def __init__(self, current_dict, past_dict):
"""Iitialize the differ."""
self.current_dict, self.past_dict = current_dict, past_dict
self.current_keys, self.past_keys = [
set(d.keys()) for d in (current_dict, past_dict)
@ -177,33 +202,23 @@ class DictDiffer(object):
self.intersect = self.current_keys.intersection(self.past_keys)
def same(self):
'''
True if the two dicts are the same
'''
"""True if the two dicts are the same."""
return self.current_dict == self.past_dict
def added(self):
'''
Returns a set of additions to past_dict
'''
"""Return a set of additions to past_dict."""
return self.current_keys - self.intersect
def removed(self):
'''
Returns a set of things removed from past_dict
'''
"""Return a set of things removed from past_dict."""
return self.past_keys - self.intersect
def changed(self):
'''
Returns a set of the keys with changed values
'''
"""Return a set of the keys with changed values."""
return set(o for o in self.intersect
if self.past_dict[o] != self.current_dict[o])
def unchanged(self):
'''
Returns a set of the keys with unchanged values
'''
"""Return a set of the keys with unchanged values."""
return set(o for o in self.intersect
if self.past_dict[o] == self.current_dict[o])