From dca903db11f899aa19e43a060edbe0a093fbbd39 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 31 Jan 2013 01:52:12 +0000 Subject: Config file parsing and creating utility. This will need to be refactored to use JSON, following leap_client, and may tie into soledad. --- src/leap/util/config.py | 170 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 128 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/leap/util/config.py b/src/leap/util/config.py index ab91a60..a762853 100644 --- a/src/leap/util/config.py +++ b/src/leap/util/config.py @@ -1,69 +1,155 @@ #! -*- encoding: utf-8 -*- """ -xxx fill me in +Config file utilities. + +This module has an :attr:`config_filename`, which can be used to set the +filename outside of function calls: + + >>> from leap.mx.util import config + >>> config.config_filename = "blahblah.yaml" + +If not set anywhere, it will default to using the top level repository +directory, i.e. "/.../leap_mx/leap_mx.conf", and will create that file with +the default settings if it does not exist. + +The config file can be loaded/created with :func:`config.loadConfig`: + + >>> config.loadConfig() + +Once the config file is loaded, this module presents a highly object-oriented +interface, so that sections taken from the config file become attribute of +this module, and the name of their respective settings become attributes of +the section names. Like this: + + >>> print config.basic.postfix_port + 465 + +@authors: Isis Lovecruft, 0x2cdb8b35 +@version: 0.0.1 +@license: see included LICENSE file """ + import os import yaml -from leap.util import log, version +## xxx only install/import this in *nix +from xdg import BaseDirectory -config_filename = 'mx.conf' +from leap.util import log, version, Storage +from leap.util.exceptions import MissingConfig, UnsupportedOS -class MissingConfig(Exception): - """Raised when the config file cannot be found.""" - def __init__(self, message=None, config_file=None): - if message: - return - else: - self.message = "Cannot locate config file" - if config_file: - self.message += " %s" % config_file - self.message += "." -def getConfigFilename(dir=None, file=None): +def _create_config_file(file): """ xxx fill me in """ - if not dir: - dir = version.getRepoDir() - if not file: - file = config_filename - return os.path.join(dir, file) - -def createConfigFile(config_file=None): - """ - xxx fill me in - """ - if not config_file: - config_file = getConfigFilename() - - if not os.path.isfile(config_file): - with open(config_file, 'w+') as conf: - conf.write(""" + with open(file, 'w+') as conf: + conf.write(""" # # mx.conf # ======= # Configurable options for the leap_mx encrypting mail exchange. # """) - conf.flush() + conf.flush() + try: + assert os.path.isfile(file), "Config file %s not created!" % file + except AssertionError, ae: + raise SystemExit(ae.message) else: - log.debug("Config file %s already present." % config_file) + return file -def loadConfigFile(config_file=None): +def _get_config_filename(filename=None, use_dot_config_directory=False): """ - xxx fill me in + Get the full path and filename of the config file. """ - if not config_file: - config_file = getConfigFilename() + platform = version.getClientPlatform()[0] + resource = version.name - if os.path.isfile(config_file): - with open(config_file, 'a+') as conf: + ## Oh hell, it could be said only to beguile: + ## That windoze users are capable of editing a .conf file. + ## Also, what maddened wingnut would be so fool + ## To run a mail exchange on a windoze nodule? + ## I'm ignoring these loons for now. And pardon if I seem jaded, + ## But srsly, this and that solaris sh*t should be deprecated. + if not platform.endswith('LINUX') and not platform.endswith('BSD'): + raise UnsupportedOS("Sorry, your operating system isn't supported.") + + ## If not given, default to the application's name + '.conf' + if not filename: + filename = resource + ".conf" + + where = None + if not use_dot_config_directory: + repo_dir = version.getRepoDir() + where = os.path.abspath(repo_dir) + ## Use ~/.config/ instead: + else: + dot_config_dirs = BaseDirectory.xdg_config_dirs + for dir in dot_config_dirs: + our_dir = os.path.join(dir, resource) + if os.path.isdir(our_dir): + if filename in os.listdir(our_dir): + where = os.path.abspath(our_dir) + if not where: + where = BaseDirectory.save_config_path(resource) + + conffile = os.path.join(where, filename) + try: + with open(conffile) as cf: pass + except IOError: + conffile = _create_config_file(conffile) + finally: + return conffile + +def loadConfig(filename=config_filename): + """ + Some of this is taken from OONI config code for now, and so this should be + refacotored, along with the leap_client config code, so that we have + similarly structured config files. It is perhaps desirable to also use + soledad as a backend for remote setup and maintainance, and thus this code + will need to hook into u1db (and potentially "pysqlcipher"). + + Excuse the yaml for now, I just wanted something that works. + + @param filename: (optional) If provided, use this filename. + """ + if not filename: + filename = _get_config_filename() + + if os.path.isfile(filename): + with open(filename, 'a+') as conf: config_contents = '\n'.join(conf.readlines()) configuration = yaml.safe_load(config_contents) + + ## These become objects with their keys loaded as attributes: + ## + ## from leap.util import config + ## config.basic.foo = bar + ## + basic = Storage() + try: + for k, v in configuration['basic'].items(): + basic[k] = v + except AttributeError: + pass + + advanced = Storage() + try: + for k, v in configuration['advanced'].items(): + advanced[k] = v + except AttributeError: + pass + + return basic, advanced else: - createConfigFile(config_file) + raise MissingConfig("Could not load config file.") + + +## This is the name of the config file to use: +## If not set, it defaults to 'leap_mx/leap_mx.conf' +if not config_filename: + config_filename = _get_config_filename() +else: + config_filename = _get_config_filename(filename=config_filename) - ## xxx finish load config - ## ask kali if we're using yaml or json or what? - ## xxx kali says json, so ixnay on the amlya bits -- cgit v1.2.3