diff roundup/config.py @ 604:13719594278b config-0-4-0-branch

I've re-worked the config structure a little so it's simpler (one less file) and added a unit test so we can be sure it's working.
author Richard Jones <richard@users.sourceforge.net>
date Wed, 06 Feb 2002 07:11:13 +0000
parents fdee2ff82b40
children
line wrap: on
line diff
--- a/roundup/config.py	Wed Feb 06 04:29:17 2002 +0000
+++ b/roundup/config.py	Wed Feb 06 07:11:13 2002 +0000
@@ -1,7 +1,36 @@
-import sys
-import os
-import ConfigParser
-import string
+'''Organise the configuration files for roundup installations.
+
+There's two configuration files of interest to any given roundup instance:
+
+roundup.rc:
+  This is the global configuration file. It specifies:
+    . default configuration variable values
+    . instance names and locations
+
+<instance home>/config.rc:
+  This defines the configuration overrides for the instance
+
+Config values are determined in order:
+ 1. instance config application-specific section:
+     'MAIL GATEWAY'
+     'HTTP SERVER'
+     'CGI'
+     'ADMIN'
+ 2. instance config 'DEFAULT' with some added vars:
+     'instance_home': the home dir
+ 3. all the entries from the roundup.rc global '[DEFAULT]'
+ 4. pre-set application defaults (in this file)
+
+Some variables will raise errors if an attempt is made to look them up
+using the application defaults:
+  . mailhost
+  . mail_domain
+  . issue_tracker_email
+  . issue_tracker_web
+  . admin_email
+
+'''
+import sys, os, ConfigParser
 
 class Error(Exception):
     pass
@@ -13,38 +42,31 @@
     pass
 
 def debug_mode():
-    """
-    Returns the basic debug mode/level.
+    """Returns the basic debug mode/level.
     """
     return os.environ.get('ROUNDUP_DEBUG', 0)
 
 def loadBaseConfig():
-    """
-    Loads the base configuration for Roundup.
+    """Loads the base configuration for Roundup.
     """
     
-    c = ConfigParser.ConfigParser()
 
-    ##
-    ## CTB: this is where to search for all overrides, including
-    ##      system-specific files, registry settings, etc.
-    ##
-
+    # CTB: this is where to search for all overrides, including
+    #      system-specific files, registry settings, etc.
+    #
     # For the moment, search for the config file in
     #
+    #      ${ROUNDUP_CONF}/roundup.rc
     #      %(sys.prefix)s/share/roundup/roundup.rc,
-    #
-    # with ROUNDUP_CONF overriding it.
-    
+    # 
     filenames_to_check = []             # list of files to check:
     if os.environ.has_key('ROUNDUP_CONF'):
         filenames_to_check.append(os.environ['ROUNDUP_CONF'])
-        
-    filenames_to_check.append('%s/share/roundup/roundup.rc'%(sys.prefix,))
+    filenames_to_check.append('%s/share/roundup/roundup.rc'%sys.prefix)
 
+    # right, now try to get a config
     for filename in filenames_to_check:
         if os.path.exists(filename):
-            c.read(filename)
             break
     else:
         raise Error("could not find configuration file")
@@ -52,123 +74,87 @@
     if debug_mode():
         print 'Loaded configuration from "%s".'%(filename,)
 
-    # we also want to give a base path for other config file names;
-    # for the moment, make it the base path of the filename we chose.
-    base_path = os.path.dirname(filename)
-
-    return BaseConfig(c, base_path)
+    return BaseConfig(filename)
 
 class BaseConfig:
