--- 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)