diff options
Diffstat (limited to 'src/lib/Bcfg2/Options/Options.py')
-rw-r--r-- | src/lib/Bcfg2/Options/Options.py | 82 |
1 files changed, 63 insertions, 19 deletions
diff --git a/src/lib/Bcfg2/Options/Options.py b/src/lib/Bcfg2/Options/Options.py index be7e7c646..3874f810d 100644 --- a/src/lib/Bcfg2/Options/Options.py +++ b/src/lib/Bcfg2/Options/Options.py @@ -10,7 +10,18 @@ from Bcfg2.Options import Types from Bcfg2.Compat import ConfigParser -__all__ = ["Option", "BooleanOption", "PathOption", "PositionalArgument"] +__all__ = ["Option", "BooleanOption", "PathOption", "PositionalArgument", + "_debug"] + + +def _debug(msg): + """ Option parsing happens before verbose/debug have been set -- + they're options, after all -- so option parsing verbosity is + enabled by changing this to True. The verbosity here is primarily + of use to developers. """ + if os.environ.get('BCFG2_OPTIONS_DEBUG', '0') == '1': + print(msg) + #: A dict that records a mapping of argparse action name (e.g., #: "store_true") to the argparse Action class for it. See @@ -158,6 +169,10 @@ class Option(object): the appropriate default value in the appropriate format.""" for parser, action in self.actions.items(): if hasattr(action, "finalize"): + if parser: + _debug("Finalizing %s for %s" % (self, parser)) + else: + _debug("Finalizing %s" % self) action.finalize(parser, namespace) def from_config(self, cfp): @@ -181,23 +196,25 @@ class Option(object): exclude.update(o.cf[1] for o in parser.option_list if o.cf and o.cf[0] == self.cf[0]) - return dict([(o, cfp.get(self.cf[0], o)) - for o in fnmatch.filter(cfp.options(self.cf[0]), - self.cf[1]) - if o not in exclude]) + rv = dict([(o, cfp.get(self.cf[0], o)) + for o in fnmatch.filter(cfp.options(self.cf[0]), + self.cf[1]) + if o not in exclude]) else: - return dict() + rv = dict() else: + if self.type: + rtype = self.type + else: + rtype = lambda x: x try: - val = cfp.getboolean(*self.cf) + rv = rtype(cfp.getboolean(*self.cf)) except ValueError: - val = cfp.get(*self.cf) + rv = rtype(cfp.get(*self.cf)) except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): - return None - if self.type: - return self.type(val) - else: - return val + rv = None + _debug("Setting %s from config file(s): %s" % (self, rv)) + return rv def default_from_config(self, cfp): """ Set the default value of this option from the config file @@ -208,9 +225,13 @@ class Option(object): """ if self.env and self.env in os.environ: self.default = os.environ[self.env] + _debug("Setting the default of %s from environment: %s" % + (self, self.default)) else: val = self.from_config(cfp) if val is not None: + _debug("Setting the default of %s from config: %s" % + (self, val)) self.default = val def _get_default(self): @@ -250,13 +271,17 @@ class Option(object): self.parsers.append(parser) if self.args: # cli option + _debug("Adding %s to %s as a CLI option" % (self, parser)) action = parser.add_argument(*self.args, **self._kwargs) if not self._dest: self._dest = action.dest if self._default: action.default = self._default self.actions[parser] = action - # else, config file-only option + else: + # else, config file-only option + _debug("Adding %s to %s as a config file-only option" % + (self, parser)) class PathOption(Option): @@ -281,6 +306,26 @@ class PathOption(Option): Option.__init__(self, *args, **kwargs) +class _BooleanOptionAction(argparse.Action): + """ BooleanOptionAction sets a boolean value in the following ways: + - if None is passed, store the default + - if the option_string is not None, then the option was passed on the + command line, thus store the opposite of the default (this is the + argparse store_true and store_false behavior) + - if a boolean value is passed, use that + + Defined here instead of :mod:`Bcfg2.Options.Actions` because otherwise + there is a circular import Options -> Actions -> Parser -> Options """ + + def __call__(self, parser, namespace, values, option_string=None): + if values is None: + setattr(namespace, self.dest, self.default) + elif option_string is not None: + setattr(namespace, self.dest, not self.default) + else: + setattr(namespace, self.dest, bool(values)) + + class BooleanOption(Option): """ Shortcut for boolean options. The default is False, but this can easily be overridden: @@ -292,11 +337,10 @@ class BooleanOption(Option): "--dwim", default=True, help="Do What I Mean")] """ def __init__(self, *args, **kwargs): - if 'default' in kwargs and kwargs['default']: - kwargs.setdefault('action', 'store_false') - else: - kwargs.setdefault('action', 'store_true') - kwargs.setdefault('default', False) + kwargs.setdefault('action', _BooleanOptionAction) + kwargs.setdefault('nargs', 0) + kwargs.setdefault('default', False) + Option.__init__(self, *args, **kwargs) |