-    """
-    A container for the installation-wide roundup configuration.
+    """A container for the installation-wide roundup configuration.
     """
-    def __init__(self, c, base_path):
-        assert isinstance(c, ConfigParser.ConfigParser)
-        self.conf = c
-        self.base_path = base_path
+    def __init__(self, filename):
+        self.filename = filename
+        self.conf = ConfigParser.ConfigParser()
+        self.conf.read(filename)
 
     def get(self, group, attr):
         return self.conf.get(group, attr)
 
-    def loadInstances(self):
-        filename = string.strip(self.conf.get('base', 'instances'))
-
-        # if it looks like an absolute path, leave it alone; otherwise,
-        # add on the base path.
-        if filename[0] == '/' or filename[0] == '\\':
-            pass
-        else:
-            filename = os.path.normpath(self.base_path + '/' + filename)
-
-        defaults_dictionary = { 'roundup_conf_dir' : self.base_path }
-
-        c = ConfigParser.ConfigParser(defaults_dictionary)
-        c.read(filename)
-
-        return InstancesConfig(c, filename)
-
-class InstancesConfig:
-    """
-    A container for the installation-wide list of instances.
-    """
-    def __init__(self, c, filename=""):
-        assert isinstance(c, ConfigParser.ConfigParser)
-        self.conf = c
-        self.filename = filename
-
-        instance_names = {}
-        instance_dirs = {}
-        
-        for name in c.sections():
-            dir = c.get(name, 'homedir')
+    def listInstances(self):
+        return filter(lambda x:x!='BASE', self.conf.sections())
 
-            if instance_names.has_key(dir) or instance_dirs.has_key(name):
-                error_text = 'ERROR: dir/name correspondence is not unique (%s)'%(self.filename,)
-                raise ValueError(error_text)
-            
-            instance_dirs[name] = dir
-            instance_names[dir] = name
-
-        self.instance_dirs = instance_dirs
-        self.instance_names = instance_names
-
-    def getNames(self):
-        return self.instance_dirs.keys()
-
-    def getNameFromDir(self, dir):
-        if self.instance_names.has_key(dir):
-            return self.instance_names[dir]
-        else:
-            raise UnknownInstanceLocation(dir)
-
-    def getDirFromName(self, name):
-        return self.instance_dirs[name]
-
-    def loadConfig(self, name):
-        instance_dir = self.getDirFromName(name)
+    def loadInstanceConfig(self, home):
+        # set up the defaults for the instance config
+        defaults = {
+            'instance_home': home,
+            'http_port': '80',
+            'database': '%(instance_home)s/db',
+            'templates': '%(instance_home)s/html',
+            'log': '%(instance_home)s/log',
+            'filter_position': 'bottom',
+            'anonymous_access': 'deny',
+            'anonymous_register': 'deny',
+            'messages_to_author': 'no',
+            'email_signature_position': 'bottom',
+        }
+        for option in self.conf.options('BASE'):
+            defaults[option] = self.conf.get('BASE', option, 1)
         
-        defaults_file = self.conf.get(name, 'defaults')
-        if not os.path.exists(defaults_file):
-            raise NoInstanceConfigFile("defaults file %s does not exist"%(defaults_file,))
-        
-        config_file = self.conf.get(name, 'config')
-        if not os.path.exists(config_file):
-            raise NoInstanceConfigFile("%s does not exist"%(config_file,))
-
-        defaults_dictionary = { 'homedir' : instance_dir,
-                                'instance_name' : name,
-                              }
+        # make the instance config
+        inst = InstanceConfig(defaults)
+        inst.read(os.path.join(home, 'config.rc'))
+        inst.validate()
+        return inst
 
 
-        c = ConfigParser.ConfigParser(defaults_dictionary)
-        c.read(defaults_file)
-        c.read(config_file)
-
-        return InstanceConfig(c, name, instance_dir)
-
-class InstanceConfig:
-    """
-    A container for each per-instance configuration.
+class InstanceConfig(ConfigParser.ConfigParser):
+    """A container for each per-instance configuration.
     """
-    
-    def __init__(self, c, instanceName, instanceDirectory):
-        assert isinstance(c, ConfigParser.ConfigParser)
-        self.conf = c
-        self.name = instanceName
-        self.directory = instanceDirectory
+    def validate(self):
+        '''Make sure the config is complete
+        '''
+        assert self.has_option('BASE', 'instance_name')
+        assert self.has_option('BASE', 'mailhost')
+        assert self.has_option('BASE', 'mail_domain')
+        assert self.has_option('BASE', 'issue_tracker_email')
+        assert self.has_option('BASE', 'issue_tracker_web')
+        assert self.has_option('BASE', 'admin_email')
 
-    def get_name(self):
-        return self.name
+    def getBase(self, name):
+        '''Convenience wrapper
+        '''
+        return self.get('BASE', name)
+
+    def getMailGW(self, name):
+        '''Look up a var for the mail gateway
+        '''
+        return self.get('MAIL GATEWAY', name)
 
-    def get_directory(self):
-        return self.directory
+    def getHTTPServer(self, name):
+        '''Look up a var for the standalone HTTP server
+        '''
+        return self.get('HTTP SERVER', name)
+
+    def getCGI(self, name):
+        '''Look up a var for the cgi script
+        '''
+        return self.get('CGI', name)
 
-    def get(self, group, attr):
-        return self.conf.get(group, attr)
-            
-if __name__ == '__main__':
-    base_config = loadBaseConfig()
-    instances = base_config.loadInstances()
-    
-    for k in instances.getNames():
-        print "%s:%s"%(k, instances.getDirFromName(k),)
+    def getAdmin(self, name):
+        '''Look up a var for the admin script
+        '''
+        return self.get('ADMIN', name)
+
+    def get_default_database_dir(self):
+        '''Historical method to allow migration to using this new config
+        system...
+        '''
+        return self.get('BASE', 'DATABASE')
+

Roundup Issue Tracker: http://roundup-tracker.org/