config: Allow specifying configuration values with no default.
[matthijs/projects/backupninja.git] / src / lib / backupninja / config.py
index af3d4dae3b7ddda15d3b4b22a1328eddfb93571e..030fc573121a83474e3486a5c0d5234921555eb4 100644 (file)
@@ -23,9 +23,8 @@
 
 import os, ConfigParser
 
-default_config_dir = '/etc/backupninja'
-default_global_config = 'backupninja.conf'
-default_actions_dir = 'actions'
+# Defaults for global configuration values
+default_global_config = {}
 
 import logging as log
 
@@ -37,32 +36,32 @@ def get_global_config(opts):
 
     opts are the parsed commandline options.
     """
-    global_config = os.path.join(default_config_dir, default_global_config)
-    return _load_config(global_config)
-
-def get_action_config(opts, action):
-    """
-    Returns the configuration for the named action, in a
-    SafeConfigParser object. If the configuration file can not be found,
-    logs an error and returns None.
-
-    opts are the parsed commandline options.
-    """
-    actions_dir = os.path.join(default_config_dir, default_actions_dir)
-    return _load_config(os.path.join(actions_dir, action))
+    global_config = os.path.join(opts.config_dir, opts.global_config)
+    return load_config(global_config, default_global_config)
 
 def list_actions(opts):
     """
     Lists all actions defined in the configuration directory. Returns a
-    list of action names that can be passed to get_action_config.
+    list of full paths to action configuration files.
+
     opts are the parsed commandline options.
     """
-    actions_dir = os.path.join(default_config_dir, default_actions_dir)
-    return os.listdir(actions_dir)
+    actions_dir = os.path.join(opts.config_dir, opts.actions_dir)
+    return [os.path.join(actions_dir, f) 
+            for f in os.listdir(actions_dir) 
+            if not f.startswith('.')]
     
-def _load_config(filename):
+def load_config(filename, defaults):
+    """
+    Load a configuration file, using the given default values.
+
+    The defaults argument contains a dictionary of sections. Each key is
+    a section name, each value is a dictionary of values (where the key
+    is the value name and the value is the actual value).
+    """
     # Open a file and read it
     config = ConfigParser.SafeConfigParser()
+    _set_default_config(config, defaults)
     log.debug('Reading config file "%s"', filename)
     try:
         file = open(filename, 'r')
@@ -74,3 +73,23 @@ def _load_config(filename):
 
     config.readfp(file)
     return config
+
+def _set_default_config(parser, values):
+    """
+    Saves the values given to the ConfigParser given. This can be used
+    to store a set of default values to a ConfigParser before loading a
+    file (The defaults argument to the ConfigParser constructor only
+    sets the values of the "DEFAULT" section).
+
+    The values argument contains a dictionary of sections. Each key is a
+    section name, each value is a dictionary of values (where the key is
+    the value name and the value is the actual value).
+    """
+    for section, options in values.items():
+        if not parser.has_section(section):
+            parser.add_section(section)
+        for option, value in options.items():
+            # Interpret None as "no default", since ConfigParser doesn't
+            # like non-string values.
+            if not value is None:
+                parser.set(section, option, value)