summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Options
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Bcfg2/Options')
-rw-r--r--src/lib/Bcfg2/Options/Options.py2
-rw-r--r--src/lib/Bcfg2/Options/Parser.py11
-rw-r--r--src/lib/Bcfg2/Options/Subcommands.py38
-rw-r--r--src/lib/Bcfg2/Options/Types.py27
4 files changed, 42 insertions, 36 deletions
diff --git a/src/lib/Bcfg2/Options/Options.py b/src/lib/Bcfg2/Options/Options.py
index 752e01b4e..c85cfd87c 100644
--- a/src/lib/Bcfg2/Options/Options.py
+++ b/src/lib/Bcfg2/Options/Options.py
@@ -363,7 +363,7 @@ class RepositoryMacroOption(Option):
def transform_value(self, value):
"""transform the value after macro expansion.
- this can be overridden to further transform the value set by
+ this can be overridden to further transform the value set by
the user *after* macros are expanded, but before the user's
``type`` function is applied. principally exists for
PathOption to canonicalize the path.
diff --git a/src/lib/Bcfg2/Options/Parser.py b/src/lib/Bcfg2/Options/Parser.py
index d146e3aa2..51e41850c 100644
--- a/src/lib/Bcfg2/Options/Parser.py
+++ b/src/lib/Bcfg2/Options/Parser.py
@@ -12,12 +12,14 @@ __all__ = ["setup", "OptionParserException", "Parser", "get_parser",
"new_parser"]
+# pylint: disable=C0103
#: The repository option. This is specified here (and imported into
#: :module:`Bcfg2.Options.Common`) rather than vice-versa due to
#: circular imports.
-repository = PathOption( # pylint: disable=C0103
+repository = PathOption(
'-Q', '--repository', cf=('server', 'repository'),
- default='var/lib/bcfg2', help="Server repository path")
+ default='/var/lib/bcfg2', help="Server repository path")
+# pylint: enable=C0103
#: A module-level :class:`argparse.Namespace` object that stores all
@@ -141,6 +143,9 @@ class Parser(argparse.ArgumentParser):
self.option_list.extend(option.list_options())
option.add_to_parser(self)
+ for opt in option.list_options():
+ opt.default_from_config(self._cfp)
+ self._defaults_set.append(opt)
def add_component(self, component):
""" Add a component (and all of its options) to the
@@ -299,7 +304,7 @@ class Parser(argparse.ArgumentParser):
# check whether the specified bcfg2.conf exists
if not self.unit_test and not os.path.exists(bootstrap.config):
- self.error("Could not read %s" % bootstrap.config)
+ sys.stderr.write("Could not read %s\n" % bootstrap.config)
self.add_config_file(self.configfile.dest, bootstrap.config,
reparse=False)
diff --git a/src/lib/Bcfg2/Options/Subcommands.py b/src/lib/Bcfg2/Options/Subcommands.py
index 8972bde00..2ba81e18d 100644
--- a/src/lib/Bcfg2/Options/Subcommands.py
+++ b/src/lib/Bcfg2/Options/Subcommands.py
@@ -48,6 +48,14 @@ class Subcommand(object):
#: one, ``bcfg2-admin`` does not.)
interactive = True
+ #: Whether or not to expose this command as command line parameter
+ #: or only in an interactive :class:`cmd.Cmd` shell.
+ only_interactive = False
+
+ #: Additional aliases for the command. The contents of the list gets
+ #: added to the default command name (the lowercased class name)
+ aliases = []
+
_ws_re = re.compile(r'\s+', flags=re.MULTILINE)
def __init__(self):
@@ -82,6 +90,7 @@ class Subcommand(object):
"""
if args is not None:
self.parser.namespace = copy.copy(master_setup)
+ self.parser.parsed = False
alist = shlex.split(args)
try:
setup = self.parser.parse(alist)
@@ -141,7 +150,9 @@ class Help(Subcommand):
self._registry = registry
def run(self, setup):
- commands = self._registry.commands
+ commands = dict((name, cmd)
+ for (name, cmd) in self._registry.commands.items()
+ if not cmd.only_interactive)
if setup.command:
try:
commands[setup.command].parser.print_help()
@@ -207,15 +218,22 @@ class CommandRegistry(object):
else:
cmd_obj = cls_or_obj
cmdcls = cmd_obj.__class__
- name = cmdcls.__name__.lower()
- self.commands[name] = cmd_obj
- # py2.5 can't mix *magic and non-magical keyword args, thus
- # the **dict(...)
- self.subcommand_options.append(
- Subparser(*cmdcls.options, **dict(name=name, help=cmdcls.__doc__)))
- if issubclass(self.__class__, cmd.Cmd) and cmdcls.interactive:
- setattr(self, "do_%s" % name, cmd_obj)
- setattr(self, "help_%s" % name, cmd_obj.parser.print_help)
+ names = [cmdcls.__name__.lower()]
+ if cmdcls.aliases:
+ names.extend(cmdcls.aliases)
+
+ for name in names:
+ self.commands[name] = cmd_obj
+
+ if not cmdcls.only_interactive:
+ # py2.5 can't mix *magic and non-magical keyword args, thus
+ # the **dict(...)
+ self.subcommand_options.append(
+ Subparser(*cmdcls.options, **dict(name=name,
+ help=cmdcls.__doc__)))
+ if issubclass(self.__class__, cmd.Cmd) and cmdcls.interactive:
+ setattr(self, "do_%s" % name, cmd_obj)
+ setattr(self, "help_%s" % name, cmd_obj.parser.print_help)
return cmd_obj
def register_commands(self, candidates, parent=Subcommand):
diff --git a/src/lib/Bcfg2/Options/Types.py b/src/lib/Bcfg2/Options/Types.py
index ac099e135..ad2e04f10 100644
--- a/src/lib/Bcfg2/Options/Types.py
+++ b/src/lib/Bcfg2/Options/Types.py
@@ -5,6 +5,7 @@ import os
import re
import pwd
import grp
+from Bcfg2.Compat import literal_eval
_COMMA_SPLIT_RE = re.compile(r'\s*,\s*')
@@ -32,28 +33,10 @@ def colon_list(value):
return value.split(':')
-def comma_dict(value):
- """ Split an option string on commas, optionally surrounded by
- whitespace, and split the resulting items again on equals signs,
- returning a dict """
- result = dict()
- if value:
- items = comma_list(value)
- for item in items:
- if '=' in item:
- key, value = item.split(r'=', 1)
- if value in ["true", "yes", "on"]:
- result[key] = True
- elif value in ["false", "no", "off"]:
- result[key] = False
- else:
- try:
- result[key] = int(value)
- except ValueError:
- result[key] = value
- else:
- result[item] = True
- return result
+def literal_dict(value):
+ """ literally evaluate the option in order to allow for arbitrarily nested
+ dictionaries """
+ return literal_eval(value)
def anchored_regex_list(value):