Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / command_shell.py @ 6dfd55cb

History | View | Annotate | Download (12 kB)

1 b9331a9f Stavros Sachtouris
# Copyright 2012 GRNET S.A. All rights reserved.
2 b9331a9f Stavros Sachtouris
#
3 b9331a9f Stavros Sachtouris
# Redistribution and use in source and binary forms, with or
4 b9331a9f Stavros Sachtouris
# without modification, are permitted provided that the following
5 b9331a9f Stavros Sachtouris
# conditions are met:
6 b9331a9f Stavros Sachtouris
#
7 b9331a9f Stavros Sachtouris
#   1. Redistributions of source code must retain the above
8 fd5db045 Stavros Sachtouris
#      copyright notice, this list of conditions and the following
9 fd5db045 Stavros Sachtouris
#      disclaimer.
10 b9331a9f Stavros Sachtouris
#
11 b9331a9f Stavros Sachtouris
#   2. Redistributions in binary form must reproduce the above
12 fd5db045 Stavros Sachtouris
#      copyright notice, this list of conditions and the following
13 fd5db045 Stavros Sachtouris
#      disclaimer in the documentation and/or other materials
14 fd5db045 Stavros Sachtouris
#      provided with the distribution.
15 b9331a9f Stavros Sachtouris
#
16 b9331a9f Stavros Sachtouris
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 b9331a9f Stavros Sachtouris
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 b9331a9f Stavros Sachtouris
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 b9331a9f Stavros Sachtouris
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 b9331a9f Stavros Sachtouris
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 b9331a9f Stavros Sachtouris
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 b9331a9f Stavros Sachtouris
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 b9331a9f Stavros Sachtouris
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 b9331a9f Stavros Sachtouris
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 b9331a9f Stavros Sachtouris
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 b9331a9f Stavros Sachtouris
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 b9331a9f Stavros Sachtouris
# POSSIBILITY OF SUCH DAMAGE.
28 b9331a9f Stavros Sachtouris
#
29 b9331a9f Stavros Sachtouris
# The views and conclusions contained in the software and
30 b9331a9f Stavros Sachtouris
# documentation are those of the authors and should not be
31 b9331a9f Stavros Sachtouris
# interpreted as representing official policies, either expressed
32 b9331a9f Stavros Sachtouris
# or implied, of GRNET S.A.
33 b9331a9f Stavros Sachtouris
34 b9331a9f Stavros Sachtouris
from cmd import Cmd
35 b9331a9f Stavros Sachtouris
from os import popen
36 ce48608f Stavros Sachtouris
from sys import stdout
37 d486baec Stavros Sachtouris
38 b6a99832 Stavros Sachtouris
from kamaki.cli import exec_cmd, print_error_message, print_subcommands_help
39 074f5027 Stavros Sachtouris
from kamaki.cli.argument import ArgumentParseManager
40 b6a99832 Stavros Sachtouris
from kamaki.cli.utils import print_dict, split_input
41 d486baec Stavros Sachtouris
from kamaki.cli.history import History
42 db950b10 Stavros Sachtouris
from kamaki.cli.errors import CLIError
43 fce93ff6 Stavros Sachtouris
from kamaki.clients import ClientError
44 e3c2c890 Stavros Sachtouris
from kamaki.cli.logger import add_file_logger
45 e3c2c890 Stavros Sachtouris
46 e3c2c890 Stavros Sachtouris
log = add_file_logger(__name__)
47 b9331a9f Stavros Sachtouris
48 fd5db045 Stavros Sachtouris
49 074f5027 Stavros Sachtouris
def _init_shell(exe_string, parser):
50 074f5027 Stavros Sachtouris
    parser.arguments.pop('version', None)
51 75c3fc42 Stavros Sachtouris
    shell = Shell()
52 75c3fc42 Stavros Sachtouris
    shell.set_prompt(exe_string)
53 75c3fc42 Stavros Sachtouris
    from kamaki import __version__ as version
54 75c3fc42 Stavros Sachtouris
    shell.greet(version)
55 75c3fc42 Stavros Sachtouris
    shell.do_EOF = shell.do_exit
56 75c3fc42 Stavros Sachtouris
    from kamaki.cli.command_tree import CommandTree
