Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / command_shell.py @ b8220825

History | View | Annotate | Download (12.7 kB)

1 b8220825 Stavros Sachtouris
# Copyright 2012-2014 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 56d84a4e Stavros Sachtouris
from sys import stdout, stderr
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 6a2a28bd Stavros Sachtouris
def _init_shell(exe_string, parser, username='', userid=''):
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 6a2a28bd Stavros Sachtouris
    shell.greet(version, username, userid)
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 f724cd35 Stavros Sachtouris
    auth_base = None
72 99085b30 Stavros Sachtouris
    cloud = None
73 834200da Stavros Sachtouris
74 fd5db045 Stavros Sachtouris
    undoc_header = 'interactive shell commands:'
75 fd5db045 Stavros Sachtouris
76 f98912a4 Stavros Sachtouris
    def emptyline(self):
77 f98912a4 Stavros Sachtouris
        self.lastcmd = ''
78 f98912a4 Stavros Sachtouris
79 77e7bef7 Stavros Sachtouris
    def postcmd(self, post, line):
80 77e7bef7 Stavros Sachtouris
        if self._context_stack:
81 77e7bef7 Stavros Sachtouris
            self._roll_command()
82 77e7bef7 Stavros Sachtouris
            self._restore(self._context_stack.pop())
83 53254b46 Stavros Sachtouris
            self.set_prompt(
84 53254b46 Stavros Sachtouris
                self._prompt_stack.pop()[len(self._prefix):-len(self._suffix)])
85 77e7bef7 Stavros Sachtouris
86 77e7bef7 Stavros Sachtouris
        return Cmd.postcmd(self, post, line)
87 77e7bef7 Stavros Sachtouris
88 42c739c0 Stavros Sachtouris
    def precmd(self, line):
89 834200da Stavros Sachtouris
        if line.startswith('/'):
90 de73876b Stavros Sachtouris
            start, end = len(self._prefix), -len(self._suffix)
91 de73876b Stavros Sachtouris
            cur_cmd_path = self.prompt.replace(' ', '_')[start:end]
92 524dc2f8 Stavros Sachtouris
            if cur_cmd_path != self.cmd_tree.name:
93 834200da Stavros Sachtouris
                cur_cmd = self.cmd_tree.get_command(cur_cmd_path)
94 834200da Stavros Sachtouris
                self._context_stack.append(self._backup())
95 834200da Stavros Sachtouris
                self._prompt_stack.append(self.prompt)
96 834200da Stavros Sachtouris
                new_context = self
97 a6ad7781 Stavros Sachtouris
                self._roll_command(cur_cmd.path)
98 834200da Stavros Sachtouris
                new_context.set_prompt(self.cmd_tree.name)
99 834200da Stavros Sachtouris
                for grp_cmd in self.cmd_tree.get_subcommands():
100 834200da Stavros Sachtouris
                    self._register_command(grp_cmd.path)
101 834200da Stavros Sachtouris
            return line[1:]
102 42c739c0 Stavros Sachtouris
        return line
103 42c739c0 Stavros Sachtouris
104 6a2a28bd Stavros Sachtouris
    def greet(self, version, username='', userid=''):
105 de73876b Stavros Sachtouris
        print('kamaki v%s - Interactive Shell\n' % version)
106 a6aced18 Stavros Sachtouris
        print('\t/exit     \tterminate kamaki')
107 de73876b Stavros Sachtouris
        print('\texit or ^D\texit context')
108 de73876b Stavros Sachtouris
        print('\t? or help \tavailable commands')
109 de73876b Stavros Sachtouris
        print('\t?command  \thelp on command')
110 de73876b Stavros Sachtouris
        print('\t!<command>\texecute OS shell command')
111 de73876b Stavros Sachtouris
        print('')
112 6a2a28bd Stavros Sachtouris
        if username or userid:
113 6a2a28bd Stavros Sachtouris
            print('Session user is %s (uuid: %s)' % (username, userid))
114 fd5db045 Stavros Sachtouris
115 fd5db045 Stavros Sachtouris
    def set_prompt(self, new_prompt):
116 53254b46 Stavros Sachtouris
        self.prompt = '%s%s%s' % (self._prefix, new_prompt, self._suffix)
117 fd5db045 Stavros Sachtouris
118 af569ab9 Stavros Sachtouris
    def cmdloop(self):
119 af569ab9 Stavros Sachtouris
        while True:
120 af569ab9 Stavros Sachtouris
            try:
