root / kamaki / cli / command_tree.py @ 5eae854d
History | View | Annotate | Download (7.8 kB)
1 | 00af4193 | Stavros Sachtouris | # Copyright 2011 GRNET S.A. All rights reserved.
|
---|---|---|---|
2 | 00af4193 | Stavros Sachtouris | #
|
3 | 00af4193 | Stavros Sachtouris | # Redistribution and use in source and binary forms, with or
|
4 | 00af4193 | Stavros Sachtouris | # without modification, are permitted provided that the following
|
5 | 00af4193 | Stavros Sachtouris | # conditions are met:
|
6 | 00af4193 | Stavros Sachtouris | #
|
7 | 00af4193 | Stavros Sachtouris | # 1. Redistributions of source code must retain the above
|
8 | 00af4193 | Stavros Sachtouris | # copyright notice, this list of conditions and the following
|
9 | 00af4193 | Stavros Sachtouris | # disclaimer.
|
10 | 00af4193 | Stavros Sachtouris | #
|
11 | 00af4193 | Stavros Sachtouris | # 2. Redistributions in binary form must reproduce the above
|
12 | 00af4193 | Stavros Sachtouris | # copyright notice, this list of conditions and the following
|
13 | 00af4193 | Stavros Sachtouris | # disclaimer in the documentation and/or other materials
|
14 | 00af4193 | Stavros Sachtouris | # provided with the distribution.
|
15 | 00af4193 | Stavros Sachtouris | #
|
16 | 00af4193 | Stavros Sachtouris | # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
17 | 00af4193 | Stavros Sachtouris | # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18 | 00af4193 | Stavros Sachtouris | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19 | 00af4193 | Stavros Sachtouris | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
20 | 00af4193 | Stavros Sachtouris | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
21 | 00af4193 | Stavros Sachtouris | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
22 | 00af4193 | Stavros Sachtouris | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
23 | 00af4193 | Stavros Sachtouris | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
24 | 00af4193 | Stavros Sachtouris | # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 | 00af4193 | Stavros Sachtouris | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
26 | 00af4193 | Stavros Sachtouris | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27 | 00af4193 | Stavros Sachtouris | # POSSIBILITY OF SUCH DAMAGE.
|
28 | 00af4193 | Stavros Sachtouris | #
|
29 | 00af4193 | Stavros Sachtouris | # The views and conclusions contained in the software and
|
30 | 00af4193 | Stavros Sachtouris | # documentation are those of the authors and should not be
|
31 | 00af4193 | Stavros Sachtouris | # interpreted as representing official policies, either expressed
|
32 | 00af4193 | Stavros Sachtouris | # or implied, of GRNET S.A.
|
33 | 00af4193 | Stavros Sachtouris | |
34 | 00af4193 | Stavros Sachtouris | import cmd |
35 | d9325478 | Stavros Sachtouris | #from .errors import CLIUnknownCommand, CLICmdIncompleteError, CLICmdSpecError, CLIError
|
36 | 00af4193 | Stavros Sachtouris | |
37 | 00af4193 | Stavros Sachtouris | class Command(object): |
38 | 00af4193 | Stavros Sachtouris | """Store a command and the next-level commands as well - no deep tree here"""
|
39 | 00af4193 | Stavros Sachtouris | _name = None
|
40 | 00af4193 | Stavros Sachtouris | path = None
|
41 | 00af4193 | Stavros Sachtouris | cmd_class = None
|
42 | 00af4193 | Stavros Sachtouris | subcommands = {} |
43 | 00af4193 | Stavros Sachtouris | help = ' '
|
44 | 00af4193 | Stavros Sachtouris | |
45 | 00af4193 | Stavros Sachtouris | def __init__(self, path, help = ' ', subcommands={}, cmd_class=None): |
46 | 00af4193 | Stavros Sachtouris | self.path = path
|
47 | 00af4193 | Stavros Sachtouris | self.help = help
|
48 | 00af4193 | Stavros Sachtouris | self.subcommands =dict(subcommands) |
49 | 00af4193 | Stavros Sachtouris | self.cmd_class = cmd_class
|
50 | 00af4193 | Stavros Sachtouris | |
51 | 00af4193 | Stavros Sachtouris | @property
|
52 | 00af4193 | Stavros Sachtouris | def name(self): |
53 | 00af4193 | Stavros Sachtouris | if self._name is None: |
54 | 00af4193 | Stavros Sachtouris | self._name = self.path.split('_')[-1] |
55 | 00af4193 | Stavros Sachtouris | return str(self._name) |
56 | 00af4193 | Stavros Sachtouris | |
57 | 00af4193 | Stavros Sachtouris | def add_subcmd(self, subcmd): |
58 | 00af4193 | Stavros Sachtouris | if subcmd.path == self.path+'_'+subcmd.name: |
59 | 00af4193 | Stavros Sachtouris | self.subcommands[subcmd.name] = subcmd
|
60 | 00af4193 | Stavros Sachtouris | return True |
61 | 00af4193 | Stavros Sachtouris | return False |
62 | 00af4193 | Stavros Sachtouris | def get_subcmd(self, name): |
63 | 00af4193 | Stavros Sachtouris | try:
|
64 | 00af4193 | Stavros Sachtouris | return self.subcommands[name] |
65 | 00af4193 | Stavros Sachtouris | except KeyError: |
66 | 00af4193 | Stavros Sachtouris | return None |
67 | 00af4193 | Stavros Sachtouris | |
68 | 00af4193 | Stavros Sachtouris | def contains(self, name): |
69 | 00af4193 | Stavros Sachtouris | """Check if a name is a direct child of self"""
|
70 | 00af4193 | Stavros Sachtouris | return self.subcommands.has_key(name) |
71 | 00af4193 | Stavros Sachtouris | |
72 | d9325478 | Stavros Sachtouris | @property
|
73 | 00af4193 | Stavros Sachtouris | def is_command(self): |
74 | 00af4193 | Stavros Sachtouris | return self.cmd_class is not None |
75 | d9325478 | Stavros Sachtouris | @property
|
76 | d9325478 | Stavros Sachtouris | def has_description(self): |
77 | d9325478 | Stavros Sachtouris | return len(self.help.strip()) > 0 |
78 | d9325478 | Stavros Sachtouris | @property
|
79 | d9325478 | Stavros Sachtouris | def description(self): |
80 | d9325478 | Stavros Sachtouris | return self.help |
81 | 00af4193 | Stavros Sachtouris | |
82 | 00af4193 | Stavros Sachtouris | def set_class(self, cmd_class): |
83 | 00af4193 | Stavros Sachtouris | self.cmd_class = cmd_class
|
84 | 00af4193 | Stavros Sachtouris | def get_class(self): |
85 | 00af4193 | Stavros Sachtouris | return self.cmd_class |
86 | 00af4193 | Stavros Sachtouris | |
87 | 629adab4 | Stavros Sachtouris | def has_subname(self, subname): |
88 | 629adab4 | Stavros Sachtouris | return self.subcommands.has_key(subname) |
89 | 00af4193 | Stavros Sachtouris | def get_subnames(self): |
90 | 00af4193 | Stavros Sachtouris | return self.subcommands.keys() |
91 | 00af4193 | Stavros Sachtouris | def get_subcommands(self): |
92 | 00af4193 | Stavros Sachtouris | return self.subcommands.values() |
93 | 00af4193 | Stavros Sachtouris | def sublen(self): |
94 | 00af4193 | Stavros Sachtouris | return len(self.subcommands) |
95 | 00af4193 | Stavros Sachtouris | |
96 | 629adab4 | Stavros Sachtouris | def parse_out(self, args): |
97 | 629adab4 | Stavros Sachtouris | cmd = self
|
98 | 629adab4 | Stavros Sachtouris | index = 0
|
99 | 629adab4 | Stavros Sachtouris | for term in args: |
100 | 629adab4 | Stavros Sachtouris | try:
|
101 | 629adab4 | Stavros Sachtouris | cmd = cmd.subcommands[term] |
102 | 629adab4 | Stavros Sachtouris | except KeyError: |
103 | 629adab4 | Stavros Sachtouris | break
|
104 | 629adab4 | Stavros Sachtouris | index += 1
|
105 | 629adab4 | Stavros Sachtouris | return cmd, args[index:]
|
106 | 629adab4 | Stavros Sachtouris | |
107 | 00af4193 | Stavros Sachtouris | def pretty_print(self, recursive=False): |
108 | 00af4193 | Stavros Sachtouris | print('Path: %s (Name: %s) is_cmd: %s\n\thelp: %s'%(self.path, self.name, |
109 | d9325478 | Stavros Sachtouris | self.is_command, self.help)) |
110 | 00af4193 | Stavros Sachtouris | for cmd in self.get_subcommands(): |
111 | 00af4193 | Stavros Sachtouris | cmd.pretty_print(recursive) |
112 | 00af4193 | Stavros Sachtouris | |
113 | 00af4193 | Stavros Sachtouris | def test_Command(): |
114 | 00af4193 | Stavros Sachtouris | cmd = Command('store', 'A store thingy') |
115 | 00af4193 | Stavros Sachtouris | cmd.add_subcmd(Command('store_list'))
|
116 | 00af4193 | Stavros Sachtouris | tmp = cmd.get_subcmd('list')
|
117 | 00af4193 | Stavros Sachtouris | tmp.add_subcmd(Command('store_list_all', 'List everything')) |
118 | 00af4193 | Stavros Sachtouris | tmp.add_subcmd(Command('store_list_one', 'List just one stuff')) |
119 | 00af4193 | Stavros Sachtouris | cmd.pretty_print(True)
|
120 | 00af4193 | Stavros Sachtouris | |
121 | d9325478 | Stavros Sachtouris | class CommandTree(object): |
122 | d9325478 | Stavros Sachtouris | |
123 | d9325478 | Stavros Sachtouris | groups = {} |
124 | d9325478 | Stavros Sachtouris | _all_commands = {} |
125 | d9325478 | Stavros Sachtouris | name = None
|
126 | d9325478 | Stavros Sachtouris | description = None
|
127 | d9325478 | Stavros Sachtouris | |
128 | d9325478 | Stavros Sachtouris | def __init__(self, name, description=''): |
129 | d9325478 | Stavros Sachtouris | self.name = name
|
130 | d9325478 | Stavros Sachtouris | self.description = description
|
131 | d9325478 | Stavros Sachtouris | |
132 | d9325478 | Stavros Sachtouris | def add_command(self, command_path, description=None, cmd_class=None): |
133 | d9325478 | Stavros Sachtouris | terms = command_path.split('_')
|
134 | d9325478 | Stavros Sachtouris | try:
|
135 | d9325478 | Stavros Sachtouris | cmd = self.groups[terms[0]] |
136 | d9325478 | Stavros Sachtouris | except KeyError: |
137 | d9325478 | Stavros Sachtouris | cmd = Command(terms[0])
|
138 | d9325478 | Stavros Sachtouris | self.groups[terms[0]] = cmd |
139 | d9325478 | Stavros Sachtouris | self._all_commands[terms[0]] = cmd |
140 | d9325478 | Stavros Sachtouris | path = terms[0]
|
141 | d9325478 | Stavros Sachtouris | for term in terms[1:]: |
142 | d9325478 | Stavros Sachtouris | path += '_'+term
|
143 | d9325478 | Stavros Sachtouris | try:
|
144 | d9325478 | Stavros Sachtouris | cmd = cmd.subcommands[term] |
145 | d9325478 | Stavros Sachtouris | except KeyError: |
146 | d9325478 | Stavros Sachtouris | new_cmd = Command(path) |
147 | d9325478 | Stavros Sachtouris | self._all_commands[path] = new_cmd
|
148 | d9325478 | Stavros Sachtouris | cmd.add_subcmd(new_cmd) |
149 | d9325478 | Stavros Sachtouris | cmd = new_cmd |
150 | d9325478 | Stavros Sachtouris | if cmd_class is not None: |
151 | d9325478 | Stavros Sachtouris | cmd.set_class(cmd_class) |
152 | d9325478 | Stavros Sachtouris | if description is not None: |
153 | d9325478 | Stavros Sachtouris | cmd.help = description |
154 | d9325478 | Stavros Sachtouris | def get_command(self, path): |
155 | d9325478 | Stavros Sachtouris | return self._all_commands[path] |
156 | d9325478 | Stavros Sachtouris | def get_groups(self): |
157 | d9325478 | Stavros Sachtouris | return self.groups.values() |
158 | d9325478 | Stavros Sachtouris | def get_group_names(self): |
159 | d9325478 | Stavros Sachtouris | return self.groups.keys() |
160 | d9325478 | Stavros Sachtouris | |
161 | d9325478 | Stavros Sachtouris | def set_description(self, path, description): |
162 | d9325478 | Stavros Sachtouris | self._all_commands[path].help = description
|
163 | d9325478 | Stavros Sachtouris | def get_descitpion(self, path): |
164 | d9325478 | Stavros Sachtouris | return self._all_commands[path].help |
165 | d9325478 | Stavros Sachtouris | def set_class(self, path, cmd_class): |
166 | d9325478 | Stavros Sachtouris | self._all_commands[path].set_class(cmd_class)
|
167 | d9325478 | Stavros Sachtouris | def get_class(self, path): |
168 | d9325478 | Stavros Sachtouris | return self._all_commands[path].get_class() |
169 | d9325478 | Stavros Sachtouris | |
170 | 73e0914d | Stavros Sachtouris | def get_subnames(self, path=None): |
171 | 73e0914d | Stavros Sachtouris | return self.get_group_names() if path in (None, '') \ |
172 | 73e0914d | Stavros Sachtouris | else self._all_commands[path].get_subnames() |
173 | 73e0914d | Stavros Sachtouris | def get_subcommands(self, path=None): |
174 | 73e0914d | Stavros Sachtouris | return self.get_groups() if path in (None, '') \ |
175 | 73e0914d | Stavros Sachtouris | else self._all_commands[path].get_subcommands() |
176 | d9325478 | Stavros Sachtouris | def get_parent(self, path): |
177 | d9325478 | Stavros Sachtouris | if '_' not in path: |
178 | d9325478 | Stavros Sachtouris | return None |
179 | d9325478 | Stavros Sachtouris | terms = path.split('_')
|
180 | d9325478 | Stavros Sachtouris | parent_path = '_'.join(terms[:-1]) |
181 | d9325478 | Stavros Sachtouris | return self._all_commands[parent_path] |
182 | d9325478 | Stavros Sachtouris | def get_closest_ancestor_command(self, path): |
183 | d9325478 | Stavros Sachtouris | path, sep, name = path.rpartition('_')
|
184 | d9325478 | Stavros Sachtouris | while len(path) > 0: |
185 | d9325478 | Stavros Sachtouris | cmd = self._all_commands[path]
|
186 | d9325478 | Stavros Sachtouris | if cmd.is_command:
|
187 | d9325478 | Stavros Sachtouris | return cmd
|
188 | d9325478 | Stavros Sachtouris | path, sep, name = path.rpartition('_')
|
189 | d9325478 | Stavros Sachtouris | return None |
190 | d9325478 | Stavros Sachtouris | |
191 | d9325478 | Stavros Sachtouris | if '_' not in path: |
192 | d9325478 | Stavros Sachtouris | return None |
193 | d9325478 | Stavros Sachtouris | terms = terms[:-1]
|
194 | d9325478 | Stavros Sachtouris | while len(terms) > 0: |
195 | d9325478 | Stavros Sachtouris | tmp_path = '_'.join(terms)
|
196 | d9325478 | Stavros Sachtouris | cmd = self._all_commands[tmp_path]
|
197 | d9325478 | Stavros Sachtouris | if cmd.is_command:
|
198 | d9325478 | Stavros Sachtouris | return cmd
|
199 | d9325478 | Stavros Sachtouris | terms = terms[:-1]
|
200 | d9325478 | Stavros Sachtouris | raise KeyError('No ancestor commands') |
201 | d9325478 | Stavros Sachtouris | |
202 | d9325478 | Stavros Sachtouris | def pretty_print(self, group=None): |
203 | d9325478 | Stavros Sachtouris | if group is None: |
204 | d9325478 | Stavros Sachtouris | for group in self.groups: |
205 | d9325478 | Stavros Sachtouris | self.pretty_print(group)
|
206 | d9325478 | Stavros Sachtouris | else:
|
207 | d9325478 | Stavros Sachtouris | self.groups[group].pretty_print(recursive=True) |
208 | d9325478 | Stavros Sachtouris | |
209 | d9325478 | Stavros Sachtouris | def test_CommandTree(): |
210 | d9325478 | Stavros Sachtouris | tree = CommandTree('kamaki', 'the kamaki tools') |
211 | d9325478 | Stavros Sachtouris | tree.add_command('store', 'A storage thingy') |
212 | d9325478 | Stavros Sachtouris | tree.add_command('server_list_lala', description='A testing server list', cmd_class=Shell) |
213 | d9325478 | Stavros Sachtouris | tree.add_command('store_list_all', 'List all things', cmd_class=Command) |
214 | d9325478 | Stavros Sachtouris | tree.add_command('store_list', 'List smthing pls', cmd_class=Shell) |
215 | d9325478 | Stavros Sachtouris | tree.add_command('server_list', description='A server list subgrp') |
216 | d9325478 | Stavros Sachtouris | tree.add_command('server', description='A server is a SERVER', cmd_class=CommandTree) |
217 | d9325478 | Stavros Sachtouris | tree.set_class('server', None) |
218 | d9325478 | Stavros Sachtouris | tree.set_description('server_list', '') |
219 | d9325478 | Stavros Sachtouris | if tree.get_class('server_list_lala') is Shell: |
220 | d9325478 | Stavros Sachtouris | print('server_list_lala is Shell')
|
221 | d9325478 | Stavros Sachtouris | else:
|
222 | d9325478 | Stavros Sachtouris | print('server_list_lala is not Shell')
|
223 | d9325478 | Stavros Sachtouris | tree.pretty_print() |
224 | d9325478 | Stavros Sachtouris | print('store_list_all closest parent command is %s'%tree.get_closest_ancestor_command('store_list_all').path) |
225 | d9325478 | Stavros Sachtouris | tree.set_class('store', tree.get_command('store_list').get_class()) |
226 | d9325478 | Stavros Sachtouris | tree.set_class('store_list', None) |
227 | d9325478 | Stavros Sachtouris | print('store_list_all closest parent command is %s'%tree.get_closest_ancestor_command('store_list_all').path) |
228 | d9325478 | Stavros Sachtouris | try:
|
229 | d9325478 | Stavros Sachtouris | print('nonexisting_list_command closest parent is %s'%tree.get_closest_ancestor_command('nonexisting_list_command').path) |
230 | d9325478 | Stavros Sachtouris | except KeyError: |
231 | d9325478 | Stavros Sachtouris | print('Aparrently nonexisting_list_command is nonexisting ')
|
232 | d9325478 | Stavros Sachtouris | |
233 | 00af4193 | Stavros Sachtouris | class Shell(cmd.Cmd): |
234 | 00af4193 | Stavros Sachtouris | """Simple command processor example."""
|
235 | 00af4193 | Stavros Sachtouris | |
236 | 00af4193 | Stavros Sachtouris | def do_greet(self, line): |
237 | 00af4193 | Stavros Sachtouris | """Hello [cmd]
|
238 | 00af4193 | Stavros Sachtouris | @line some line"""
|
239 | 00af4193 | Stavros Sachtouris | print "hello" |
240 | 00af4193 | Stavros Sachtouris | |
241 | 00af4193 | Stavros Sachtouris | def do_lala(self, lala): |
242 | 00af4193 | Stavros Sachtouris | print('This is what I got: %s'%lala)
|
243 | 00af4193 | Stavros Sachtouris | def help_lala(self): |
244 | 00af4193 | Stavros Sachtouris | print('This is SPAAARTAAAAAAA')
|
245 | 00af4193 | Stavros Sachtouris | |
246 | 00af4193 | Stavros Sachtouris | def do_lalum(self, args): |
247 | 00af4193 | Stavros Sachtouris | print('lalum')
|
248 | 00af4193 | Stavros Sachtouris | def complete_lalum(self, text, line, begidx, endidx): |
249 | 00af4193 | Stavros Sachtouris | completions = ['lala']
|
250 | 00af4193 | Stavros Sachtouris | return completions
|
251 | 00af4193 | Stavros Sachtouris | |
252 | 00af4193 | Stavros Sachtouris | def do_EOF(self, line): |
253 | 00af4193 | Stavros Sachtouris | return True |
254 | 00af4193 | Stavros Sachtouris | |
255 | 1c1fd2fa | Stavros Sachtouris | if __name__ == '__main__': |
256 | 1c1fd2fa | Stavros Sachtouris | sh = Shell() |
257 | 1c1fd2fa | Stavros Sachtouris | sh.prompt = 'lala_$ '
|
258 | 1c1fd2fa | Stavros Sachtouris | sh.cmdloop() |
259 | 1c1fd2fa | Stavros Sachtouris | |
260 | 1c1fd2fa | Stavros Sachtouris | #import sys
|
261 | 1c1fd2fa | Stavros Sachtouris | #sh.onecmd(' '.join(sys.argv[1:]))
|
262 | 1c1fd2fa | Stavros Sachtouris | #test_CommandTree() |