57 75c3fc42 Stavros Sachtouris
    shell.cmd_tree = CommandTree(
58 75c3fc42 Stavros Sachtouris
        'kamaki', 'A command line tool for poking clouds')
59 75c3fc42 Stavros Sachtouris
    return shell
60 fd5db045 Stavros Sachtouris
61 b9331a9f Stavros Sachtouris
62 b9331a9f Stavros Sachtouris
class Shell(Cmd):
63 fd5db045 Stavros Sachtouris
    """Kamaki interactive shell"""
64 fd5db045 Stavros Sachtouris
    _prefix = '['
65 53254b46 Stavros Sachtouris
    _suffix = ']: '
66 fd5db045 Stavros Sachtouris
    cmd_tree = None
67 fd5db045 Stavros Sachtouris
    _history = None
68 834200da Stavros Sachtouris
    _context_stack = []
69 834200da Stavros Sachtouris
    _prompt_stack = []
70 074f5027 Stavros Sachtouris
    _parser = None
71 834200da Stavros Sachtouris
72 fd5db045 Stavros Sachtouris
    undoc_header = 'interactive shell commands:'
73 fd5db045 Stavros Sachtouris
74 77e7bef7 Stavros Sachtouris
    def postcmd(self, post, line):
75 77e7bef7 Stavros Sachtouris
        if self._context_stack:
76 77e7bef7 Stavros Sachtouris
            self._roll_command()
77 77e7bef7 Stavros Sachtouris
            self._restore(self._context_stack.pop())
78 53254b46 Stavros Sachtouris
            self.set_prompt(
79 53254b46 Stavros Sachtouris
                self._prompt_stack.pop()[len(self._prefix):-len(self._suffix)])
80 77e7bef7 Stavros Sachtouris
81 77e7bef7 Stavros Sachtouris
        return Cmd.postcmd(self, post, line)
82 77e7bef7 Stavros Sachtouris
83 42c739c0 Stavros Sachtouris
    def precmd(self, line):
84 834200da Stavros Sachtouris
        if line.startswith('/'):
85 de73876b Stavros Sachtouris
            start, end = len(self._prefix), -len(self._suffix)
86 de73876b Stavros Sachtouris
            cur_cmd_path = self.prompt.replace(' ', '_')[start:end]
87 524dc2f8 Stavros Sachtouris
            if cur_cmd_path != self.cmd_tree.name:
88 834200da Stavros Sachtouris
                cur_cmd = self.cmd_tree.get_command(cur_cmd_path)
89 834200da Stavros Sachtouris
                self._context_stack.append(self._backup())
90 834200da Stavros Sachtouris
                self._prompt_stack.append(self.prompt)
91 834200da Stavros Sachtouris
                new_context = self
92 a6ad7781 Stavros Sachtouris
                self._roll_command(cur_cmd.path)
93 834200da Stavros Sachtouris
                new_context.set_prompt(self.cmd_tree.name)
94 834200da Stavros Sachtouris
                for grp_cmd in self.cmd_tree.get_subcommands():
95 834200da Stavros Sachtouris
                    self._register_command(grp_cmd.path)
96 834200da Stavros Sachtouris
            return line[1:]
97 42c739c0 Stavros Sachtouris
        return line
98 42c739c0 Stavros Sachtouris
99 fd5db045 Stavros Sachtouris
    def greet(self, version):
100 de73876b Stavros Sachtouris
        print('kamaki v%s - Interactive Shell\n' % version)
101 a6aced18 Stavros Sachtouris
        print('\t/exit     \tterminate kamaki')
102 de73876b Stavros Sachtouris
        print('\texit or ^D\texit context')
103 de73876b Stavros Sachtouris
        print('\t? or help \tavailable commands')
104 de73876b Stavros Sachtouris
        print('\t?command  \thelp on command')
105 de73876b Stavros Sachtouris
        print('\t!<command>\texecute OS shell command')
106 de73876b Stavros Sachtouris
        print('')
107 fd5db045 Stavros Sachtouris
108 fd5db045 Stavros Sachtouris
    def set_prompt(self, new_prompt):
109 53254b46 Stavros Sachtouris
        self.prompt = '%s%s%s' % (self._prefix, new_prompt, self._suffix)
110 fd5db045 Stavros Sachtouris
111 af569ab9 Stavros Sachtouris
    def cmdloop(self):
