merge
authorTero Marttila <terom@paivola.fi>
Sun, 22 Dec 2013 14:24:16 +0200
changeset 26 9384a10f7d5e
parent 25 538c02bd95e0 (diff)
parent 24 9f1ecf190fe0 (current diff)
child 27 62159e5b6685
merge
--- a/pvl/args.py	Sat Dec 21 22:49:12 2013 +0200
+++ b/pvl/args.py	Sun Dec 22 14:24:16 2013 +0200
@@ -30,14 +30,20 @@
     general.add_option('--log-file',                                                                    help="Log to file")
     general.add_option('--debug-module',    action='append', metavar='MODULE', 
             help="Enable logging for the given logger/module name")
-    
+
+     parser.add_option('-c', '--config',    metavar='PATH',
+            help="Read option defaults from config")
+    parser.add_option('--config-encoding',  metavar='CHARSET',  default='utf-8',
+            help="Unicode decoding for config file")
+
+   
     if setuid :
         general.add_option('--uid',             help="Change uid")
         general.add_option('--gid',             help="Change gid")
 
     # defaults
     parser.set_defaults(
-        _setuid             = setuid,
+        setuid              = setuid,
         logname             = parser.prog,
         loglevel            = logging.WARN,
         debug_module        = [],
@@ -127,6 +133,106 @@
     else:
         return [apply_file(None, *args, **opts)]
 
+import configobj
+import copy
+import optparse
+
+class Options (object) :
+    """
+        Custom optparse.Values implementation.
+
+        Passed to OptionParser.parse_args(), called by Option.take_action():
+            setattr(values, dest, ...)
+            values.ensure_value(dest, ...)
+    """
+
+    def __init__ (self, defaults={ }) :
+        self._defaults  = defaults
+        self._options   = { }
+
+    def __setattr__ (self, name, value) :
+        if name.startswith('_') :
+            self.__dict__[name] = value
+        else :
+            self._options[name] = value
+    
+    def ensure_value (self, name, default) :
+        if name in self._options :
+            pass
+        elif name in self._defaults :
+            self._options[name] = copy.copy(self._defaults[name])
+        else :
+            self._options[name] = default
+
+        return self._options[name]
+
+    def _merge (self, options) :
+        """
+            Merge in options from given Options.
+        """
+        
+        # TODO: lists?
+        self._options.update(options._options)
+
+    def __getattr__ (self, name) :
+        if name.startswith('_') :
+            raise AttributeError(name)
+
+        if name in self._options :
+            return self._options[name]
+        elif name in self._defaults :
+            return self._defaults[name]
+        else :
+            raise AttributeError(name)
+
+def apply_config (options, parser, config, encoding=None) :
+    """
+        Load options from config.
+    """
+
+    import configobj
+        
+    config = configobj.ConfigObj(config,
+            encoding        = options.config_encoding if encoding is None else encoding,
+    )
+    config_options = Options(options._defaults)
+
+    # load scalars
+    for scalar in config.scalars :
+        # option from config
+        option = parser._long_opt.get('--' + scalar)
+        
+        if not option :
+            raise optparse.BadOptionError(scalar)
+        
+        # value from config
+        if option.takes_value() :
+            value = config[scalar]
+
+        else :
+            # ignore
+            value = None
+        
+        # apply
+        option.process(scalar, value, config_options, parser)
+    
+    # apply in actual options
+    config_options._merge(options)
+
+    return config_options
+
+def parse (parser, argv) :
+    """
+        Parse options, args from argv.
+    """
+
+    options, args = parser.parse_args(argv[1:], values=Options(parser.defaults))
+
+    if options.config :
+        options = apply_config(options, parser, options.config)
+    
+    return options, args
+
 def apply (options, logname=None, rootok=True) :
     """
         Apply the optparse options.
@@ -148,7 +254,7 @@
     # TODO: use --quiet for stdout output?
     options.quiet = options.loglevel > logging.WARN
     
-    if options._setuid :
+    if options.setuid :
         if options.uid or options.gid or not rootok :
             # set uid/gid
             apply_setid(options, rootok=rootok)