1 # Copyright 2011 GRNET S.A. All rights reserved.
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
7 # 1. Redistributions of source code must retain the above
8 # copyright notice, this list of conditions and the following
11 # 2. Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following
13 # disclaimer in the documentation and/or other materials
14 # provided with the distribution.
16 # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 # POSSIBILITY OF SUCH DAMAGE.
29 # The views and conclusions contained in the software and
30 # documentation are those of the authors and should not be
31 # interpreted as representing official policies, either expressed
32 # or implied, of GRNET S.A.
35 #from .errors import CLIUnknownCommand, CLICmdIncompleteError, CLICmdSpecError, CLIError
37 class Command(object):
38 """Store a command and the next-level commands as well - no deep tree here"""
45 def __init__(self, path, help = ' ', subcommands={}, cmd_class=None):
48 self.subcommands =dict(subcommands)
49 self.cmd_class = cmd_class
53 if self._name is None:
54 self._name = self.path.split('_')[-1]
55 return str(self._name)
57 def add_subcmd(self, subcmd):
58 if subcmd.path == self.path+'_'+subcmd.name:
59 self.subcommands[subcmd.name] = subcmd
62 def get_subcmd(self, name):
64 return self.subcommands[name]
68 def contains(self, name):
69 """Check if a name is a direct child of self"""
70 return self.subcommands.has_key(name)
74 return self.cmd_class is not None
76 def has_description(self):
77 return len(self.help.strip()) > 0
79 def description(self):
82 def set_class(self, cmd_class):
83 self.cmd_class = cmd_class
87 def get_subnames(self):
88 return self.subcommands.keys()
89 def get_subcommands(self):
90 return self.subcommands.values()
92 return len(self.subcommands)
94 def pretty_print(self, recursive=False):
95 print('Path: %s (Name: %s) is_cmd: %s\n\thelp: %s'%(self.path, self.name,
96 self.is_command, self.help))
97 for cmd in self.get_subcommands():
98 cmd.pretty_print(recursive)
101 cmd = Command('store', 'A store thingy')
102 cmd.add_subcmd(Command('store_list'))
103 tmp = cmd.get_subcmd('list')
104 tmp.add_subcmd(Command('store_list_all', 'List everything'))
105 tmp.add_subcmd(Command('store_list_one', 'List just one stuff'))
106 cmd.pretty_print(True)
108 class CommandTree(object):
115 def __init__(self, name, description=''):
117 self.description = description
119 def add_command(self, command_path, description=None, cmd_class=None):
120 terms = command_path.split('_')
122 cmd = self.groups[terms[0]]
124 cmd = Command(terms[0])
125 self.groups[terms[0]] = cmd
126 self._all_commands[terms[0]] = cmd
128 for term in terms[1:]:
131 cmd = cmd.subcommands[term]
133 new_cmd = Command(path)
134 self._all_commands[path] = new_cmd
135 cmd.add_subcmd(new_cmd)
137 if cmd_class is not None:
138 cmd.set_class(cmd_class)
139 if description is not None:
140 cmd.help = description
141 def get_command(self, path):
142 return self._all_commands[path]
143 def get_groups(self):
144 return self.groups.values()
145 def get_group_names(self):
146 return self.groups.keys()
148 def set_description(self, path, description):
149 self._all_commands[path].help = description
150 def get_descitpion(self, path):
151 return self._all_commands[path].help
152 def set_class(self, path, cmd_class):
153 self._all_commands[path].set_class(cmd_class)
154 def get_class(self, path):
155 return self._all_commands[path].get_class()
157 def get_subnames(self, path):
158 return self._all_commands[path].get_subnames()
159 def get_subcommands(self, path):
160 return self._all_commands[path].get_subcommands()
161 def get_parent(self, path):
164 terms = path.split('_')
165 parent_path = '_'.join(terms[:-1])
166 return self._all_commands[parent_path]
167 def get_closest_ancestor_command(self, path):
168 path, sep, name = path.rpartition('_')
170 cmd = self._all_commands[path]
173 path, sep, name = path.rpartition('_')
179 while len(terms) > 0:
180 tmp_path = '_'.join(terms)
181 cmd = self._all_commands[tmp_path]
185 raise KeyError('No ancestor commands')
187 def pretty_print(self, group=None):
189 for group in self.groups:
190 self.pretty_print(group)
192 self.groups[group].pretty_print(recursive=True)
194 def test_CommandTree():
195 tree = CommandTree('kamaki', 'the kamaki tools')
196 tree.add_command('store', 'A storage thingy')
197 tree.add_command('server_list_lala', description='A testing server list', cmd_class=Shell)
198 tree.add_command('store_list_all', 'List all things', cmd_class=Command)
199 tree.add_command('store_list', 'List smthing pls', cmd_class=Shell)
200 tree.add_command('server_list', description='A server list subgrp')
201 tree.add_command('server', description='A server is a SERVER', cmd_class=CommandTree)
202 tree.set_class('server', None)
203 tree.set_description('server_list', '')
204 if tree.get_class('server_list_lala') is Shell:
205 print('server_list_lala is Shell')
207 print('server_list_lala is not Shell')
209 print('store_list_all closest parent command is %s'%tree.get_closest_ancestor_command('store_list_all').path)
210 tree.set_class('store', tree.get_command('store_list').get_class())
211 tree.set_class('store_list', None)
212 print('store_list_all closest parent command is %s'%tree.get_closest_ancestor_command('store_list_all').path)
214 print('nonexisting_list_command closest parent is %s'%tree.get_closest_ancestor_command('nonexisting_list_command').path)
216 print('Aparrently nonexisting_list_command is nonexisting ')
218 class Shell(cmd.Cmd):
219 """Simple command processor example."""
221 def do_greet(self, line):
226 def do_lala(self, lala):
227 print('This is what I got: %s'%lala)
229 print('This is SPAAARTAAAAAAA')
231 def do_lalum(self, args):
233 def complete_lalum(self, text, line, begidx, endidx):
234 completions = ['lala']
237 def do_EOF(self, line):
241 #sh.prompt = 'lala_$ '
245 #sh.onecmd(' '.join(sys.argv[1:]))