History in shell can execute commands ('recall')
authorStavros Sachtouris <saxtouri@admin.grnet.gr>
Wed, 12 Dec 2012 11:56:56 +0000 (13:56 +0200)
committerStavros Sachtouris <saxtouri@admin.grnet.gr>
Wed, 12 Dec 2012 11:56:56 +0000 (13:56 +0200)
kamaki/cli/command_shell.py
kamaki/cli/command_tree.py
kamaki/cli/commands/history_cli.py

index 46fd7e2..1a830dc 100644 (file)
@@ -40,6 +40,7 @@ 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
+from kamaki.clients import ClientError
 
 
 def _init_shell(exe_string, parser):
@@ -164,7 +165,10 @@ class Shell(Cmd):
             # exec command or change context
             if subcmd.is_command:  # exec command
                 cls = subcmd.get_class()
-                instance = cls(dict(cmd_parser.arguments))
+                if subcmd.path == 'history_recall':
+                    instance = cls(dict(cmd_parser.arguments), self.cmd_tree)
+                else:
+                    instance = cls(dict(cmd_parser.arguments))
                 cmd_parser.update_arguments(instance.arguments)
                 instance.arguments.pop('config')
                 #cmd_parser = ArgumentParseManager(subcmd.path,
@@ -180,11 +184,12 @@ class Shell(Cmd):
 
                 for name, arg in instance.arguments.items():
                     arg.value = getattr(cmd_parser.parsed, name, arg.default)
+
                 try:
                     _exec_cmd(instance,
                         cmd_parser.unparsed,
                         cmd_parser.parser.print_help)
-                except CLIError as err:
+                except (ClientError, CLIError) as err:
                     _print_error_message(err)
             elif ('-h' in cmd_args or '--help' in cmd_args) \
             or len(cmd_args):  # print options
index 6f765a5..4d706f3 100644 (file)
@@ -155,6 +155,23 @@ class CommandTree(object):
         if description is not None:
             cmd.help = description
 
+    def find_best_match(self, terms):
+        """Find a command that best matches a given list of terms
+
+        :param terms: (list of str) match them against paths in cmd_tree
+
+        :returns: (Command, list) the matching command, the remaining terms
+        """
+        path = []
+        for term in terms:
+            check_path = path + [term]
+            if '_'.join(check_path) not in self._all_commands:
+                break
+            path = check_path
+        if path:
+            return (self._all_commands['_'.join(path)], terms[len(path):])
+        return (None, terms)
+
     def add_tree(self, new_tree):
         tname = new_tree.name
         tdesc = new_tree.description
index 49db728..2e22276 100644 (file)
 
 from kamaki.cli.command_tree import CommandTree
 from kamaki.cli.argument import IntArgument, ValueArgument
+from kamaki.cli.argument import ArgumentParseManager
 from kamaki.cli.history import History
 from kamaki.cli import command
 from kamaki.cli.commands import _command_init
+from kamaki.cli import _exec_cmd, _print_error_message
+from kamaki.cli.errors import CLIError
+from kamaki.cli.utils import split_input
+from kamaki.clients import ClientError
 
 
 history_cmds = CommandTree('history', 'Command history')
@@ -86,10 +91,30 @@ class history_recall(_init_history):
         super(self.__class__, self).__init__(arguments)
         self._cmd_tree = cmd_tree
 
+    def _run_from_line(self, line):
+        terms = split_input(line)
+        cmd, args = self._cmd_tree.find_best_match(terms)
+        if not cmd.is_command:
+            return
+        try:
+            instance = cmd.get_class()(self.arguments)
+            instance.config = self.config
+            prs = ArgumentParseManager(cmd.path.split(),
+                dict(instance.arguments))
+            prs.syntax = '%s %s' % (cmd.path.replace('_', ' '),
+                cmd.get_class().syntax)
+            prs.parse(args)
+            _exec_cmd(instance, prs.unparsed, prs.parser.print_help)
+        except (CLIError, ClientError) as err:
+            _print_error_message(err)
+        except Exception as e:
+            print('Execution of [ %s ] failed' % line)
+            print('\t%s' % e)
+
     def main(self, commandid):
         super(self.__class__, self).main()
         r = self.history.retrieve(commandid)
+        print(r[:-1])
         if self._cmd_tree:
-            raise NotImplemented('Sorry, recall is not implemented yet')
-        else:
-            print(r)
+            r = r[len('kamaki '):-1] if r.startswith('kamaki ') else r[:-1]
+            self._run_from_line(r)