-# Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
+# Copyright (C) 2010-2012 W. Trevor King <wking@drexel.edu>
#
# This file is part of Hooke.
#
-# Hooke is free software: you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
+# Hooke is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
#
-# Hooke is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
-# Public License for more details.
+# Hooke is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
#
-# You should have received a copy of the GNU Lesser General Public
-# License along with Hooke. If not, see
-# <http://www.gnu.org/licenses/>.
+# You should have received a copy of the GNU Lesser General Public License
+# along with Hooke. If not, see <http://www.gnu.org/licenses/>.
"""Defines :class:`CommandLine` for driving Hooke from the command
line.
import cmd
import logging
import optparse
+import pprint
try:
import readline # including readline makes cmd.Cmd.cmdloop() smarter
except ImportError, e:
import logging
logging.warn('could not import readline, bash-like line editing disabled.')
import shlex
+import sys
from ..command import CommandExit, Exit, Command, Argument, StoreValue
-from ..engine import CommandMessage
-from ..interaction import Request, ReloadUserInterfaceConfig
+from ..engine import CommandMessage, CloseEngine
+from ..interaction import EOFResponse, Request, ReloadUserInterfaceConfig
from ..ui import UserInterface
from ..util.convert import from_string
from ..util.encoding import get_input_encoding, get_output_encoding
# Define a few helper classes.
+class EOF (EOFError):
+ """Raise upon reaching the end of the input file.
+
+ After this point, no more user interaction is possible.
+ """
+ pass
+
class Default (object):
"""Marker for options not given on the command line.
"""
try:
self.add_option(
'--disable-%s' % name, dest=name,
- default=Default, action='store_false')
+ default=Default, action='store_false',
+ help=self._argument_help(a))
except optparse.OptionConflictError, e:
logging.warn('error in %s: %s' % (command, e))
raise
try:
self.add_option(
'--enable-%s' % name, dest=name,
- default=Default, action='store_true')
+ default=Default, action='store_true',
+ help=self._argument_help(a))
except optparse.OptionConflictError, e:
logging.warn('error in %s: %s' % (command, e))
raise
type = 'string'
try:
self.add_option(
- '--%s' % name, dest=name, type=type, default=Default)
+ '--%s' % name, dest=name, type=type, default=Default,
+ help=self._argument_help(a))
except optparse.OptionConflictError, e:
logging.warn('error in %s: %s' % (command, e))
raise
self.command_args.remove(infinite_counter)
self.command_args.append(infinite_counter)
+ def _argument_help(self, argument):
+ return '%s (%s)' % (argument._help, argument.default)
+ # default in the case of callbacks, config-backed values, etc.?
+
def exit(self, status=0, msg=None):
"""Override :meth:`optparse.OptionParser.exit` which calls
:func:`sys.exit`.
try:
args = self._parse_args(args)
except optparse.OptParseError, e:
- self.cmd.stdout.write(str(e).lstrip()+'\n')
+ self.cmd.stdout.write(unicode(e).lstrip()+'\n')
self.cmd.stdout.write('Failure\n')
return
cm = CommandMessage(self.command.name, args)
return True
elif isinstance(msg, CommandExit):
self.cmd.stdout.write(msg.__class__.__name__+'\n')
- self.cmd.stdout.write(str(msg).rstrip()+'\n')
+ self.cmd.stdout.write(unicode(msg).rstrip()+'\n')
break
elif isinstance(msg, ReloadUserInterfaceConfig):
self.cmd.ui.reload_config(msg.config)
continue
elif isinstance(msg, Request):
- self._handle_request(msg)
+ try:
+ self._handle_request(msg)
+ except EOF:
+ return True
continue
- self.cmd.stdout.write(str(msg).rstrip()+'\n')
+ if isinstance(msg, dict):
+ text = pprint.pformat(msg)
+ else:
+ text = unicode(msg)
+ self.cmd.stdout.write(text.rstrip()+'\n')
def _parse_args(self, args):
options,args = self.parser.parse_args(args)
while True:
if error != None:
self.cmd.stdout.write(''.join([
- error.__class__.__name__, ': ', str(error), '\n']))
+ error.__class__.__name__, ': ', unicode(error), '\n']))
self.cmd.stdout.write(prompt_string)
- value = parser(msg, self.cmd.stdin.readline())
+ stdin = sys.stdin
+ try:
+ sys.stdin = self.cmd.stdin
+ raw_response = raw_input()
+ except EOFError, e:
+ self.cmd.inqueue.put(EOFResponse())
+ self.cmd.inqueue.put(CloseEngine())
+ raise EOF
+ finally:
+ sys.stdin = stdin
+ value = parser(msg, raw_response)
try:
response = msg.response(value)
break
self.parser = CommandLineParser(self.command, self.name_fn)
def __call__(self):
- blocks = [self.command.help(name_fn=self.name_fn),
+ blocks = [self.parser.format_help(),
+ self._command_message(),
'----',
'Usage: ' + self._usage_string(),
'']
self.cmd.stdout.write('\n'.join(blocks))
- def _message(self):
- return self.command.help(name_fn=self.name_fn)
+ def _command_message(self):
+ return self.command._help
def _usage_string(self):
if len(self.parser.command_opts) == 0: