summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Options/Options.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Bcfg2/Options/Options.py')
-rw-r--r--src/lib/Bcfg2/Options/Options.py82
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)