1 # Copyright 2012 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 class Command(object):
36 """Store a command and the next-level (2 levels)"""
43 def __init__(self, path, help=' ', subcommands={}, cmd_class=None):
46 self.subcommands = dict(subcommands)
47 self.cmd_class = cmd_class
51 if self._name is None:
52 self._name = self.path.split('_')[-1]
53 return str(self._name)
55 def add_subcmd(self, subcmd):
56 if subcmd.path == '%s_%s' % (self.path, subcmd.name):
57 self.subcommands[subcmd.name] = subcmd
61 def get_subcmd(self, name):
63 return self.subcommands[name]
67 def contains(self, name):
68 """Check if a name is a direct child of self"""
69 return name in self.subcommands
73 return self.cmd_class is not None
76 def has_description(self):
77 return len(self.help.strip()) > 0
80 def description(self):
84 def parent_path(self):
85 parentpath, sep, name = self.path.rpartition('_')
88 def set_class(self, cmd_class):
89 self.cmd_class = cmd_class
94 def has_subname(self, subname):
95 return subname in self.subcommands
97 def get_subnames(self):
98 return self.subcommands.keys()
100 def get_subcommands(self):
101 return self.subcommands.values()
104 return len(self.subcommands)
106 def parse_out(self, args):
111 cmd = cmd.subcommands[term]
115 return cmd, args[index:]
117 def pretty_print(self, recursive=False):
118 print('Path: %s (Name: %s) is_cmd: %s\n\thelp: %s'\
119 % (self.path, self.name, self.is_command, self.help))
120 for cmd in self.get_subcommands():
121 cmd.pretty_print(recursive)
124 class CommandTree(object):
131 def __init__(self, name, description=''):
133 self.description = description
135 def add_command(self, command_path, description=None, cmd_class=None):
136 terms = command_path.split('_')
138 cmd = self.groups[terms[0]]
140 cmd = Command(terms[0])
141 self.groups[terms[0]] = cmd
142 self._all_commands[terms[0]] = cmd
144 for term in terms[1:]:
147 cmd = cmd.subcommands[term]
149 new_cmd = Command(path)
150 self._all_commands[path] = new_cmd
151 cmd.add_subcmd(new_cmd)
153 if cmd_class is not None:
154 cmd.set_class(cmd_class)
155 if description is not None:
156 cmd.help = description
158 def add_tree(self, new_tree):
159 tname = new_tree.name
160 tdesc = new_tree.description
161 self.groups.update(new_tree.groups)
162 self._all_commands.update(new_tree._all_commands)
163 self.set_description(tname, tdesc)
165 def has_command(self, path):
166 return path in self._all_commands
168 def get_command(self, path):
169 return self._all_commands[path]
171 def get_groups(self):
172 return self.groups.values()
174 def get_group_names(self):
175 return self.groups.keys()
177 def set_description(self, path, description):
178 self._all_commands[path].help = description
180 def get_description(self, path):
181 return self._all_commands[path].help
183 def set_class(self, path, cmd_class):
184 self._all_commands[path].set_class(cmd_class)
186 def get_class(self, path):
187 return self._all_commands[path].get_class()
189 def get_subnames(self, path=None):
190 return self.get_group_names() if path in (None, '') \
191 else self._all_commands[path].get_subnames()
193 def get_subcommands(self, path=None):
194 return self.get_groups() if path in (None, '') \
195 else self._all_commands[path].get_subcommands()
197 def get_parent(self, path):
200 terms = path.split('_')
201 parent_path = '_'.join(terms[:-1])
202 return self._all_commands[parent_path]
204 def get_closest_ancestor_command(self, path):
205 path, sep, name = path.rpartition('_')
207 cmd = self._all_commands[path]
210 path, sep, name = path.rpartition('_')
215 terms = path.split()[:-1]
216 while len(terms) > 0:
217 tmp_path = '_'.join(terms)
218 cmd = self._all_commands[tmp_path]
222 raise KeyError('No ancestor commands')
224 def pretty_print(self, group=None):
226 for group in self.groups:
227 self.pretty_print(group)
229 self.groups[group].pretty_print(recursive=True)