121 af569ab9 Stavros Sachtouris
                Cmd.cmdloop(self)
122 af569ab9 Stavros Sachtouris
            except KeyboardInterrupt:
123 af569ab9 Stavros Sachtouris
                print(' - interrupted')
124 af569ab9 Stavros Sachtouris
                continue
125 af569ab9 Stavros Sachtouris
            break
126 af569ab9 Stavros Sachtouris
127 fd5db045 Stavros Sachtouris
    def do_exit(self, line):
128 fd5db045 Stavros Sachtouris
        print('')
129 de73876b Stavros Sachtouris
        start, end = len(self._prefix), -len(self._suffix)
130 de73876b Stavros Sachtouris
        if self.prompt[start:end] == self.cmd_tree.name:
131 a6ad7781 Stavros Sachtouris
            exit(0)
132 fd5db045 Stavros Sachtouris
        return True
133 fd5db045 Stavros Sachtouris
134 fd5db045 Stavros Sachtouris
    def do_shell(self, line):
135 fd5db045 Stavros Sachtouris
        output = popen(line).read()
136 fd5db045 Stavros Sachtouris
        print(output)
137 fd5db045 Stavros Sachtouris
138 fd5db045 Stavros Sachtouris
    @property
139 fd5db045 Stavros Sachtouris
    def path(self):
140 fd5db045 Stavros Sachtouris
        if self._cmd:
141 3dabe5d2 Stavros Sachtouris
            return self._cmd.path
142 fd5db045 Stavros Sachtouris
        return ''
143 fd5db045 Stavros Sachtouris
144 fd5db045 Stavros Sachtouris
    @classmethod
145 fd5db045 Stavros Sachtouris
    def _register_method(self, method, name):
146 fd5db045 Stavros Sachtouris
        self.__dict__[name] = method
147 fd5db045 Stavros Sachtouris
148 fd5db045 Stavros Sachtouris
    @classmethod
149 fd5db045 Stavros Sachtouris
    def _unregister_method(self, name):
150 fd5db045 Stavros Sachtouris
        try:
151 fd5db045 Stavros Sachtouris
            self.__dict__.pop(name)
152 fd5db045 Stavros Sachtouris
        except KeyError:
153 fd5db045 Stavros Sachtouris
            pass
154 fd5db045 Stavros Sachtouris
155 77e7bef7 Stavros Sachtouris
    def _roll_command(self, cmd_path=None):
156 d252a7a8 Stavros Sachtouris
        for subname in self.cmd_tree.subnames(cmd_path):
157 fd5db045 Stavros Sachtouris
            self._unregister_method('do_%s' % subname)
158 fd5db045 Stavros Sachtouris
            self._unregister_method('complete_%s' % subname)
159 fd5db045 Stavros Sachtouris
            self._unregister_method('help_%s' % subname)
160 fd5db045 Stavros Sachtouris
161 fd5db045 Stavros Sachtouris
    @classmethod
162 fd5db045 Stavros Sachtouris
    def _backup(self):
163 fd5db045 Stavros Sachtouris
        return dict(self.__dict__)
164 fd5db045 Stavros Sachtouris
165 fd5db045 Stavros Sachtouris
    @classmethod
166 fd5db045 Stavros Sachtouris
    def _restore(self, oldcontext):
167 fd5db045 Stavros Sachtouris
        self.__dict__ = oldcontext
168 fd5db045 Stavros Sachtouris
169 e3c2c890 Stavros Sachtouris
    @staticmethod
170 56d84a4e Stavros Sachtouris
    def _create_help_method(cmd_name, args, required, descr, syntax):
171 e3c2c890 Stavros Sachtouris
        tmp_args = dict(args)
172 f6822a26 Stavros Sachtouris
        #tmp_args.pop('options', None)
173 8cec3671 Stavros Sachtouris
        tmp_args.pop('cloud', None)
174 e3c2c890 Stavros Sachtouris
        tmp_args.pop('debug', None)
175 e3c2c890 Stavros Sachtouris
        tmp_args.pop('verbose', None)
176 e3c2c890 Stavros Sachtouris
        tmp_args.pop('silent', None)
177 e3c2c890 Stavros Sachtouris
        tmp_args.pop('config', None)
178 49e85ee2 Stavros Sachtouris
        help_parser = ArgumentParseManager(
179 9b3c8fd9 Stavros Sachtouris
            cmd_name, tmp_args, required,
180 9b3c8fd9 Stavros Sachtouris
            syntax=syntax, description=descr, check_required=False)