112 af569ab9 Stavros Sachtouris
        while True:
113 af569ab9 Stavros Sachtouris
            try:
114 af569ab9 Stavros Sachtouris
                Cmd.cmdloop(self)
115 af569ab9 Stavros Sachtouris
            except KeyboardInterrupt:
116 af569ab9 Stavros Sachtouris
                print(' - interrupted')
117 af569ab9 Stavros Sachtouris
                continue
118 af569ab9 Stavros Sachtouris
            break
119 af569ab9 Stavros Sachtouris
120 fd5db045 Stavros Sachtouris
    def do_exit(self, line):
121 fd5db045 Stavros Sachtouris
        print('')
122 de73876b Stavros Sachtouris
        start, end = len(self._prefix), -len(self._suffix)
123 de73876b Stavros Sachtouris
        if self.prompt[start:end] == self.cmd_tree.name:
124 a6ad7781 Stavros Sachtouris
            exit(0)
125 fd5db045 Stavros Sachtouris
        return True
126 fd5db045 Stavros Sachtouris
127 fd5db045 Stavros Sachtouris
    def do_shell(self, line):
128 fd5db045 Stavros Sachtouris
        output = popen(line).read()
129 fd5db045 Stavros Sachtouris
        print(output)
130 fd5db045 Stavros Sachtouris
131 fd5db045 Stavros Sachtouris
    @property
132 fd5db045 Stavros Sachtouris
    def path(self):
133 fd5db045 Stavros Sachtouris
        if self._cmd:
134 3dabe5d2 Stavros Sachtouris
            return self._cmd.path
135 fd5db045 Stavros Sachtouris
        return ''
136 fd5db045 Stavros Sachtouris
137 fd5db045 Stavros Sachtouris
    @classmethod
138 fd5db045 Stavros Sachtouris
    def _register_method(self, method, name):
139 fd5db045 Stavros Sachtouris
        self.__dict__[name] = method
140 fd5db045 Stavros Sachtouris
141 fd5db045 Stavros Sachtouris
    @classmethod
142 fd5db045 Stavros Sachtouris
    def _unregister_method(self, name):
143 fd5db045 Stavros Sachtouris
        try:
144 fd5db045 Stavros Sachtouris
            self.__dict__.pop(name)
145 fd5db045 Stavros Sachtouris
        except KeyError:
146 fd5db045 Stavros Sachtouris
            pass
147 fd5db045 Stavros Sachtouris
148 77e7bef7 Stavros Sachtouris
    def _roll_command(self, cmd_path=None):
149 fd5db045 Stavros Sachtouris
        for subname in self.cmd_tree.get_subnames(cmd_path):
150 fd5db045 Stavros Sachtouris
            self._unregister_method('do_%s' % subname)
151 fd5db045 Stavros Sachtouris
            self._unregister_method('complete_%s' % subname)
152 fd5db045 Stavros Sachtouris
            self._unregister_method('help_%s' % subname)
153 fd5db045 Stavros Sachtouris
154 fd5db045 Stavros Sachtouris
    @classmethod
155 fd5db045 Stavros Sachtouris
    def _backup(self):
156 fd5db045 Stavros Sachtouris
        return dict(self.__dict__)
157 fd5db045 Stavros Sachtouris
158 fd5db045 Stavros Sachtouris
    @classmethod
159 fd5db045 Stavros Sachtouris
    def _restore(self, oldcontext):
160 fd5db045 Stavros Sachtouris
        self.__dict__ = oldcontext
161 fd5db045 Stavros Sachtouris
162 e3c2c890 Stavros Sachtouris
    @staticmethod
163 030c0d3a Stavros Sachtouris
    def _create_help_method(cmd_name, args, descr, syntax):
164 e3c2c890 Stavros Sachtouris
        tmp_args = dict(args)
165 e3c2c890 Stavros Sachtouris
        tmp_args.pop('options', None)
166 e3c2c890 Stavros Sachtouris
        tmp_args.pop('debug', None)
167 e3c2c890 Stavros Sachtouris
        tmp_args.pop('verbose', None)
168 e3c2c890 Stavros Sachtouris
        tmp_args.pop('include', None)
169 e3c2c890 Stavros Sachtouris
        tmp_args.pop('silent', None)
