summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Kosek <mkosek@redhat.com>2012-01-27 16:51:37 +0100
committerMartin Kosek <mkosek@redhat.com>2012-02-06 08:57:20 +0100
commitc080c65636ec0e01ffec460c79d0d0d4a7f9da4b (patch)
tree731f848c86fd1434e986704419e23c921b2c0551
parent1403307664dab99f602530d53c64692a6cbd700f (diff)
downloadfreeipa.git-c080c65636ec0e01ffec460c79d0d0d4a7f9da4b.tar.gz
freeipa.git-c080c65636ec0e01ffec460c79d0d0d4a7f9da4b.tar.xz
freeipa.git-c080c65636ec0e01ffec460c79d0d0d4a7f9da4b.zip
Add argument help to CLI
CLI command help contains a documentation for all options that can be passed to commands. However, help strings for positional arguments are not included. This patch uses an OptionParser description field to list all command arguments as OptionParser does not have a native support to provide such information to user. https://fedorahosted.org/freeipa/ticket/1974
-rw-r--r--ipalib/cli.py90
-rw-r--r--ipalib/plugins/baseldap.py4
2 files changed, 84 insertions, 10 deletions
diff --git a/ipalib/cli.py b/ipalib/cli.py
index ad835f29..5d07cb1b 100644
--- a/ipalib/cli.py
+++ b/ipalib/cli.py
@@ -942,6 +942,61 @@ class Collector(object):
def __todict__(self):
return dict(self.__options)
+class CLIOptionParserFormatter(optparse.IndentedHelpFormatter):
+ def format_argument(self, name, help_string):
+ result = []
+ opt_width = self.help_position - self.current_indent - 2
+ if len(name) > opt_width:
+ name = "%*s%s\n" % (self.current_indent, "", name)
+ indent_first = self.help_position
+ else: # start help on same line as name
+ name = "%*s%-*s " % (self.current_indent, "", opt_width, name)
+ indent_first = 0
+ result.append(name)
+ if help_string:
+ help_lines = textwrap.wrap(help_string, self.help_width)
+ result.append("%*s%s\n" % (indent_first, "", help_lines[0]))
+ result.extend(["%*s%s\n" % (self.help_position, "", line)
+ for line in help_lines[1:]])
+ elif name[-1] != "\n":
+ result.append("\n")
+ return "".join(result)
+
+class CLIOptionParser(optparse.OptionParser):
+ """
+ This OptionParser subclass adds an ability to print positional
+ arguments in CLI help. Custom formatter is used to format the argument
+ list in the same way as OptionParser formats options.
+ """
+ def __init__(self, *args, **kwargs):
+ self._arguments = []
+ if 'formatter' not in kwargs:
+ kwargs['formatter'] = CLIOptionParserFormatter()
+ optparse.OptionParser.__init__(self, *args, **kwargs)
+
+ def format_option_help(self, formatter=None):
+ """
+ Prepend argument help to standard OptionParser's option help
+ """
+ option_help = optparse.OptionParser.format_option_help(self, formatter)
+
+ if isinstance(formatter, CLIOptionParserFormatter):
+ heading = unicode(_("Positional arguments"))
+ arguments = [formatter.format_heading(heading)]
+ formatter.indent()
+ for (name, help_string) in self._arguments:
+ arguments.append(formatter.format_argument(name, help_string))
+ formatter.dedent()
+ if len(arguments) > 1:
+ # there is more than just the heading
+ arguments.append(u"\n")
+ else:
+ arguments = []
+ option_help = "".join(arguments) + option_help
+ return option_help
+
+ def add_argument(self, name, help_string):
+ self._arguments.append((name, help_string))
class cli(backend.Executioner):
"""
@@ -1006,7 +1061,7 @@ class cli(backend.Executioner):
yield (key, self.Backend.textui.decode(value))
def build_parser(self, cmd):
- parser = optparse.OptionParser(
+ parser = CLIOptionParser(
usage=' '.join(self.usage_iter(cmd))
)
option_groups = {}
@@ -1045,20 +1100,37 @@ class cli(backend.Executioner):
option_group.add_option(o)
else:
parser.add_option(o)
+
+ for arg in cmd.args():
+ name = self.__get_arg_name(arg, format_name=False)
+ if name is None:
+ continue
+ doc = unicode(arg.doc)
+ parser.add_argument(name, doc)
+
return parser
+ def __get_arg_name(self, arg, format_name=True):
+ if arg.password:
+ return
+
+ name = to_cli(arg.cli_name).upper()
+ if not format_name:
+ return name
+ if arg.multivalue:
+ name = '%s...' % name
+ if arg.required:
+ return name
+ else:
+ return '[%s]' % name
+
def usage_iter(self, cmd):
yield 'Usage: %%prog [global-options] %s' % to_cli(cmd.name)
for arg in cmd.args():
- if arg.password:
+ name = self.__get_arg_name(arg)
+ if name is None:
continue
- name = to_cli(arg.cli_name).upper()
- if arg.multivalue:
- name = '%s...' % name
- if arg.required:
- yield name
- else:
- yield '[%s]' % name
+ yield name
yield '[options]'
def prompt_interactively(self, cmd, kw):
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index f59a0d41..00ae9493 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -1591,7 +1591,9 @@ class LDAPSearch(BaseLDAPCommand, crud.Search):
#pylint: disable=E1003
for key in self.obj.get_ancestor_primary_keys():
yield key
- yield Str('criteria?', noextrawhitespace=False)
+ yield Str('criteria?',
+ noextrawhitespace=False,
+ doc=_('A string searched in all relevant object attributes'))
for arg in super(crud.Search, self).get_args():
yield arg