Skip to content
config.py 5.5 KiB
Newer Older
Seblu's avatar
Seblu committed
# -*- python -*-
Seblu's avatar
Seblu committed
# -*- coding: utf-8 -*-
# Started 30/05/2011 by Seblu <seblu@seblu.net>

'''
InstallSystems Configuration files class
'''

import os
Seblu's avatar
Seblu committed
import sys
Seblu's avatar
Seblu committed
from ConfigParser import RawConfigParser
from installsystems.printer import *
from installsystems.repository import RepositoryConfig
Seblu's avatar
Seblu committed

Seblu's avatar
Seblu committed

Seblu's avatar
Seblu committed
class ConfigFile(object):
Seblu's avatar
Seblu committed
    '''
    Configuration File base class
    '''
Seblu's avatar
Seblu committed

Seblu's avatar
Seblu committed
    def __init__(self, filename):
        '''
Seblu's avatar
Seblu committed
        filename can be full path to config file or a name in config directory
Seblu's avatar
Seblu committed
        '''
        #try to get filename in default config dir
        if os.path.isfile(filename):
Seblu's avatar
Seblu committed
            self.path = os.path.abspath(filename)
Seblu's avatar
Seblu committed
        else:
Seblu's avatar
Seblu committed
            self.path = self._config_path(filename)
Seblu's avatar
Seblu committed
        self.reload()

Seblu's avatar
Seblu committed
    def reload():
        '''
        Reload configuration from file
        '''
        raise NotImplementedError

    def _config_path(self, name):
        '''
        Return path of the best config file
        '''
        for cf in [ os.path.join(os.path.expanduser("~/.config/installsystems/%s.conf" % name)),
                    "/etc/installsystems/%s.conf" % name ]:
            if (os.path.isfile(cf) and os.access(cf, os.R_OK)):
Seblu's avatar
Seblu committed
                return cf
        return None

Seblu's avatar
Seblu committed

class MainConfigFile(ConfigFile):
    '''
    Program configuration file
    '''

Seblu's avatar
Seblu committed
    def __init__(self, filename, prefix=os.path.basename(sys.argv[0])):
        self.prefix = prefix
        ConfigFile.__init__(self, filename)

Seblu's avatar
Seblu committed
    def reload(self):
        '''
        Load/Reload config file
        '''
        self._config = {}
Seblu's avatar
Seblu committed
        # loading default options
        self._config["cache"] = self.cache
Seblu's avatar
Seblu committed
        # loading config file if exists
        if self.path is None:
Seblu's avatar
Seblu committed
            debug("No main config file to load")
Seblu's avatar
Seblu committed
            return
        debug("Loading main config file: %s" % self.path)
Seblu's avatar
Seblu committed
        try:
            cp = RawConfigParser()
            cp.read(self.path)
            # main configuration
Seblu's avatar
Seblu committed
            if cp.has_section(self.prefix):
Seblu's avatar
Seblu committed
                self._config.update(cp.items(self.prefix))
Seblu's avatar
Seblu committed
        except Exception as e:
            raise Exception("Unable load main config file %s: %s" % (self.path, e))
Seblu's avatar
Seblu committed

    def merge(self, namespace):
        '''
        Merge current loaded option with a namespace from argparse
        '''
        for option, value in self._config.items():
            if not hasattr(namespace, option):
                setattr(namespace, option, value)
            elif getattr(namespace, option) == None:
                # we need to handle boolean differently
                if option in ("debug", "quiet", "no_cache", "no_color"):
                    setattr(namespace, option, value.lower() not in ("false", "no", "0"))
                # we need to handle integer differently
                elif option in ("timeout"):
                    try:
                        n = int(value)
                    except ValueError:
                        raise Exception("Invalid %s: Not a number" % option)
                    setattr(namespace, option, n)
                # we can handle string more carefuly
                elif option in ("cache", "repo_filter", "repo_config"):
                    setattr(namespace, option, value)
                else:
                    warn("Invalid option %s in %s, skipped" % (option, self.path))
Seblu's avatar
Seblu committed

Seblu's avatar
Seblu committed
    def _cache_paths(self):
        '''
        List all candidates to cache directories. Alive or not
        '''
Seblu's avatar
Seblu committed
        dirs = [os.path.expanduser("~/.cache"), "/var/tmp", "/tmp"]
        # we have an additional directry if we are root
Seblu's avatar
Seblu committed
        if os.getuid() == 0:
            dirs.insert(0, "/var/cache")
        return map(lambda x: os.path.join(x, self.prefix), dirs)

    def _cache_path(self):
        '''
        Return path of the best cache directory
        '''
        # find a good directory
        for di in self._cache_paths():
            if (os.path.exists(di)
                and os.path.isdir(di)
                and os.access(di, os.R_OK|os.W_OK|os.X_OK)):
                return di
        return None

Seblu's avatar
Seblu committed
    @property
    def cache(self):
Seblu's avatar
Seblu committed
        '''
        Find a cache directory
        '''
Seblu's avatar
Seblu committed
        if "cache" in self._config:
            return self._config["cache"]
        if self._cache_path() is None:
            for di in self._cache_paths():
                try:
                    os.mkdir(di)
                    break
                except Exception as e:
                    debug("Unable to create %s: %s" % (di, e))
        return self._cache_path()

Seblu's avatar
Seblu committed

class RepoConfigFile(ConfigFile):
    '''
    Repository Configuration class
    '''

    def reload(self):
        '''
        Load/Reload config file
        '''
        # seting default config
        self._config = {}
        self._repos = []
Seblu's avatar
Seblu committed
        # if no file nothing to load
        if self.path is None:
            return
Seblu's avatar
Seblu committed
        # loading config file if exists
        debug("Loading repository config file: %s" % self.path)
Seblu's avatar
Seblu committed
        try:
            cp = RawConfigParser()
            cp.read(self.path)
            # each section is a repository
            for rep in cp.sections():
                # check if its a repo section
                if "path" not in cp.options(rep):
                    continue
                # get all options in repo
                self._repos.append(RepositoryConfig(rep, **dict(cp.items(rep))))
        except Exception as e:
            raise Exception("Unable to load repository file %s: %s" % (self.path, e))
Seblu's avatar
Seblu committed

Seblu's avatar
Seblu committed
    @property
    def repos(self):
Seblu's avatar
Seblu committed
        '''
        Get a list of repository available
        '''
        # deep copy
        return list(self._repos)