181 56d84a4e Stavros Sachtouris
        return help_parser.print_help
182 e3c2c890 Stavros Sachtouris
183 d53062bd Stavros Sachtouris
    def _register_command(self, cmd_path):
184 fd5db045 Stavros Sachtouris
        cmd = self.cmd_tree.get_command(cmd_path)
185 074f5027 Stavros Sachtouris
        arguments = self._parser.arguments
186 fd5db045 Stavros Sachtouris
187 834200da Stavros Sachtouris
        def do_method(new_context, line):
188 fd5db045 Stavros Sachtouris
            """ Template for all cmd.Cmd methods of the form do_<cmd name>
189 fd5db045 Stavros Sachtouris
                Parse cmd + args and decide to execute or change context
190 fd5db045 Stavros Sachtouris
                <cmd> <term> <term> <args> is always parsed to most specific
191 fd5db045 Stavros Sachtouris
                even if cmd_term_term is not a terminal path
192 fd5db045 Stavros Sachtouris
            """
193 efbcdc41 Stavros Sachtouris
            subcmd, cmd_args = cmd.parse_out(split_input(line))
194 074f5027 Stavros Sachtouris
            self._history.add(' '.join([cmd.path.replace('_', ' '), line]))
195 e3c2c890 Stavros Sachtouris
            cmd_parser = ArgumentParseManager(
196 e3c2c890 Stavros Sachtouris
                cmd.name, dict(self._parser.arguments))
197 074f5027 Stavros Sachtouris
            cmd_parser.parser.description = subcmd.help
198 fd5db045 Stavros Sachtouris
199 fd5db045 Stavros Sachtouris
            # exec command or change context
200 fd5db045 Stavros Sachtouris
            if subcmd.is_command:  # exec command
201 db950b10 Stavros Sachtouris
                try:
202 eb46e9a1 Stavros Sachtouris
                    cls = subcmd.cmd_class
203 56d84a4e Stavros Sachtouris
                    cmd_parser.required = getattr(cls, 'required', None)
204 c8e17a67 Stavros Sachtouris
                    ldescr = getattr(cls, 'long_description', '')
205 c8e17a67 Stavros Sachtouris
                    if subcmd.path == 'history_run':
206 53e1f8d5 Stavros Sachtouris
                        instance = cls(
207 0ec19fd3 Stavros Sachtouris
                            dict(cmd_parser.arguments), self.auth_base,
208 f724cd35 Stavros Sachtouris
                            cmd_tree=self.cmd_tree)
209 c8e17a67 Stavros Sachtouris
                    else:
210 f724cd35 Stavros Sachtouris
                        instance = cls(
211 99085b30 Stavros Sachtouris
                            dict(cmd_parser.arguments),
212 0ec19fd3 Stavros Sachtouris
                            self.auth_base, self.cloud)
213 c8e17a67 Stavros Sachtouris
                    cmd_parser.update_arguments(instance.arguments)
214 c8e17a67 Stavros Sachtouris
                    cmd_parser.arguments = instance.arguments
215 49e85ee2 Stavros Sachtouris
                    subpath = subcmd.path.split('_')[
216 49e85ee2 Stavros Sachtouris
                        (len(cmd.path.split('_')) - 1):]
217 c8e17a67 Stavros Sachtouris
                    cmd_parser.syntax = '%s %s' % (
218 49e85ee2 Stavros Sachtouris
                        ' '.join(subpath), instance.syntax)
219 e3c2c890 Stavros Sachtouris
                    help_method = self._create_help_method(
220 49e85ee2 Stavros Sachtouris
                        cmd.name, cmd_parser.arguments,
221 49e85ee2 Stavros Sachtouris
                        cmd_parser.required, subcmd.help, cmd_parser.syntax)
222 c8e17a67 Stavros Sachtouris
                    if '-h' in cmd_args or '--help' in cmd_args:
223 e3c2c890 Stavros Sachtouris
                        help_method()
224 c8e17a67 Stavros Sachtouris
                        if ldescr.strip():
225 c8e17a67 Stavros Sachtouris
                            print('\nDetails:')
226 c8e17a67 Stavros Sachtouris
                            print('%s' % ldescr)
227 c8e17a67 Stavros Sachtouris
                        return
228 c8e17a67 Stavros Sachtouris
                    cmd_parser.parse(cmd_args)