170 e3c2c890 Stavros Sachtouris
        tmp_args.pop('config', None)
171 e3c2c890 Stavros Sachtouris
        help_parser = ArgumentParseManager(cmd_name, tmp_args)
172 e3c2c890 Stavros Sachtouris
        help_parser.parser.description = descr
173 030c0d3a Stavros Sachtouris
        help_parser.syntax = syntax
174 e3c2c890 Stavros Sachtouris
        return help_parser.parser.print_help
175 e3c2c890 Stavros Sachtouris
176 d53062bd Stavros Sachtouris
    def _register_command(self, cmd_path):
177 fd5db045 Stavros Sachtouris
        cmd = self.cmd_tree.get_command(cmd_path)
178 074f5027 Stavros Sachtouris
        arguments = self._parser.arguments
179 fd5db045 Stavros Sachtouris
180 834200da Stavros Sachtouris
        def do_method(new_context, line):
181 fd5db045 Stavros Sachtouris
            """ Template for all cmd.Cmd methods of the form do_<cmd name>
182 fd5db045 Stavros Sachtouris
                Parse cmd + args and decide to execute or change context
183 fd5db045 Stavros Sachtouris
                <cmd> <term> <term> <args> is always parsed to most specific
184 fd5db045 Stavros Sachtouris
                even if cmd_term_term is not a terminal path
185 fd5db045 Stavros Sachtouris
            """
186 efbcdc41 Stavros Sachtouris
            subcmd, cmd_args = cmd.parse_out(split_input(line))
187 074f5027 Stavros Sachtouris
            self._history.add(' '.join([cmd.path.replace('_', ' '), line]))
188 e3c2c890 Stavros Sachtouris
            cmd_parser = ArgumentParseManager(
189 e3c2c890 Stavros Sachtouris
                cmd.name, dict(self._parser.arguments))
190 074f5027 Stavros Sachtouris
            cmd_parser.parser.description = subcmd.help
191 fd5db045 Stavros Sachtouris
192 fd5db045 Stavros Sachtouris
            # exec command or change context
193 fd5db045 Stavros Sachtouris
            if subcmd.is_command:  # exec command
194 db950b10 Stavros Sachtouris
                try:
195 c8e17a67 Stavros Sachtouris
                    cls = subcmd.get_class()
196 c8e17a67 Stavros Sachtouris
                    ldescr = getattr(cls, 'long_description', '')
197 c8e17a67 Stavros Sachtouris
                    if subcmd.path == 'history_run':
198 53e1f8d5 Stavros Sachtouris
                        instance = cls(
199 53e1f8d5 Stavros Sachtouris
                            dict(cmd_parser.arguments),
200 c8e17a67 Stavros Sachtouris
                            self.cmd_tree)
201 c8e17a67 Stavros Sachtouris
                    else:
202 c8e17a67 Stavros Sachtouris
                        instance = cls(dict(cmd_parser.arguments))
203 c8e17a67 Stavros Sachtouris
                    cmd_parser.update_arguments(instance.arguments)
204 0d4a6d0a Stavros Sachtouris
                    #instance.arguments.pop('config')
205 c8e17a67 Stavros Sachtouris
                    cmd_parser.arguments = instance.arguments
206 c8e17a67 Stavros Sachtouris
                    cmd_parser.syntax = '%s %s' % (
207 c8e17a67 Stavros Sachtouris
                        subcmd.path.replace('_', ' '), cls.syntax)
208 e3c2c890 Stavros Sachtouris
                    help_method = self._create_help_method(
209 030c0d3a Stavros Sachtouris
                        cmd.name, cmd_parser.arguments,
210 030c0d3a Stavros Sachtouris
                        subcmd.help, cmd_parser.syntax)
211 c8e17a67 Stavros Sachtouris
                    if '-h' in cmd_args or '--help' in cmd_args:
212 e3c2c890 Stavros Sachtouris
                        help_method()
213 c8e17a67 Stavros Sachtouris
                        if ldescr.strip():
214 c8e17a67 Stavros Sachtouris
                            print('\nDetails:')
215 c8e17a67 Stavros Sachtouris
                            print('%s' % ldescr)
216 c8e17a67 Stavros Sachtouris
                        return
