diff options
Diffstat (limited to 'overlord/config.py')
-rw-r--r-- | overlord/config.py | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/overlord/config.py b/overlord/config.py new file mode 100644 index 0000000..4caf83c --- /dev/null +++ b/overlord/config.py @@ -0,0 +1,441 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +################################################################################# +# overlord CONFIGURATION +################################################################################# +# File: config.py +# +# Handles overlord configuration +# +# Copyright: +# (c) 2005 - 2009 Gunnar Wrobel +# (c) 2009 Sebastian Pipping +# Distributed under the terms of the GNU General Public License v2 +# +# Author(s): +# Gunnar Wrobel <wrobel@gentoo.org> +# Sebastian Pipping <sebastian@pipping.org> +# Brian Dolbec <brian.dolbec@gmail.com> +# +'''Defines the configuration options and provides parsing functionality.''' + +__version__ = "$Id: config.py 286 2007-01-09 17:48:23Z wrobel $" + +#=============================================================================== +# +# Dependencies +# +#------------------------------------------------------------------------------- + +import sys, ConfigParser + +from optparse import OptionParser, OptionGroup +from overlord.debug import OUT +from overlord.version import VERSION + +#=============================================================================== +# +# Class Config +# +#------------------------------------------------------------------------------- + +_USAGE = """ + overlord (-a|-d|-s|-i) (OVERLAY|ALL) + overlord -f [-o URL] + overlord (-l|-L|-S)""" + +class BareConfig(object): + '''Handles the configuration only.''' + + def __init__(self, output=None, stdout=None, stdin=None, stderr=None): + ''' + Creates a bare config with defaults and a few output options. + + >>> a = BareConfig() + >>> a['overlays'] + '\\nhttp://www.gentoo.org/proj/en/overlays/repositories.xml' + >>> sorted(a.keys()) + ['bzr_command', 'cache', 'config', 'cvs_command', 'darcs_command', + 'git_command', 'local_list', 'make_conf', 'mercurial_command', + 'nocheck', 'overlays', 'proxy', 'quietness', 'rsync_command', 'storage', + 'svn_command', 'tar_command', 'umask', 'width'] + ''' + self._defaults = {'config' : '/etc/overlord/overlord.cfg', + 'storage' : '/var/lib/layman', + 'cache' : '%(storage)s/cache', + 'local_list': '%(storage)s/overlays.xml', + 'make_conf' : '%(storage)s/make.conf', + 'nocheck' : 'yes', + 'proxy' : '', + 'umask' : '0022', + 'overlays' : + 'http://www.gentoo.org/proj/en/overlays/repositories.xml', + 'bzr_command': '/usr/bin/bzr', + 'cvs_command': '/usr/bin/cvs', + 'darcs_command': '/usr/bin/darcs', + 'git_command': '/usr/bin/git', + 'g-common_command': '/usr/bin/g-common', + 'mercurial_command': '/usr/bin/hg', + 'rsync_command': '/usr/bin/rsync', + 'svn_command': '/usr/bin/svn', + 'tar_command': '/bin/tar' + } + self._options = { + 'stdout': stdout if stdout else sys.stdout, + 'stdin': stdin if stdin else sys.stdin, + 'stderr': stderr if stderr else sys.stderr, + 'output': output if output else OUT, + 'quietness': '4', + 'width': 0, + 'verbose': False, + 'quiet': False, + } + + + def keys(self): + '''Special handler for the configuration keys. + ''' + self._options['output'].debug('Retrieving BareConfig options', 8) + keys = [i for i in self._options] + self._options['output'].debug('Retrieving BareConfig defaults', 8) + keys += [i for i in self._defaults + if not i in keys] + self._options['output'].debug('Retrieving BareConfig done...', 8) + return keys + + + def get_defaults(self): + """returns our defaults dictionary""" + return self._defaults + + + def get_option(self, key): + """returns the current option's value""" + return self.__getitem__(key) + + + def set_option(self, option, value): + """Sets an option to the value """ + self._options[option] = value + + + def __getitem__(self, key): + self._options['output'].debug('Retrieving BareConfig option', 8) + if (key in self._options + and not self._options[key] is None): + return self._options[key] + self._options['output'].debug('Retrieving BareConfig default', 8) + if key in self._defaults: + if '%(storage)s' in self._defaults[key]: + return self._defaults[key] %{'storage': self._defaults['storage']} + return self._defaults[key] + return None + + + + +class ArgsParser(object): + '''Handles the configuration and option parser.''' + + def __init__(self, args=None, output=None, + stdout=None, stdin=None, stderr=None): + ''' + Creates and describes all possible polymeraZe options and creates + a debugging object. + + >>> import os.path + >>> here = os.path.dirname(os.path.realpath(__file__)) + >>> sys.argv.append('--config') + >>> sys.argv.append(here + '/../etc/overlord.cfg') + >>> a = ArgsParser() + >>> a['overlays'] + '\\nhttp://www.gentoo.org/proj/en/overlays/repositories.xml' + >>> sorted(a.keys()) + ['bzr_command', 'cache', 'config', 'cvs_command', 'darcs_command', + 'git_command', 'local_list', 'make_conf', 'mercurial_command', + 'nocheck', 'overlays', 'proxy', 'quietness', 'rsync_command', 'storage', + 'svn_command', 'tar_command', 'umask', 'width'] + ''' + if args == None: + args = sys.argv + + self.stdout = stdout if stdout else sys.stdout + self.stderr = stderr if stderr else sys.stderr + self.stdin = stdin if stdin else sys.stdin + self.output = output if output else OUT + + self.bare_config = BareConfig(self.output, self.stdout, + self.stdin, self.stderr) + self.defaults = self.bare_config.get_defaults() + #print self.defaults + + self.parser = OptionParser( + usage = _USAGE, + version = VERSION) + + #----------------------------------------------------------------- + # Main Options + + group = OptionGroup(self.parser, + '<Actions>') + + group.add_option('-a', + '--add', + action = 'append', + help = 'Add the given overlay from the cached remote li' + 'st to your locally installed overlays.. Specify "ALL" ' + 'to add all overlays from the remote list.') + + group.add_option('-d', + '--delete', + action = 'append', + help = 'Remove the given overlay from your locally inst' + 'alled overlays. Specify "ALL" to remove all overlays') + + group.add_option('-s', + '--sync', + action = 'append', + help = 'Update the specified overlay. Use "ALL" as para' + 'meter to synchronize all overlays') + + group.add_option('-i', + '--info', + action = 'append', + help = 'Display information about the specified overlay' + '.') + + group.add_option('-S', + '--sync-all', + action = 'store_true', + help = 'Update all overlays.') + + group.add_option('-L', + '--list', + action = 'store_true', + help = 'List the contents of the remote list.') + + group.add_option('-l', + '--list-local', + action = 'store_true', + help = 'List the locally installed overlays.') + + group.add_option('-f', + '--fetch', + action = 'store_true', + help = 'Fetch a remote list of overlays. This option is' + ' deprecated. The fetch operation will be performed by ' + 'default when you run sync, sync-all, or list.') + + group.add_option('-n', + '--nofetch', + action = 'store_true', + help = 'Do not fetch a remote list of overlays.') + + group.add_option('-p', + '--priority', + action = 'store', + help = 'Use this with the --add switch to set the prior' + 'ity of the added overlay. This will influence the sort' + 'ing order of the overlays in the PORTDIR_OVERLAY varia' + 'ble.') + + self.parser.add_option_group(group) + + #----------------------------------------------------------------- + # Additional Options + + group = OptionGroup(self.parser, + '<Path options>') + + group.add_option('-c', + '--config', + action = 'store', + help = 'Path to the config file [default: ' \ + + self.defaults['config'] + '].') + + group.add_option('-o', + '--overlays', + action = 'append', + help = 'The list of overlays [default: ' \ + + self.defaults['overlays'] + '].') + + self.parser.add_option_group(group) + + #----------------------------------------------------------------- + # Output Options + + group = OptionGroup(self.parser, + '<Output options>') + + group.add_option('-v', + '--verbose', + action = 'store_true', + help = 'Increase the amount of output and describe the ' + 'overlays.') + + group.add_option('-q', + '--quiet', + action = 'store_true', + help = 'Yield no output. Please be careful with this op' + 'tion: If the processes spawned by overlord when adding o' + 'r synchronizing overlays require any input overlord will' + ' hang without telling you why. This might happen for e' + 'xample if your overlay resides in subversion and the S' + 'SL certificate of the server needs acceptance.') + + group.add_option('-N', + '--nocolor', + action = 'store_true', + help = 'Remove color codes from the overlord output.') + + group.add_option('-Q', + '--quietness', + action = 'store', + type = 'int', + default = '4', + help = 'Set the level of output (0-4). Default: 4. Once' + ' you set this below 2 the same warning as given for --' + 'quiet applies! ') + + group.add_option('-W', + '--width', + action = 'store', + type = 'int', + default = '0', + help = 'Sets the screen width. This setting is usually ' + 'not required as overlord is capable of detecting the ' + 'available number of columns automatically.') + + group.add_option('-k', + '--nocheck', + action = 'store_true', + help = 'Do not check overlay definitions and do not i' + 'ssue a warning if description or contact information' + ' are missing.') + + self.parser.add_option_group(group) + + #----------------------------------------------------------------- + # Debug Options + + self.output.cli_opts(self.parser) + + # Parse the command line first since we need to get the config + # file option. + if len(args) == 1: + print 'Usage:%s' % _USAGE + sys.exit(0) + + (self.options, remain_args) = self.parser.parse_args(args) + # remain_args starts with something like "bin/overlord" ... + if len(remain_args) > 1: + self.parser.error("Unhandled parameters: %s" + % ', '.join(('"%s"' % e) for e in remain_args[1:])) + + # handle debugging + self.output.cli_handle(self.options) + + # add output to the options + self.options.__dict__['output'] = self.output + + # add the std in/out/err to the options + self.options.__dict__['stdout'] = self.stdout + self.options.__dict__['stdin'] = self.stdin + self.options.__dict__['stderr'] = self.stderr + + + if self.options.__dict__['nocolor']: + self.output.color_off() + + # Fetch only an alternate config setting from the options + if not self.options.__dict__['config'] is None: + self.defaults['config'] = self.options.__dict__['config'] + + self.output.debug('Got config file at ' + self.defaults['config'], 8) + + # Now parse the config file + self.config = ConfigParser.ConfigParser(self.defaults) + self.config.add_section('MAIN') + + # handle quietness + if self['quiet']: + self.output.set_info_level(1) + self.output.set_warn_level(1) + self.defaults['quietness'] = 0 + elif 'quietness' in self.keys(): + self.output.set_info_level(int(self['quietness'])) + self.output.set_warn_level(int(self['quietness'])) + + self.output.debug('Reading config file at ' + self.defaults['config'], 8) + + self.config.read(self.defaults['config']) + + def __getitem__(self, key): + + if key == 'overlays': + overlays = '' + if (key in self.options.__dict__.keys() + and not self.options.__dict__[key] is None): + overlays = '\n'.join(self.options.__dict__[key]) + if self.config.has_option('MAIN', 'overlays'): + overlays += '\n' + self.config.get('MAIN', 'overlays') + if overlays: + return overlays + + self.output.debug('Retrieving option', 8) + + if (key in self.options.__dict__.keys() + and not self.options.__dict__[key] is None): + return self.options.__dict__[key] + + self.output.debug('Retrieving option', 8) + + if self.config.has_option('MAIN', key): + if key == 'nocheck': + if self.config.get('MAIN', key).lower() == 'yes': + return True + else: + return False + return self.config.get('MAIN', key) + + self.output.debug('Retrieving option', 8) + + if key in self.defaults.keys(): + return self.defaults[key] + + self.output.debug('Retrieving option', 8) + + return None + + def keys(self): + '''Special handler for the configuration keys.''' + + self.output.debug('Retrieving keys', 8) + + keys = [i for i in self.options.__dict__.keys() + if not self.options.__dict__[i] is None] + + self.output.debug('Retrieving keys', 8) + + keys += [name for name, _ in self.config.items('MAIN') + if not name in keys] + + self.output.debug('Retrieving keys', 8) + + keys += [i for i in self.defaults.keys() + if not i in keys] + + self.output.debug('Retrieving keys', 8) + + return keys + + +#=============================================================================== +# +# Testing +# +#------------------------------------------------------------------------------- + +if __name__ == '__main__': + import doctest + doctest.testmod(sys.modules[__name__]) |