Revision 017d37ce
b/kamaki/cli/__init__.py | ||
---|---|---|
53 | 53 |
from ordereddict import OrderedDict |
54 | 54 |
|
55 | 55 |
#from kamaki import clients |
56 |
from .errors import CLIError |
|
56 |
from .errors import CLIError, CLISyntaxError, CLICmdIncompleteError
|
|
57 | 57 |
from .config import Config #TO BE REMOVED |
58 |
from .utils import magenta, red, yellow, CommandTree
|
|
58 |
from .utils import bold, magenta, red, yellow, CommandTree, print_list
|
|
59 | 59 |
from argument import _arguments, parse_known_args |
60 | 60 |
|
61 | 61 |
_commands = CommandTree() |
62 | 62 |
|
63 |
GROUPS={} |
|
64 |
CLI_LOCATIONS = ['kamaki.cli.commands', 'kamaki.commands', 'kamaki.cli', 'kamaki', ''] |
|
63 |
#basic command groups |
|
65 | 64 |
|
66 | 65 |
def command(): |
67 | 66 |
"""Class decorator that registers a class as a CLI command""" |
... | ... | |
112 | 111 |
else: |
113 | 112 |
|
114 | 113 |
|
114 |
def _expand_cmd(cmd_prefix, unparsed): |
|
115 |
if len(unparsed) == 0: |
|
116 |
return None |
|
117 |
prefix = (cmd_prefix+'_') if len(cmd_prefix) > 0 else '' |
|
118 |
for term in _commands.list(cmd_prefix): |
|
119 |
try: |
|
120 |
unparsed.remove(term) |
|
121 |
except ValueError: |
|
122 |
continue |
|
123 |
return prefix+term |
|
124 |
return None |
|
125 |
|
|
126 |
def _retrieve_cmd(unparsed): |
|
127 |
cmd_str = None |
|
128 |
cur_cmd = _expand_cmd('', unparsed) |
|
129 |
while cur_cmd is not None: |
|
130 |
cmd_str = cur_cmd |
|
131 |
cur_cmd = _expand_cmd(cur_cmd, unparsed) |
|
132 |
if cmd_str is None: |
|
133 |
print(bold('Command groups:')) |
|
134 |
print_list(_commands.get_groups(), ident=14) |
|
135 |
|
|
136 |
return None |
|
137 |
try: |
|
138 |
return _commands.get_class(cmd_str) |
|
139 |
except CLICmdIncompleteError: |
|
140 |
print(bold('%s:'%cmd_str)) |
|
141 |
print_list(_commands.list(cmd_str)) |
|
142 |
return None |
|
143 |
|
|
115 | 144 |
def one_command(): |
116 | 145 |
try: |
117 | 146 |
exe = basename(argv[0]) |
... | ... | |
119 | 148 |
parsed, unparsed = parse_known_args(parser) |
120 | 149 |
if _arguments['version'].value: |
121 | 150 |
exit(0) |
151 |
_commands.set_groups(_arguments['config'].get_groups()) |
|
152 |
cmd = _retrieve_cmd(unparsed) |
|
153 |
|
|
154 |
if cmd is None: |
|
155 |
parser.print_help() |
|
156 |
exit(0) |
|
157 |
|
|
122 | 158 |
except CLIError as err: |
123 | 159 |
_print_error_message(err) |
124 | 160 |
exit(1) |
b/kamaki/cli/argument.py | ||
---|---|---|
142 | 142 |
def value(self, config_file): |
143 | 143 |
self._value = Config(config_file) if config_file is not None else Config() |
144 | 144 |
|
145 |
def get_groups(self): |
|
146 |
return self.value.apis() |
|
147 |
|
|
148 |
|
|
149 |
_config_arg = ConfigArgument(1, 'Path to configuration file', '--config') |
|
150 |
|
|
145 | 151 |
class CmdLineConfigArgument(Argument): |
146 | 152 |
def __init__(self, config_arg, help='', parsed_name=None, default=None): |
147 | 153 |
super(self.__class__, self).__init__(1, help, parsed_name, default) |
... | ... | |
164 | 170 |
raise CLISyntaxError(details='Missing . between section and key: -o section.key=val') |
165 | 171 |
self._config_arg.value.override(section.strip(), key.strip(), val.strip()) |
166 | 172 |
|
167 |
_config_arg = ConfigArgument(1, 'Path to configuration file', '--config') |
|
168 | 173 |
_arguments = dict(config = _config_arg, |
169 | 174 |
debug = Argument(0, 'Include debug output', ('-d', '--debug')), |
170 | 175 |
include = Argument(0, 'Include protocol headers in the output', ('-i', '--include')), |
b/kamaki/cli/errors.py | ||
---|---|---|
55 | 55 |
super(CLIUnknownCommand, self).__init__(message, status, details, importance=0) |
56 | 56 |
|
57 | 57 |
class CLICmdSpecError(CLIError): |
58 |
def __init__(self, message='Command Specification Error', status=13, details=''): |
|
58 |
def __init__(self, message='Command Specification Error', status=13, details='', importance=1):
|
|
59 | 59 |
super(CLICmdSpecError, self).__init__(message, status, details, importance=0) |
60 | 60 |
|
61 |
class CLICmdIncompleteError(CLICmdSpecError): |
|
62 |
def __init__(self, message='Incomplete Command Error', status=14, details=''): |
|
63 |
super(CLICmdSpecError, self).__init__(message, status, details, importance=1) |
|
64 |
|
|
61 | 65 |
def raiseCLIError(err, importance = -1): |
62 | 66 |
if importance < 0: |
63 | 67 |
if err.status <= 0: |
b/kamaki/cli/utils.py | ||
---|---|---|
38 | 38 |
return val |
39 | 39 |
red = yellow = magenta = bold |
40 | 40 |
|
41 |
from .errors import CLIUnknownCommand, CLICmdSpecError, CLIError |
|
41 |
from .errors import CLIUnknownCommand, CLICmdIncompleteError, CLICmdSpecError, CLIError
|
|
42 | 42 |
|
43 | 43 |
""" |
44 | 44 |
def magenta(val): |
... | ... | |
88 | 88 |
def __init__(self): |
89 | 89 |
self._commands = {} |
90 | 90 |
|
91 |
def set_groups(self, groups): |
|
92 |
for grp in groups: |
|
93 |
self._commands[grp] = {} |
|
94 |
|
|
95 |
def get_groups(self): |
|
96 |
return self._commands.keys() |
|
97 |
|
|
91 | 98 |
def _get_commands_from_prefix(self, prefix): |
99 |
if len(prefix) == 0: |
|
100 |
return self._commands |
|
92 | 101 |
path = get_pathlist_from_prefix(prefix) |
93 | 102 |
next_list = self._commands |
94 | 103 |
try: |
... | ... | |
116 | 125 |
except ValueError: |
117 | 126 |
return ret |
118 | 127 |
|
119 |
def is_full_command(self, command):
|
|
128 |
def get_class(self, command):
|
|
120 | 129 |
""" Check if a command exists as a full/terminal command |
121 | 130 |
e.g. store_list is full, store is partial, stort is not existing |
122 | 131 |
@param command can either be a cmd1_cmd2_... str or a ['cmd1, cmd2, ...'] list |
... | ... | |
124 | 133 |
@raise CLIUnknownCommand if command is unknown to this tree |
125 | 134 |
""" |
126 | 135 |
next_level = self._get_commands_from_prefix(command) |
127 |
if '_class' in next_level.keys(): |
|
128 |
return True |
|
129 |
return False |
|
136 |
try: |
|
137 |
return next_level['_class'] |
|
138 |
except KeyError: |
|
139 |
raise CLICmdIncompleteError(details='Cmd %s is not a full cmd'%command) |
|
130 | 140 |
|
131 | 141 |
def add(self, command, cmd_class): |
132 | 142 |
"""Add a command_path-->cmd_class relation to the path """ |
... | ... | |
146 | 156 |
try: |
147 | 157 |
cmds = cmds[cmd] |
148 | 158 |
except KeyError: |
149 |
raise CLIUnknownCommand('set_description to cmd %s failed: cmd not found'%command) |
|
159 |
raise CLIUnknownCommand(details='set_description to cmd %s failed: cmd not found'%command)
|
|
150 | 160 |
cmds['_description'] = description |
161 |
|
|
151 | 162 |
def load_spec_package(self, spec_package): |
152 | 163 |
loaded = False |
153 | 164 |
for location in self.cmd_spec_locations: |
... | ... | |
159 | 170 |
except ImportError: |
160 | 171 |
pass |
161 | 172 |
if not loaded: |
162 |
raise CLICmdSpecError('Cmd Spec Package %s load failed'%spec_package) |
|
173 |
raise CLICmdSpecError(details='Cmd Spec Package %s load failed'%spec_package)
|
|
163 | 174 |
|
164 | 175 |
def load_spec(self, spec_package, spec): |
165 | 176 |
"""Load spec from a non nessecery loaded spec package""" |
... | ... | |
177 | 188 |
raise CLICmdSpecError('Cmd Spec %s load failed'%spec) |
178 | 189 |
|
179 | 190 |
def get_pathlist_from_prefix(prefix): |
180 |
return prefix if isinstance(prefix,list) else unicode(prefix).split('_') |
|
191 |
if isinstance(prefix, list): |
|
192 |
return prefix |
|
193 |
if len(prefix) == 0: |
|
194 |
return [] |
|
195 |
return unicode(prefix).split('_') |
|
181 | 196 |
|
182 | 197 |
def pretty_keys(d, delim='_', recurcive=False): |
183 | 198 |
"""Transform keys of a dict from the form |
Also available in: Unified diff