229 c8e17a67 Stavros Sachtouris
230 c8e17a67 Stavros Sachtouris
                    for name, arg in instance.arguments.items():
231 de73876b Stavros Sachtouris
                        arg.value = getattr(
232 0ec19fd3 Stavros Sachtouris
                            cmd_parser.parsed, name, arg.default)
233 c8e17a67 Stavros Sachtouris
234 e3c2c890 Stavros Sachtouris
                    exec_cmd(instance, cmd_parser.unparsed, help_method)
235 53e1f8d5 Stavros Sachtouris
                        #[term for term in cmd_parser.unparsed\
236 53e1f8d5 Stavros Sachtouris
                        #    if not term.startswith('-')],
237 fce93ff6 Stavros Sachtouris
                except (ClientError, CLIError) as err:
238 b6a99832 Stavros Sachtouris
                    print_error_message(err)
239 de73876b Stavros Sachtouris
            elif ('-h' in cmd_args or '--help' in cmd_args) or len(cmd_args):
240 de73876b Stavros Sachtouris
                # print options
241 a71bb904 Stavros Sachtouris
                print('%s' % cmd.help)
242 b6a99832 Stavros Sachtouris
                print_subcommands_help(cmd)
243 fd5db045 Stavros Sachtouris
            else:  # change context
244 834200da Stavros Sachtouris
                #new_context = this
245 fd5db045 Stavros Sachtouris
                backup_context = self._backup()
246 fd5db045 Stavros Sachtouris
                old_prompt = self.prompt
247 fd5db045 Stavros Sachtouris
                new_context._roll_command(cmd.parent_path)
248 fd5db045 Stavros Sachtouris
                new_context.set_prompt(subcmd.path.replace('_', ' '))
249 eb46e9a1 Stavros Sachtouris
                newcmds = [subcmd for subcmd in subcmd.subcommands.values()]
250 fd5db045 Stavros Sachtouris
                for subcmd in newcmds:
251 d53062bd Stavros Sachtouris
                    new_context._register_command(subcmd.path)
252 fd5db045 Stavros Sachtouris
                new_context.cmdloop()
253 fd5db045 Stavros Sachtouris
                self.prompt = old_prompt
254 fd5db045 Stavros Sachtouris
                #when new context is over, roll back to the old one
255 fd5db045 Stavros Sachtouris
                self._restore(backup_context)
256 fd5db045 Stavros Sachtouris
        self._register_method(do_method, 'do_%s' % cmd.name)
257 fd5db045 Stavros Sachtouris
258 fd5db045 Stavros Sachtouris
        def help_method(self):
259 fd5db045 Stavros Sachtouris
            print('%s (%s -h for more options)' % (cmd.help, cmd.name))
260 54d800e8 Stavros Sachtouris
            if cmd.is_command:
261 eb46e9a1 Stavros Sachtouris
                cls = cmd.cmd_class
262 2fbca093 Stavros Sachtouris
                ldescr = getattr(cls, 'long_description', '')
263 54d800e8 Stavros Sachtouris
                #_construct_command_syntax(cls)
264 54d800e8 Stavros Sachtouris
                plist = self.prompt[len(self._prefix):-len(self._suffix)]
265 54d800e8 Stavros Sachtouris
                plist = plist.split(' ')
266 54d800e8 Stavros Sachtouris
                clist = cmd.path.split('_')
267 54d800e8 Stavros Sachtouris
                upto = 0
268 2fbca093 Stavros Sachtouris
                if ldescr:
269 2fbca093 Stavros Sachtouris
                    print('%s' % ldescr)
270 54d800e8 Stavros Sachtouris
                for i, term in enumerate(plist):
271 54d800e8 Stavros Sachtouris
                    try:
272 54d800e8 Stavros Sachtouris
                        if clist[i] == term:
273 54d800e8 Stavros Sachtouris
                            upto += 1
274 54d800e8 Stavros Sachtouris
                    except IndexError:
275 54d800e8 Stavros Sachtouris
                        break
276 54d800e8 Stavros Sachtouris
                print('Syntax: %s %s' % (' '.join(clist[upto:]), cls.syntax))
277 8741c407 Stavros Sachtouris
            if cmd.subcommands:
278 b6a99832 Stavros Sachtouris
                print_subcommands_help(cmd)
279 54d800e8 Stavros Sachtouris
280 fd5db045 Stavros Sachtouris
        self._register_method(help_method, 'help_%s' % cmd.name)