217 c8e17a67 Stavros Sachtouris
                    cmd_parser.parse(cmd_args)
218 c8e17a67 Stavros Sachtouris
219 c8e17a67 Stavros Sachtouris
                    for name, arg in instance.arguments.items():
220 de73876b Stavros Sachtouris
                        arg.value = getattr(
221 de73876b Stavros Sachtouris
                            cmd_parser.parsed,
222 de73876b Stavros Sachtouris
                            name,
223 c8e17a67 Stavros Sachtouris
                            arg.default)
224 c8e17a67 Stavros Sachtouris
225 e3c2c890 Stavros Sachtouris
                    exec_cmd(instance, cmd_parser.unparsed, help_method)
226 53e1f8d5 Stavros Sachtouris
                        #[term for term in cmd_parser.unparsed\
227 53e1f8d5 Stavros Sachtouris
                        #    if not term.startswith('-')],
228 fce93ff6 Stavros Sachtouris
                except (ClientError, CLIError) as err:
229 b6a99832 Stavros Sachtouris
                    print_error_message(err)
230 de73876b Stavros Sachtouris
            elif ('-h' in cmd_args or '--help' in cmd_args) or len(cmd_args):
231 de73876b Stavros Sachtouris
                # print options
232 a71bb904 Stavros Sachtouris
                print('%s' % cmd.help)
233 b6a99832 Stavros Sachtouris
                print_subcommands_help(cmd)
234 fd5db045 Stavros Sachtouris
            else:  # change context
235 834200da Stavros Sachtouris
                #new_context = this
236 fd5db045 Stavros Sachtouris
                backup_context = self._backup()
237 fd5db045 Stavros Sachtouris
                old_prompt = self.prompt
238 fd5db045 Stavros Sachtouris
                new_context._roll_command(cmd.parent_path)
239 fd5db045 Stavros Sachtouris
                new_context.set_prompt(subcmd.path.replace('_', ' '))
240 fd5db045 Stavros Sachtouris
                newcmds = [subcmd for subcmd in subcmd.get_subcommands()]
241 fd5db045 Stavros Sachtouris
                for subcmd in newcmds:
242 d53062bd Stavros Sachtouris
                    new_context._register_command(subcmd.path)
243 fd5db045 Stavros Sachtouris
                new_context.cmdloop()
244 fd5db045 Stavros Sachtouris
                self.prompt = old_prompt
245 fd5db045 Stavros Sachtouris
                #when new context is over, roll back to the old one
246 fd5db045 Stavros Sachtouris
                self._restore(backup_context)
247 fd5db045 Stavros Sachtouris
        self._register_method(do_method, 'do_%s' % cmd.name)
248 fd5db045 Stavros Sachtouris
249 fd5db045 Stavros Sachtouris
        def help_method(self):
250 fd5db045 Stavros Sachtouris
            print('%s (%s -h for more options)' % (cmd.help, cmd.name))
251 54d800e8 Stavros Sachtouris
            if cmd.is_command:
252 54d800e8 Stavros Sachtouris
                cls = cmd.get_class()
253 2fbca093 Stavros Sachtouris
                ldescr = getattr(cls, 'long_description', '')
254 54d800e8 Stavros Sachtouris
                #_construct_command_syntax(cls)
255 54d800e8 Stavros Sachtouris
                plist = self.prompt[len(self._prefix):-len(self._suffix)]
256 54d800e8 Stavros Sachtouris
                plist = plist.split(' ')
257 54d800e8 Stavros Sachtouris
                clist = cmd.path.split('_')
258 54d800e8 Stavros Sachtouris
                upto = 0
259 2fbca093 Stavros Sachtouris
                if ldescr:
260 2fbca093 Stavros Sachtouris
                    print('%s' % ldescr)
261 54d800e8 Stavros Sachtouris
                for i, term in enumerate(plist):
262 54d800e8 Stavros Sachtouris
                    try:
263 54d800e8 Stavros Sachtouris
                        if clist[i] == term:
264 54d800e8 Stavros Sachtouris
                            upto += 1
265 54d800e8 Stavros Sachtouris
                    except IndexError:
266 54d800e8 Stavros Sachtouris
                        break
267 54d800e8 Stavros Sachtouris
                print('Syntax: %s %s' % (' '.join(clist[upto:]), cls.syntax))
