import os import shutil import sys import argparse import logging import logging.config if sys.version_info < (3, 0): from ConfigParser import RawConfigParser, MissingSectionHeaderError else: from configparser import RawConfigParser, MissingSectionHeaderError from baboon.baboon.fmt import cerr, cwarn, csuccess from baboon.baboon.dictconf import LOGGING, PARSER from baboon.common.config import get_config_args, get_config_file from baboon.common.config import init_config_log from baboon.common.errors.baboon_exception import ConfigException SCMS = ('git',) def check_server(add_mandatory_fields=[]): """ Checks the server section in the config dict. The add_mandatory_fields list allows to add more mandatory fields. """ mandatory_keys = set(['master', 'pubsub'] + add_mandatory_fields) _check_config_section('server', mandatory_keys) def check_user(add_mandatory_fields=[]): """ Checks the user section in the config dict. The add_mandatory_fields list allows to add more mandatory fields. """ mandatory_keys = set(['jid', 'passwd'] + add_mandatory_fields) _check_config_section('user', mandatory_keys) def check_project(add_mandatory_fields=[]): """ Checks if there's at least one configured project. The add_mandatory_fields list allows to add more mandatory fields to validate all configured projects. """ mandatory_keys = set(['path', 'scm', 'enable'] + add_mandatory_fields) projects = config.get('projects', {}) # Ensure there's at least one project. if not len(projects): raise ConfigException("No project configured.") # For all projects, ensure all mandatory fields are present. mandatory_keys = set(['path', 'scm', 'enable'] + add_mandatory_fields) for project in projects: _check_config_section(project, mandatory_keys, prefix='projects') def check_config(add_mandatory_server_fields=[], add_mandatory_user_fields=[], add_mandatory_project_fields=[]): """ Checks all the mandatory fields in all sections. """ check_server(add_mandatory_fields=add_mandatory_server_fields) check_user(add_mandatory_fields=add_mandatory_user_fields) check_project(add_mandatory_fields=add_mandatory_project_fields) def dump(): """ Dumps the config dict to the user's configuration file ~/.baboonrc. If the file already exists, it's copied to ~/.baboonrc.old and the original file is overwritten. """ # Don't dump the config if the --nosave arg is present. if config['parser'].get('nosave', False): return baboonrc_path = os.path.expanduser('~/.baboonrc') # Override the default baboonrc_path if the --config arg is present. if config['parser'].get('configpath'): baboonrc_path = config['parser']['configpath'] try: # Dump the config file. with open(baboonrc_path, 'w') as fd: print >>fd, get_dumped_user() print >>fd, get_dumped_server() print >>fd, get_dumped_projects() print >>fd, get_dumped_example_project() csuccess("The new configuration file is written in %s\n" % baboonrc_path) except EnvironmentError as err: cerr("Cannot dump the configuration. Cause:\n%s" % err) def get_dumped_server(): """ Returns a dumped representation of the server section. """ return '\n'.join(_get_dumped_section('server')) + '\n' def get_dumped_user(): """ Returns a dumped representation of the user section. """ return '\n'.join(_get_dumped_section('user')) + '\n' def get_dumped_projects(): """ Returns a dumped representation of the projects section. """ content = [] for project, opts in config['projects'].iteritems(): dumped_section = _get_dumped_section(project, prefix='projects') content.append('\n'.join(dumped_section) + '\n') return '\n'.join(content) def get_dumped_example_project(): """ Returns a dumped representation of project configuration example. """ return """# Example of project definition. #[awesome_project] \t# The project name on the baboon server. #path = /pathto/project # The project path of your system. #scm = git \t\t# The source code manager you use for this project. #enable = 1 \t\t# You want baboon to actually watch this project. """ def get_baboon_config(): """ Returns the baboon full dict configuration. """ arg_attrs = get_config_args(PARSER) file_attrs = get_config_file(arg_attrs, 'baboonrc') init_config_log(arg_attrs, LOGGING) config = { 'parser': arg_attrs, 'projects': {} } # The known section tuple contains the list of sections to put directly # as a root key in the config dict. Other sections will be interpreted as a # project and placed into the 'projects' key. known_section = ('server', 'user') for key in file_attrs: if key in known_section: config[key] = file_attrs[key] else: # It's a project, add the attributes to the projects key. config['projects'][key] = file_attrs[key] # If a hostname has been defined in the command line, we need to override # all fields that depend on it. depend_hostnames = {} if 'server' in config: depend_hostnames['server'] = ['pubsub', 'streamer', 'master'] if 'user' in config: depend_hostnames['user'] = ['jid'] # Search and replace default hostname by hostname defined from the command # line. for section, fields in depend_hostnames.iteritems(): for field in fields: try: cur_value = config[section][field] config[section][field] = cur_value.replace( 'baboon-project.org', config['parser']['hostname']) except KeyError: # Just pass the keyerror exception. If it's a mandatory field, # the error will be raised correctly later. pass return config def _check_config_section(section, mandatory_keys, prefix=None): # If the prefix is provided, use the config['prefix'] src dict instead of # directly the src config. Useful for projects sections. src = config[prefix] if prefix else config # Ensure the section exists. if section not in src: raise ConfigException("'%s' section is missing." % section) try: # Ensure all mandatory keys exist with a non-empty value. If not, # raised a appropriate message exception. for key, value in [(x, src[section][x]) for x in mandatory_keys]: if not value: raise ConfigException("Value of the '%s' field cannot be " "empty." % key) except KeyError as err: raise ConfigException("'%s' field required in the '%s' section " % (err.message, section)) def _get_dumped_section(section, prefix=None): try: src = config[prefix] if prefix else config content = ['[%s]' % section] for option, value in src['%s' % section].iteritems(): content.append('%s = %s' % (option, value)) return content except KeyError: # Ignore all the section content if a KeyError exception is raised. return '' config = get_baboon_config()