281 fd5db045 Stavros Sachtouris
282 fd5db045 Stavros Sachtouris
        def complete_method(self, text, line, begidx, endidx):
283 efbcdc41 Stavros Sachtouris
            subcmd, cmd_args = cmd.parse_out(split_input(line)[1:])
284 fd5db045 Stavros Sachtouris
            if subcmd.is_command:
285 eb46e9a1 Stavros Sachtouris
                cls = subcmd.cmd_class
286 834200da Stavros Sachtouris
                instance = cls(dict(arguments))
287 fd5db045 Stavros Sachtouris
                empty, sep, subname = subcmd.path.partition(cmd.path)
288 fd5db045 Stavros Sachtouris
                cmd_name = '%s %s' % (cmd.name, subname.replace('_', ' '))
289 de73876b Stavros Sachtouris
                print('\n%s\nSyntax:\t%s %s' % (
290 eb46e9a1 Stavros Sachtouris
                    cls.help, cmd_name, cls.syntax))
291 fd5db045 Stavros Sachtouris
                cmd_args = {}
292 fd5db045 Stavros Sachtouris
                for arg in instance.arguments.values():
293 fd5db045 Stavros Sachtouris
                    cmd_args[','.join(arg.parsed_name)] = arg.help
294 f55d3a15 Stavros Sachtouris
                print_dict(cmd_args, indent=2)
295 fd5db045 Stavros Sachtouris
                stdout.write('%s %s' % (self.prompt, line))
296 d252a7a8 Stavros Sachtouris
            return subcmd.subnames()
297 fd5db045 Stavros Sachtouris
        self._register_method(complete_method, 'complete_%s' % cmd.name)
298 fd5db045 Stavros Sachtouris
299 fd5db045 Stavros Sachtouris
    @property
300 fd5db045 Stavros Sachtouris
    def doc_header(self):
301 fd5db045 Stavros Sachtouris
        tmp_partition = self.prompt.partition(self._prefix)
302 fd5db045 Stavros Sachtouris
        tmp_partition = tmp_partition[2].partition(self._suffix)
303 fd5db045 Stavros Sachtouris
        hdr = tmp_partition[0].strip()
304 fd5db045 Stavros Sachtouris
        return '%s commands:' % hdr
305 fd5db045 Stavros Sachtouris
306 844a6bdb Stavros Sachtouris
    def run(self, auth_base, cloud, parser, path=''):
307 f724cd35 Stavros Sachtouris
        self.auth_base = auth_base
308 844a6bdb Stavros Sachtouris
        self.cloud = cloud
309 074f5027 Stavros Sachtouris
        self._parser = parser
310 50a32c37 Stavros Sachtouris
        cnf = parser.arguments['config']
311 50a32c37 Stavros Sachtouris
        self._history = History(cnf.get('global', 'history_file'))
312 50a32c37 Stavros Sachtouris
        self._history.limit = cnf.get('global', 'history_limit')
313 db950b10 Stavros Sachtouris
        if path:
314 fd5db045 Stavros Sachtouris
            cmd = self.cmd_tree.get_command(path)
315 fd5db045 Stavros Sachtouris
            intro = cmd.path.replace('_', ' ')
316 fd5db045 Stavros Sachtouris
        else:
317 fd5db045 Stavros Sachtouris
            intro = self.cmd_tree.name
318 fd5db045 Stavros Sachtouris
319 a7aacf12 Stavros Sachtouris
        acceptable = parser.arguments['config'].groups
320 d252a7a8 Stavros Sachtouris
        total = self.cmd_tree.groups.keys()
321 320aac17 Stavros Sachtouris
        self.cmd_tree.exclude(set(total).difference(acceptable))
322 320aac17 Stavros Sachtouris
323 fd5db045 Stavros Sachtouris
        for subcmd in self.cmd_tree.get_subcommands(path):
324 d53062bd Stavros Sachtouris
            self._register_command(subcmd.path)
325 fd5db045 Stavros Sachtouris
326 fd5db045 Stavros Sachtouris
        self.set_prompt(intro)
327 db950b10 Stavros Sachtouris
328 f9af2848 Stavros Sachtouris
        try:
329 f9af2848 Stavros Sachtouris
            self.cmdloop()
330 af569ab9 Stavros Sachtouris
        except Exception as e:
331 af569ab9 Stavros Sachtouris
            print('(%s)' % e)
332 f9af2848 Stavros Sachtouris
            from traceback import print_stack
333 f9af2848 Stavros Sachtouris
            print_stack()