268 8741c407 Stavros Sachtouris
            if cmd.subcommands:
269 b6a99832 Stavros Sachtouris
                print_subcommands_help(cmd)
270 54d800e8 Stavros Sachtouris
271 fd5db045 Stavros Sachtouris
        self._register_method(help_method, 'help_%s' % cmd.name)
272 fd5db045 Stavros Sachtouris
273 fd5db045 Stavros Sachtouris
        def complete_method(self, text, line, begidx, endidx):
274 efbcdc41 Stavros Sachtouris
            subcmd, cmd_args = cmd.parse_out(split_input(line)[1:])
275 fd5db045 Stavros Sachtouris
            if subcmd.is_command:
276 fd5db045 Stavros Sachtouris
                cls = subcmd.get_class()
277 834200da Stavros Sachtouris
                instance = cls(dict(arguments))
278 fd5db045 Stavros Sachtouris
                empty, sep, subname = subcmd.path.partition(cmd.path)
279 fd5db045 Stavros Sachtouris
                cmd_name = '%s %s' % (cmd.name, subname.replace('_', ' '))
280 de73876b Stavros Sachtouris
                print('\n%s\nSyntax:\t%s %s' % (
281 de73876b Stavros Sachtouris
                    cls.description,
282 de73876b Stavros Sachtouris
                    cmd_name,
283 de73876b Stavros Sachtouris
                    cls.syntax))
284 fd5db045 Stavros Sachtouris
                cmd_args = {}
285 fd5db045 Stavros Sachtouris
                for arg in instance.arguments.values():
286 fd5db045 Stavros Sachtouris
                    cmd_args[','.join(arg.parsed_name)] = arg.help
287 f551841a Stavros Sachtouris
                print_dict(cmd_args, ident=2)
288 fd5db045 Stavros Sachtouris
                stdout.write('%s %s' % (self.prompt, line))
289 fd5db045 Stavros Sachtouris
            return subcmd.get_subnames()
290 fd5db045 Stavros Sachtouris
        self._register_method(complete_method, 'complete_%s' % cmd.name)
291 fd5db045 Stavros Sachtouris
292 fd5db045 Stavros Sachtouris
    @property
293 fd5db045 Stavros Sachtouris
    def doc_header(self):
294 fd5db045 Stavros Sachtouris
        tmp_partition = self.prompt.partition(self._prefix)
295 fd5db045 Stavros Sachtouris
        tmp_partition = tmp_partition[2].partition(self._suffix)
296 fd5db045 Stavros Sachtouris
        hdr = tmp_partition[0].strip()
297 fd5db045 Stavros Sachtouris
        return '%s commands:' % hdr
298 fd5db045 Stavros Sachtouris
299 074f5027 Stavros Sachtouris
    def run(self, parser, path=''):
300 074f5027 Stavros Sachtouris
        self._parser = parser
301 074f5027 Stavros Sachtouris
        self._history = History(
302 074f5027 Stavros Sachtouris
            parser.arguments['config'].get('history', 'file'))
303 db950b10 Stavros Sachtouris
        if path:
304 fd5db045 Stavros Sachtouris
            cmd = self.cmd_tree.get_command(path)
305 fd5db045 Stavros Sachtouris
            intro = cmd.path.replace('_', ' ')
306 fd5db045 Stavros Sachtouris
        else:
307 fd5db045 Stavros Sachtouris
            intro = self.cmd_tree.name
308 fd5db045 Stavros Sachtouris
309 fd5db045 Stavros Sachtouris
        for subcmd in self.cmd_tree.get_subcommands(path):
310 d53062bd Stavros Sachtouris
            self._register_command(subcmd.path)
311 fd5db045 Stavros Sachtouris
312 fd5db045 Stavros Sachtouris
        self.set_prompt(intro)
313 db950b10 Stavros Sachtouris
314 f9af2848 Stavros Sachtouris
        try:
315 f9af2848 Stavros Sachtouris
            self.cmdloop()
316 af569ab9 Stavros Sachtouris
        except Exception as e:
317 af569ab9 Stavros Sachtouris
            print('(%s)' % e)
318 f9af2848 Stavros Sachtouris
            from traceback import print_stack
319 f9af2848 Stavros Sachtouris
            print_stack()