summaryrefslogtreecommitdiffstats
path: root/ipalib/cli.py
diff options
context:
space:
mode:
authorPetr Viktorin <pviktori@redhat.com>2012-11-06 11:45:50 -0500
committerRob Crittenden <rcritten@redhat.com>2013-02-18 13:07:17 -0500
commit1e2437ece1f5d645ab5ab12628021798bb7b9e1a (patch)
tree3b8f1cc4fbcc055a0dbe7455c254f77895e0ba33 /ipalib/cli.py
parent5f5b4c3e5eec96821411685c7d9a80d85c15af07 (diff)
downloadfreeipa-1e2437ece1f5d645ab5ab12628021798bb7b9e1a.tar.gz
freeipa-1e2437ece1f5d645ab5ab12628021798bb7b9e1a.tar.xz
freeipa-1e2437ece1f5d645ab5ab12628021798bb7b9e1a.zip
Print help to stderr on error
Whenever a command is used incorrectly, it should output an error message (and possibly additional help) to stderr. This patch adds a parameter to a bunch of places to allow selecting either stdout or stderr for help output, and makes badly called commands output to stderr only. Part of the effort for https://fedorahosted.org/freeipa/ticket/3060
Diffstat (limited to 'ipalib/cli.py')
-rw-r--r--ipalib/cli.py76
1 files changed, 46 insertions, 30 deletions
diff --git a/ipalib/cli.py b/ipalib/cli.py
index ac0eb0589..704a75ca3 100644
--- a/ipalib/cli.py
+++ b/ipalib/cli.py
@@ -50,7 +50,7 @@ from errors import (PublicError, CommandError, HelpError, InternalError,
NoSuchNamespaceError, ValidationError, NotFound, NotConfiguredError,
PromptFailed, ConversionError)
from constants import CLI_TAB
-from parameters import Password, Bytes, File, Str, StrEnum
+from parameters import Password, Bytes, File, Str, StrEnum, Any
from text import _
from ipapython.version import API_VERSION
@@ -665,6 +665,9 @@ class help(frontend.Local):
"""
takes_args = (Str('command?'),)
+ takes_options = (
+ Any('outfile?', flags=['no_option']),
+ )
has_output = tuple()
@@ -749,56 +752,68 @@ class help(frontend.Local):
super(help, self)._on_finalize()
- def run(self, key):
+ def run(self, key, outfile=None):
+ if outfile is None:
+ outfile = sys.stdout
+ writer = self._writer(outfile)
name = from_cli(key)
mod_name = '%s.%s' % (self._PLUGIN_BASE_MODULE, name)
- if key is None or name == "topics":
- self.print_topics()
+ if key is None:
+ make_ipa_parser().print_help(outfile)
+ return
+ if name == "topics":
+ self.print_topics(outfile)
return
if name in self._topics:
- self.print_commands(name)
+ self.print_commands(name, outfile)
elif name in self.Command:
cmd = self.Command[name]
if cmd.NO_CLI:
raise HelpError(topic=name)
- print unicode(_('Purpose: %s')) % unicode(_(cmd.doc)).strip()
+ writer(_('Purpose: %s') % unicode(_(cmd.doc)).strip())
self.Backend.cli.build_parser(cmd).print_help()
elif mod_name in sys.modules:
- self.print_commands(name)
+ self.print_commands(name, outfile)
elif name == "commands":
mcl = max(len(s) for s in (self.Command))
for cname in self.Command:
cmd = self.Command[cname]
if cmd.NO_CLI:
continue
- print '%s %s' % (to_cli(cmd.name).ljust(mcl), cmd.summary)
+ writer('%s %s' % (to_cli(cmd.name).ljust(mcl), cmd.summary))
else:
raise HelpError(topic=name)
- def print_topics(self):
+ def _writer(self, outfile):
+ def writer(string=''):
+ print >> outfile, unicode(string)
+ return writer
+
+ def print_topics(self, outfile):
+ writer = self._writer(outfile)
topics = sorted(self._topics.keys())
- print unicode(_('Usage: ipa [global-options] COMMAND ...'))
- print ''
- print unicode(_('Built-in commands:'))
+ writer(_('Usage: ipa [global-options] COMMAND [command-options]...'))
+ writer()
+ writer(_('Built-in commands:'))
for c in self._builtins:
- print unicode(_('Help subtopics:'))
- print ' %s %s' % (to_cli(c.name).ljust(self._mtl), c.summary)
- print ''
- print unicode(_('Help topics:'))
+ writer(' %s %s' % (to_cli(c.name).ljust(self._mtl), c.summary))
+ writer()
+ writer(_('Help topics:'))
for t in topics:
topic = self._topics[t]
- print ' %s %s' % (to_cli(t).ljust(self._mtl), topic[0])
- print ''
- print unicode(_('Try `ipa --help` for a list of global options.'))
+ writer(' %s %s' % (to_cli(t).ljust(self._mtl), topic[0]))
+ writer()
+ writer(_('Try `ipa --help` for a list of global options.'))
- def print_commands(self, topic):
+ def print_commands(self, topic, outfile):
+ writer = self._writer(outfile)
if topic in self._topics and type(self._topics[topic][2]) is dict:
# we want to display topic which has subtopics
for subtopic in self._topics[topic][2]:
doc = self._topics[topic][2][subtopic][0]
mcl = self._topics[topic][1]
- print ' %s %s' % (to_cli(subtopic).ljust(mcl), doc)
+ writer(' %s %s' % (to_cli(subtopic).ljust(mcl), doc))
else:
# we want to display subtopic or a topic which has no subtopics
if topic in self._topics:
@@ -821,13 +836,14 @@ class help(frontend.Local):
if topic not in self.Command and len(commands) == 0:
raise HelpError(topic=topic)
- print doc
+ writer(doc)
if commands:
- print ''
- print unicode(_('Topic commands:'))
+ writer()
+ writer(_('Topic commands:'))
for c in commands:
- print ' %s %s' % (to_cli(c.name).ljust(mcl), c.summary)
- print "\n"
+ writer(
+ ' %s %s' % (to_cli(c.name).ljust(mcl), c.summary))
+ writer()
class show_mappings(frontend.Command):
"""
@@ -1013,14 +1029,14 @@ class cli(backend.Executioner):
On incorrect invocation, prints out a help message and returns None
"""
if len(argv) == 0:
+ print >>sys.stderr, 'Error: Command not specified'
self.Command.help()
- return
+ exit(2)
(key, argv) = (argv[0], argv[1:])
name = from_cli(key)
if name not in self.Command and len(argv) == 0:
try:
- self.Command.help(unicode(key))
- return
+ self.Command.help(unicode(key), outfile=sys.stderr)
except HelpError:
pass
if name not in self.Command or self.Command[name].NO_CLI:
@@ -1120,7 +1136,7 @@ class cli(backend.Executioner):
for arg in cmd.args():
name = self.__get_arg_name(arg, format_name=False)
- if name is None:
+ if 'no_option' in arg.flags or name is None:
continue
doc = unicode(arg.doc)
parser.add_argument(name, doc)