Merge branch 'develop' into features/astakos
[kamaki] / kamaki / cli / command_shell.py
index 1ddd456..f4f3443 100644 (file)
 from cmd import Cmd
 from os import popen
 from sys import stdout
-from argparse import ArgumentParser
 
 from kamaki.cli import _exec_cmd, _print_error_message
-from kamaki.cli.argument import update_arguments
-from kamaki.cli.utils import print_dict
+from kamaki.cli.argument import ArgumentParseManager
+from kamaki.cli.utils import print_dict, split_input, print_items
 from kamaki.cli.history import History
 from kamaki.cli.errors import CLIError
 
 
-def _init_shell(exe_string, arguments):
-    arguments.pop('version', None)
-    arguments.pop('options', None)
-    arguments.pop('history', None)
+def _init_shell(exe_string, parser):
+    parser.arguments.pop('version', None)
+    parser.arguments.pop('options', None)
+    parser.arguments.pop('debug', None)
+    parser.arguments.pop('verbose', None)
+    parser.arguments.pop('include', None)
+    parser.arguments.pop('silent', None)
     shell = Shell()
     shell.set_prompt(exe_string)
     from kamaki import __version__ as version
@@ -64,9 +66,9 @@ class Shell(Cmd):
     _suffix = ']:'
     cmd_tree = None
     _history = None
-    _arguments = None
     _context_stack = []
     _prompt_stack = []
+    _parser = None
 
     undoc_header = 'interactive shell commands:'
 
@@ -143,7 +145,7 @@ class Shell(Cmd):
 
     def _register_command(self, cmd_path):
         cmd = self.cmd_tree.get_command(cmd_path)
-        arguments = self._arguments
+        arguments = self._parser.arguments
 
         def do_method(new_context, line):
             """ Template for all cmd.Cmd methods of the form do_<cmd name>
@@ -151,28 +153,37 @@ class Shell(Cmd):
                 <cmd> <term> <term> <args> is always parsed to most specific
                 even if cmd_term_term is not a terminal path
             """
-            subcmd, cmd_args = cmd.parse_out(line.split())
-            if self._history:
-                self._history.add(' '.join([cmd.path.replace('_', ' '), line]))
-            cmd_parser = ArgumentParser(cmd.name, add_help=False)
-            cmd_parser.description = subcmd.help
+            subcmd, cmd_args = cmd.parse_out(split_input(line))
+            self._history.add(' '.join([cmd.path.replace('_', ' '), line]))
+            cmd_parser = ArgumentParseManager(
+                cmd.name,
+                dict(self._parser.arguments))
+
+            cmd_parser.parser.description = subcmd.help
 
             # exec command or change context
             if subcmd.is_command:  # exec command
                 cls = subcmd.get_class()
-                instance = cls(dict(arguments))
-                cmd_parser.prog = '%s %s' % (cmd_parser.prog.replace('_', ' '),
-                    cls.syntax)
-                update_arguments(cmd_parser, instance.arguments)
+                instance = cls(dict(cmd_parser.arguments))
+                cmd_parser.update_arguments(instance.arguments)
+                instance.arguments.pop('config')
+                #cmd_parser = ArgumentParseManager(subcmd.path,
+                #    instance.arguments)
+                cmd_parser.arguments = instance.arguments
+                cmd_parser.syntax = '%s %s' % (
+                    subcmd.path.replace('_', ' '), cls.syntax)
                 if '-h' in cmd_args or '--help' in cmd_args:
-                    cmd_parser.print_help()
+                    cmd_parser.parser.print_help()
+                    print('\n%s' % subcmd.help)
                     return
-                parsed, unparsed = cmd_parser.parse_known_args(cmd_args)
+                cmd_parser.parse(cmd_args)
 
                 for name, arg in instance.arguments.items():
-                    arg.value = getattr(parsed, name, arg.default)
+                    arg.value = getattr(cmd_parser.parsed, name, arg.default)
                 try:
-                    _exec_cmd(instance, unparsed, cmd_parser.print_help)
+                    _exec_cmd(instance,
+                        cmd_parser.unparsed,
+                        cmd_parser.parser.print_help)
                 except CLIError as err:
                     _print_error_message(err)
             elif ('-h' in cmd_args or '--help' in cmd_args) \
@@ -199,10 +210,30 @@ class Shell(Cmd):
 
         def help_method(self):
             print('%s (%s -h for more options)' % (cmd.help, cmd.name))
+            if cmd.is_command:
+                cls = cmd.get_class()
+                #_construct_command_syntax(cls)
+                plist = self.prompt[len(self._prefix):-len(self._suffix)]
+                plist = plist.split(' ')
+                clist = cmd.path.split('_')
+                upto = 0
+                for i, term in enumerate(plist):
+                    try:
+                        if clist[i] == term:
+                            upto += 1
+                    except IndexError:
+                        break
+                print('Syntax: %s %s' % (' '.join(clist[upto:]), cls.syntax))
+            else:
+                options = dict(name='Options:')
+                for sub in cmd.get_subcommands():
+                    options[sub.name] = sub.help
+                print_items([options])
+
         self._register_method(help_method, 'help_%s' % cmd.name)
 
         def complete_method(self, text, line, begidx, endidx):
-            subcmd, cmd_args = cmd.parse_out(line.split()[1:])
+            subcmd, cmd_args = cmd.parse_out(split_input(line)[1:])
             if subcmd.is_command:
                 cls = subcmd.get_class()
                 instance = cls(dict(arguments))
@@ -225,9 +256,11 @@ class Shell(Cmd):
         hdr = tmp_partition[0].strip()
         return '%s commands:' % hdr
 
-    def run(self, arguments, path=''):
-        self._history = History(arguments['config'].get('history', 'file'))
-        self._arguments = arguments
+    def run(self, parser, path=''):
+        print('> > >')
+        self._parser = parser
+        self._history = History(
+            parser.arguments['config'].get('history', 'file'))
         if path:
             cmd = self.cmd_tree.get_command(path)
             intro = cmd.path.replace('_', ' ')
@@ -238,5 +271,10 @@ class Shell(Cmd):
             self._register_command(subcmd.path)
 
         self.set_prompt(intro)
+        print('< < <')
 
-        self.cmdloop()
+        try:
+            self.cmdloop()
+        except Exception:
+            from traceback import print_stack
+            print_stack()