Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / __init__.py @ 362adf50

History | View | Annotate | Download (15.2 kB)

1 d486baec Stavros Sachtouris
# Copyright 2012-2013 GRNET S.A. All rights reserved.
2 7493ccb6 Stavros Sachtouris
#
3 7493ccb6 Stavros Sachtouris
# Redistribution and use in source and binary forms, with or
4 7493ccb6 Stavros Sachtouris
# without modification, are permitted provided that the following
5 7493ccb6 Stavros Sachtouris
# conditions are met:
6 7493ccb6 Stavros Sachtouris
#
7 7493ccb6 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 7493ccb6 Stavros Sachtouris
#
11 7493ccb6 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 7493ccb6 Stavros Sachtouris
#
16 7493ccb6 Stavros Sachtouris
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 7493ccb6 Stavros Sachtouris
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 7493ccb6 Stavros Sachtouris
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 7493ccb6 Stavros Sachtouris
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 7493ccb6 Stavros Sachtouris
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 7493ccb6 Stavros Sachtouris
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 7493ccb6 Stavros Sachtouris
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 7493ccb6 Stavros Sachtouris
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 7493ccb6 Stavros Sachtouris
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 7493ccb6 Stavros Sachtouris
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 7493ccb6 Stavros Sachtouris
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 7493ccb6 Stavros Sachtouris
# POSSIBILITY OF SUCH DAMAGE.
28 7493ccb6 Stavros Sachtouris
#
29 7493ccb6 Stavros Sachtouris
# The views and conclusions contained in the software and
30 7493ccb6 Stavros Sachtouris
# documentation are those of the authors and should not be
31 7493ccb6 Stavros Sachtouris
# interpreted as representing official policies, either expressed
32 d486baec Stavros Sachtouris
# or implied, of GRNET S.A.command
33 7493ccb6 Stavros Sachtouris
34 7493ccb6 Stavros Sachtouris
import logging
35 d486baec Stavros Sachtouris
from sys import argv, exit, stdout
36 f3e94e06 Stavros Sachtouris
from os.path import basename
37 d486baec Stavros Sachtouris
from inspect import getargspec
38 3dabe5d2 Stavros Sachtouris
39 ee4c47d7 Stavros Sachtouris
from kamaki.cli.argument import ArgumentParseManager
40 fd5db045 Stavros Sachtouris
from kamaki.cli.history import History
41 af569ab9 Stavros Sachtouris
from kamaki.cli.utils import print_dict, red, magenta, yellow
42 d486baec Stavros Sachtouris
from kamaki.cli.errors import CLIError
43 7637d600 Stavros Sachtouris
from kamaki.cli import logger
44 7493ccb6 Stavros Sachtouris
45 d486baec Stavros Sachtouris
_help = False
46 d486baec Stavros Sachtouris
_debug = False
47 1a3c18fd Stavros Sachtouris
_include = False
48 d486baec Stavros Sachtouris
_verbose = False
49 d486baec Stavros Sachtouris
_colors = False
50 aa5c0458 Stavros Sachtouris
kloger = None
51 9dc724e5 Stavros Sachtouris
filelog = None
52 fd5db045 Stavros Sachtouris
53 b6a99832 Stavros Sachtouris
#  command auxiliary methods
54 b6a99832 Stavros Sachtouris
55 b6a99832 Stavros Sachtouris
_best_match = []
56 b6a99832 Stavros Sachtouris
57 fd5db045 Stavros Sachtouris
58 24ff0a35 Stavros Sachtouris
def _arg2syntax(arg):
59 24ff0a35 Stavros Sachtouris
    return arg.replace(
60 24ff0a35 Stavros Sachtouris
        '____', '[:').replace(
61 2005b18e Stavros Sachtouris
            '___', ':').replace(
62 2005b18e Stavros Sachtouris
                '__', ']').replace(
63 2005b18e Stavros Sachtouris
                    '_', ' ')
64 24ff0a35 Stavros Sachtouris
65 24ff0a35 Stavros Sachtouris
66 d486baec Stavros Sachtouris
def _construct_command_syntax(cls):
67 fd5db045 Stavros Sachtouris
        spec = getargspec(cls.main.im_func)
68 fd5db045 Stavros Sachtouris
        args = spec.args[1:]
69 fd5db045 Stavros Sachtouris
        n = len(args) - len(spec.defaults or ())
70 24ff0a35 Stavros Sachtouris
        required = ' '.join(['<%s>' % _arg2syntax(x) for x in args[:n]])
71 24ff0a35 Stavros Sachtouris
        optional = ' '.join(['[%s]' % _arg2syntax(x) for x in args[n:]])
72 fd5db045 Stavros Sachtouris
        cls.syntax = ' '.join(x for x in [required, optional] if x)
73 fd5db045 Stavros Sachtouris
        if spec.varargs:
74 fd5db045 Stavros Sachtouris
            cls.syntax += ' <%s ...>' % spec.varargs
75 fd5db045 Stavros Sachtouris
76 fd5db045 Stavros Sachtouris
77 d486baec Stavros Sachtouris
def _num_of_matching_terms(basic_list, attack_list):
78 d486baec Stavros Sachtouris
    if not attack_list:
79 75c3fc42 Stavros Sachtouris
        return len(basic_list)
80 fd5db045 Stavros Sachtouris
81 d486baec Stavros Sachtouris
    matching_terms = 0
82 d486baec Stavros Sachtouris
    for i, term in enumerate(basic_list):
83 d486baec Stavros Sachtouris
        try:
84 d486baec Stavros Sachtouris
            if term != attack_list[i]:
85 d486baec Stavros Sachtouris
                break
86 d486baec Stavros Sachtouris
        except IndexError:
87 d486baec Stavros Sachtouris
            break
88 d486baec Stavros Sachtouris
        matching_terms += 1
89 d486baec Stavros Sachtouris
    return matching_terms
90 dfee2caf Stavros Sachtouris
91 fd5db045 Stavros Sachtouris
92 d486baec Stavros Sachtouris
def _update_best_match(name_terms, prefix=[]):
93 d486baec Stavros Sachtouris
    if prefix:
94 d486baec Stavros Sachtouris
        pref_list = prefix if isinstance(prefix, list) else prefix.split('_')
95 d486baec Stavros Sachtouris
    else:
96 d486baec Stavros Sachtouris
        pref_list = []
97 dfee2caf Stavros Sachtouris
98 d486baec Stavros Sachtouris
    num_of_matching_terms = _num_of_matching_terms(name_terms, pref_list)
99 d486baec Stavros Sachtouris
    global _best_match
100 e9533b0c Stavros Sachtouris
    if not prefix:
101 e9533b0c Stavros Sachtouris
        _best_match = []
102 fd5db045 Stavros Sachtouris
103 d486baec Stavros Sachtouris
    if num_of_matching_terms and len(_best_match) <= num_of_matching_terms:
104 d486baec Stavros Sachtouris
        if len(_best_match) < num_of_matching_terms:
105 d486baec Stavros Sachtouris
            _best_match = name_terms[:num_of_matching_terms]
106 d486baec Stavros Sachtouris
        return True
107 d486baec Stavros Sachtouris
    return False
108 d486baec Stavros Sachtouris
109 d486baec Stavros Sachtouris
110 d486baec Stavros Sachtouris
def command(cmd_tree, prefix='', descedants_depth=1):
111 d486baec Stavros Sachtouris
    """Load a class as a command
112 451a7992 Stavros Sachtouris
        e.g. spec_cmd0_cmd1 will be command spec cmd0
113 451a7992 Stavros Sachtouris

114 451a7992 Stavros Sachtouris
        :param cmd_tree: is initialized in cmd_spec file and is the structure
115 d486baec Stavros Sachtouris
            where commands are loaded. Var name should be _commands
116 451a7992 Stavros Sachtouris
        :param prefix: if given, load only commands prefixed with prefix,
117 451a7992 Stavros Sachtouris
        :param descedants_depth: is the depth of the tree descedants of the
118 d486baec Stavros Sachtouris
            prefix command. It is used ONLY if prefix and if prefix is not
119 d486baec Stavros Sachtouris
            a terminal command
120 451a7992 Stavros Sachtouris

121 451a7992 Stavros Sachtouris
        :returns: the specified class object
122 d486baec Stavros Sachtouris
    """
123 d486baec Stavros Sachtouris
124 d486baec Stavros Sachtouris
    def wrap(cls):
125 451a7992 Stavros Sachtouris
        global kloger
126 d486baec Stavros Sachtouris
        cls_name = cls.__name__
127 d486baec Stavros Sachtouris
128 d486baec Stavros Sachtouris
        if not cmd_tree:
129 d486baec Stavros Sachtouris
            if _debug:
130 451a7992 Stavros Sachtouris
                kloger.warning('command %s found but not loaded' % cls_name)
131 d486baec Stavros Sachtouris
            return cls
132 0b368c8c Stavros Sachtouris
133 d486baec Stavros Sachtouris
        name_terms = cls_name.split('_')
134 d486baec Stavros Sachtouris
        if not _update_best_match(name_terms, prefix):
135 e9533b0c Stavros Sachtouris
            if _debug:
136 451a7992 Stavros Sachtouris
                kloger.warning('%s failed to update_best_match' % cls_name)
137 d486baec Stavros Sachtouris
            return None
138 fd5db045 Stavros Sachtouris
139 d486baec Stavros Sachtouris
        global _best_match
140 d486baec Stavros Sachtouris
        max_len = len(_best_match) + descedants_depth
141 d486baec Stavros Sachtouris
        if len(name_terms) > max_len:
142 d486baec Stavros Sachtouris
            partial = '_'.join(name_terms[:max_len])
143 d486baec Stavros Sachtouris
            if not cmd_tree.has_command(partial):  # add partial path
144 d486baec Stavros Sachtouris
                cmd_tree.add_command(partial)
145 e9533b0c Stavros Sachtouris
            if _debug:
146 451a7992 Stavros Sachtouris
                kloger.warning('%s failed max_len test' % cls_name)
147 d486baec Stavros Sachtouris
            return None
148 fd5db045 Stavros Sachtouris
149 de73876b Stavros Sachtouris
        (
150 de73876b Stavros Sachtouris
            cls.description, sep, cls.long_description
151 de73876b Stavros Sachtouris
        ) = cls.__doc__.partition('\n')
152 d486baec Stavros Sachtouris
        _construct_command_syntax(cls)
153 0b368c8c Stavros Sachtouris
154 d486baec Stavros Sachtouris
        cmd_tree.add_command(cls_name, cls.description, cls)
155 d486baec Stavros Sachtouris
        return cls
156 d486baec Stavros Sachtouris
    return wrap
157 fd5db045 Stavros Sachtouris
158 0b368c8c Stavros Sachtouris
159 d486baec Stavros Sachtouris
cmd_spec_locations = [
160 d486baec Stavros Sachtouris
    'kamaki.cli.commands',
161 d486baec Stavros Sachtouris
    'kamaki.commands',
162 d486baec Stavros Sachtouris
    'kamaki.cli',
163 d486baec Stavros Sachtouris
    'kamaki',
164 d486baec Stavros Sachtouris
    '']
165 fd5db045 Stavros Sachtouris
166 0b368c8c Stavros Sachtouris
167 b6a99832 Stavros Sachtouris
#  Generic init auxiliary functions
168 b6a99832 Stavros Sachtouris
169 b6a99832 Stavros Sachtouris
170 d486baec Stavros Sachtouris
def _setup_logging(silent=False, debug=False, verbose=False, include=False):
171 fd5db045 Stavros Sachtouris
    """handle logging for clients package"""
172 fd5db045 Stavros Sachtouris
173 fd5db045 Stavros Sachtouris
    if silent:
174 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger(__name__, logging.CRITICAL)
175 db8d1766 Stavros Sachtouris
        return
176 db8d1766 Stavros Sachtouris
177 6e1f863b Stavros Sachtouris
    sfmt, rfmt = '> %(message)s', '< %(message)s'
178 db8d1766 Stavros Sachtouris
    if debug:
179 9dc724e5 Stavros Sachtouris
        print('Logging location: %s' % logger.get_log_filename())
180 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger('kamaki.clients.send', logging.DEBUG, sfmt)
181 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger('kamaki.clients.recv', logging.DEBUG, rfmt)
182 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger(__name__, logging.DEBUG)
183 fd5db045 Stavros Sachtouris
    elif verbose:
184 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger('kamaki.clients.send', logging.INFO, sfmt)
185 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger('kamaki.clients.recv', logging.INFO, rfmt)
186 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger(__name__, logging.INFO)
187 1a3c18fd Stavros Sachtouris
    if include:
188 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger('kamaki.clients.send', logging.INFO, sfmt)
189 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger('kamaki.clients.recv', logging.INFO, rfmt)
190 9dc724e5 Stavros Sachtouris
    logger.add_stream_logger(__name__, logging.WARNING)
191 aa5c0458 Stavros Sachtouris
    global kloger
192 9dc724e5 Stavros Sachtouris
    kloger = logger.get_logger(__name__)
193 fd5db045 Stavros Sachtouris
194 ce48608f Stavros Sachtouris
195 ce9ccb40 Stavros Sachtouris
def _check_config_version(cnf):
196 ce9ccb40 Stavros Sachtouris
    guess = cnf.guess_version()
197 ce9ccb40 Stavros Sachtouris
    if guess < 3.0:
198 362adf50 Stavros Sachtouris
        print('Config file format version >= 3.0 is required')
199 362adf50 Stavros Sachtouris
        print('Configuration file "%s" format is not up to date' % (
200 ce9ccb40 Stavros Sachtouris
            cnf.path))
201 362adf50 Stavros Sachtouris
        print('but kamaki can fix this:')
202 362adf50 Stavros Sachtouris
        print('Calculating changes while preserving information')
203 ce9ccb40 Stavros Sachtouris
        lost_terms = cnf.rescue_old_file()
204 ce9ccb40 Stavros Sachtouris
        print('... DONE')
205 362adf50 Stavros Sachtouris
        if lost_terms:
206 362adf50 Stavros Sachtouris
            print 'The following information will NOT be preserved:'
207 362adf50 Stavros Sachtouris
            print '\t', '\n\t'.join(lost_terms)
208 362adf50 Stavros Sachtouris
        print('Kamaki is ready to convert the config file to version 3.0')
209 ce9ccb40 Stavros Sachtouris
        stdout.write('Overwrite file %s ? [Y, y] ' % cnf.path)
210 ce9ccb40 Stavros Sachtouris
        from sys import stdin
211 ce9ccb40 Stavros Sachtouris
        reply = stdin.readline()
212 ce9ccb40 Stavros Sachtouris
        if reply in ('Y\n', 'y\n'):
213 ce9ccb40 Stavros Sachtouris
            cnf.write()
214 ce9ccb40 Stavros Sachtouris
            print('... DONE')
215 ce9ccb40 Stavros Sachtouris
        else:
216 ce9ccb40 Stavros Sachtouris
            print('... ABORTING')
217 ce9ccb40 Stavros Sachtouris
            raise CLIError(
218 ce9ccb40 Stavros Sachtouris
                'Invalid format for config file %s' % cnf.path,
219 362adf50 Stavros Sachtouris
                importance=3, details=[
220 362adf50 Stavros Sachtouris
                    'Please, update config file to v3.0',
221 362adf50 Stavros Sachtouris
                    'For automatic conversion, rerun and say Y'])
222 ce9ccb40 Stavros Sachtouris
223 ce9ccb40 Stavros Sachtouris
224 362adf50 Stavros Sachtouris
def _init_session(arguments, is_non_API=False):
225 d486baec Stavros Sachtouris
    global _help
226 d486baec Stavros Sachtouris
    _help = arguments['help'].value
227 d486baec Stavros Sachtouris
    global _debug
228 d486baec Stavros Sachtouris
    _debug = arguments['debug'].value
229 1a3c18fd Stavros Sachtouris
    global _include
230 1a3c18fd Stavros Sachtouris
    _include = arguments['include'].value
231 d486baec Stavros Sachtouris
    global _verbose
232 d486baec Stavros Sachtouris
    _verbose = arguments['verbose'].value
233 cb4a5d9c Stavros Sachtouris
    _cnf = arguments['config']
234 ce9ccb40 Stavros Sachtouris
    _check_config_version(_cnf.value)
235 3f0eae61 Stavros Sachtouris
236 d486baec Stavros Sachtouris
    global _colors
237 362adf50 Stavros Sachtouris
    _colors = _cnf.value.get_global('colors')
238 87565d2c Stavros Sachtouris
    if not (stdout.isatty() and _colors == 'on'):
239 4f6a21f6 Stavros Sachtouris
        from kamaki.cli.utils import remove_colors
240 4f6a21f6 Stavros Sachtouris
        remove_colors()
241 d486baec Stavros Sachtouris
    _silent = arguments['silent'].value
242 d486baec Stavros Sachtouris
    _setup_logging(_silent, _debug, _verbose, _include)
243 362adf50 Stavros Sachtouris
244 362adf50 Stavros Sachtouris
    if _help or is_non_API:
245 362adf50 Stavros Sachtouris
        return None
246 362adf50 Stavros Sachtouris
247 362adf50 Stavros Sachtouris
    cloud = arguments['cloud'].value or 'default'
248 362adf50 Stavros Sachtouris
    if not cloud in _cnf.value.keys('remote'):
249 362adf50 Stavros Sachtouris
        raise CLIError(
250 362adf50 Stavros Sachtouris
            'No cloud remote "%s" is configured' % cloud,
251 362adf50 Stavros Sachtouris
            importance=3, details=[
252 362adf50 Stavros Sachtouris
                'To configure a new cloud remote, find and set the',
253 362adf50 Stavros Sachtouris
                'single authentication URL and token:',
254 362adf50 Stavros Sachtouris
                '  kamaki config set remote.%s.url <URL>' % cloud,
255 362adf50 Stavros Sachtouris
                '  kamaki config set remote.%s.token <t0k3n>' % cloud])
256 362adf50 Stavros Sachtouris
    url = _cnf.get_remote(cloud, 'url')
257 362adf50 Stavros Sachtouris
    if not url:
258 362adf50 Stavros Sachtouris
        kloger.warning(
259 362adf50 Stavros Sachtouris
            'WARNING: No remote.%s.url, use service urls instead' % cloud)
260 362adf50 Stavros Sachtouris
        return cloud
261 362adf50 Stavros Sachtouris
    token = _cnf.get_remote(cloud, 'token')
262 362adf50 Stavros Sachtouris
    if not token:
263 362adf50 Stavros Sachtouris
        raise CLIError(
264 362adf50 Stavros Sachtouris
            'No authentication token provided for %s cloud' % cloud,
265 362adf50 Stavros Sachtouris
            importance=3, details=[
266 362adf50 Stavros Sachtouris
                'Get and set a token for %s cloud:' % cloud,
267 362adf50 Stavros Sachtouris
                '  kamaki config set remote.%s.token <t0k3n>' % cloud])
268 362adf50 Stavros Sachtouris
269 f724cd35 Stavros Sachtouris
    from kamaki.clients.astakos import AstakosClient as AuthCachedClient
270 8cec3671 Stavros Sachtouris
    try:
271 362adf50 Stavros Sachtouris
        return AuthCachedClient(url, token)
272 8cec3671 Stavros Sachtouris
    except AssertionError as ae:
273 362adf50 Stavros Sachtouris
        kloger.warning(
274 362adf50 Stavros Sachtouris
            'WARNING: Failed to load auth_url %s [ %s ]' % (url, ae))
275 8cec3671 Stavros Sachtouris
        return None
276 d486baec Stavros Sachtouris
277 d486baec Stavros Sachtouris
278 d486baec Stavros Sachtouris
def _load_spec_module(spec, arguments, module):
279 f724cd35 Stavros Sachtouris
    if not spec:
280 d486baec Stavros Sachtouris
        return None
281 d486baec Stavros Sachtouris
    pkg = None
282 d486baec Stavros Sachtouris
    for location in cmd_spec_locations:
283 f724cd35 Stavros Sachtouris
        location += spec if location == '' else '.%s' % spec
284 d486baec Stavros Sachtouris
        try:
285 d486baec Stavros Sachtouris
            pkg = __import__(location, fromlist=[module])
286 d486baec Stavros Sachtouris
            return pkg
287 f724cd35 Stavros Sachtouris
        except ImportError as ie:
288 d486baec Stavros Sachtouris
            continue
289 f724cd35 Stavros Sachtouris
    if not pkg:
290 f724cd35 Stavros Sachtouris
        kloger.debug('Loading cmd grp %s failed: %s' % (spec, ie))
291 d486baec Stavros Sachtouris
    return pkg
292 d486baec Stavros Sachtouris
293 d486baec Stavros Sachtouris
294 d486baec Stavros Sachtouris
def _groups_help(arguments):
295 d486baec Stavros Sachtouris
    global _debug
296 aa5c0458 Stavros Sachtouris
    global kloger
297 d486baec Stavros Sachtouris
    descriptions = {}
298 f724cd35 Stavros Sachtouris
    for cmd_group, spec in arguments['config'].get_cli_specs():
299 d486baec Stavros Sachtouris
        pkg = _load_spec_module(spec, arguments, '_commands')
300 d486baec Stavros Sachtouris
        if pkg:
301 f724cd35 Stavros Sachtouris
            cmds = getattr(pkg, '_commands')
302 d486baec Stavros Sachtouris
            try:
303 d486baec Stavros Sachtouris
                for cmd in cmds:
304 d486baec Stavros Sachtouris
                    descriptions[cmd.name] = cmd.description
305 d486baec Stavros Sachtouris
            except TypeError:
306 d486baec Stavros Sachtouris
                if _debug:
307 f724cd35 Stavros Sachtouris
                    kloger.warning(
308 f724cd35 Stavros Sachtouris
                        'No cmd description for module %s' % cmd_group)
309 d486baec Stavros Sachtouris
        elif _debug:
310 f724cd35 Stavros Sachtouris
            kloger.warning('Loading of %s cmd spec failed' % cmd_group)
311 d486baec Stavros Sachtouris
    print('\nOptions:\n - - - -')
312 d486baec Stavros Sachtouris
    print_dict(descriptions)
313 d486baec Stavros Sachtouris
314 d486baec Stavros Sachtouris
315 b6a99832 Stavros Sachtouris
def _load_all_commands(cmd_tree, arguments):
316 24ff0a35 Stavros Sachtouris
    _cnf = arguments['config']
317 f724cd35 Stavros Sachtouris
    for cmd_group, spec in _cnf.get_cli_specs():
318 b6a99832 Stavros Sachtouris
        try:
319 b6a99832 Stavros Sachtouris
            spec_module = _load_spec_module(spec, arguments, '_commands')
320 b6a99832 Stavros Sachtouris
            spec_commands = getattr(spec_module, '_commands')
321 b6a99832 Stavros Sachtouris
        except AttributeError:
322 b6a99832 Stavros Sachtouris
            if _debug:
323 b6a99832 Stavros Sachtouris
                global kloger
324 f724cd35 Stavros Sachtouris
                kloger.warning('No valid description for %s' % cmd_group)
325 b6a99832 Stavros Sachtouris
            continue
326 b6a99832 Stavros Sachtouris
        for spec_tree in spec_commands:
327 f724cd35 Stavros Sachtouris
            if spec_tree.name == cmd_group:
328 b6a99832 Stavros Sachtouris
                cmd_tree.add_tree(spec_tree)
329 b6a99832 Stavros Sachtouris
                break
330 b6a99832 Stavros Sachtouris
331 b6a99832 Stavros Sachtouris
332 b6a99832 Stavros Sachtouris
#  Methods to be used by CLI implementations
333 b6a99832 Stavros Sachtouris
334 b6a99832 Stavros Sachtouris
335 b6a99832 Stavros Sachtouris
def print_subcommands_help(cmd):
336 d486baec Stavros Sachtouris
    printout = {}
337 d486baec Stavros Sachtouris
    for subcmd in cmd.get_subcommands():
338 4f6a21f6 Stavros Sachtouris
        spec, sep, print_path = subcmd.path.partition('_')
339 4f6a21f6 Stavros Sachtouris
        printout[print_path.replace('_', ' ')] = subcmd.description
340 d486baec Stavros Sachtouris
    if printout:
341 d486baec Stavros Sachtouris
        print('\nOptions:\n - - - -')
342 d486baec Stavros Sachtouris
        print_dict(printout)
343 d486baec Stavros Sachtouris
344 d486baec Stavros Sachtouris
345 b6a99832 Stavros Sachtouris
def update_parser_help(parser, cmd):
346 d486baec Stavros Sachtouris
    global _best_match
347 7c2247a0 Stavros Sachtouris
    parser.syntax = parser.syntax.split('<')[0]
348 7c2247a0 Stavros Sachtouris
    parser.syntax += ' '.join(_best_match)
349 d486baec Stavros Sachtouris
350 a71bb904 Stavros Sachtouris
    description = ''
351 d486baec Stavros Sachtouris
    if cmd.is_command:
352 d486baec Stavros Sachtouris
        cls = cmd.get_class()
353 7c2247a0 Stavros Sachtouris
        parser.syntax += ' ' + cls.syntax
354 7c2247a0 Stavros Sachtouris
        parser.update_arguments(cls().arguments)
355 a71bb904 Stavros Sachtouris
        description = getattr(cls, 'long_description', '')
356 a71bb904 Stavros Sachtouris
        description = description.strip()
357 d486baec Stavros Sachtouris
    else:
358 7c2247a0 Stavros Sachtouris
        parser.syntax += ' <...>'
359 d486baec Stavros Sachtouris
    if cmd.has_description:
360 de73876b Stavros Sachtouris
        parser.parser.description = cmd.help + (
361 de73876b Stavros Sachtouris
            ('\n%s' % description) if description else '')
362 2fbca093 Stavros Sachtouris
    else:
363 2fbca093 Stavros Sachtouris
        parser.parser.description = description
364 d486baec Stavros Sachtouris
365 d486baec Stavros Sachtouris
366 b6a99832 Stavros Sachtouris
def print_error_message(cli_err):
367 d486baec Stavros Sachtouris
    errmsg = '%s' % cli_err
368 d486baec Stavros Sachtouris
    if cli_err.importance == 1:
369 d486baec Stavros Sachtouris
        errmsg = magenta(errmsg)
370 d486baec Stavros Sachtouris
    elif cli_err.importance == 2:
371 d486baec Stavros Sachtouris
        errmsg = yellow(errmsg)
372 d486baec Stavros Sachtouris
    elif cli_err.importance > 2:
373 d486baec Stavros Sachtouris
        errmsg = red(errmsg)
374 d486baec Stavros Sachtouris
    stdout.write(errmsg)
375 66f1ff99 Stavros Sachtouris
    for errmsg in cli_err.details:
376 f724cd35 Stavros Sachtouris
        print('|  %s' % errmsg)
377 d486baec Stavros Sachtouris
378 d486baec Stavros Sachtouris
379 b6a99832 Stavros Sachtouris
def exec_cmd(instance, cmd_args, help_method):
380 fd5db045 Stavros Sachtouris
    try:
381 fd5db045 Stavros Sachtouris
        return instance.main(*cmd_args)
382 fd5db045 Stavros Sachtouris
    except TypeError as err:
383 fd5db045 Stavros Sachtouris
        if err.args and err.args[0].startswith('main()'):
384 fd5db045 Stavros Sachtouris
            print(magenta('Syntax error'))
385 d486baec Stavros Sachtouris
            if _debug:
386 d486baec Stavros Sachtouris
                raise err
387 d486baec Stavros Sachtouris
            if _verbose:
388 fd5db045 Stavros Sachtouris
                print(unicode(err))
389 fd5db045 Stavros Sachtouris
            help_method()
390 fd5db045 Stavros Sachtouris
        else:
391 fd5db045 Stavros Sachtouris
            raise
392 fd5db045 Stavros Sachtouris
    return 1
393 fd5db045 Stavros Sachtouris
394 f247bcb4 Stavros Sachtouris
395 b6a99832 Stavros Sachtouris
def get_command_group(unparsed, arguments):
396 b6a99832 Stavros Sachtouris
    groups = arguments['config'].get_groups()
397 b6a99832 Stavros Sachtouris
    for term in unparsed:
398 b6a99832 Stavros Sachtouris
        if term.startswith('-'):
399 b6a99832 Stavros Sachtouris
            continue
400 b6a99832 Stavros Sachtouris
        if term in groups:
401 b6a99832 Stavros Sachtouris
            unparsed.remove(term)
402 b6a99832 Stavros Sachtouris
            return term
403 b6a99832 Stavros Sachtouris
        return None
404 b6a99832 Stavros Sachtouris
    return None
405 b6a99832 Stavros Sachtouris
406 b6a99832 Stavros Sachtouris
407 7c2247a0 Stavros Sachtouris
def set_command_params(parameters):
408 7c2247a0 Stavros Sachtouris
    """Add a parameters list to a command
409 7c2247a0 Stavros Sachtouris

410 7c2247a0 Stavros Sachtouris
    :param paramters: (list of str) a list of parameters
411 7c2247a0 Stavros Sachtouris
    """
412 d486baec Stavros Sachtouris
    global command
413 d486baec Stavros Sachtouris
    def_params = list(command.func_defaults)
414 7c2247a0 Stavros Sachtouris
    def_params[0] = parameters
415 d486baec Stavros Sachtouris
    command.func_defaults = tuple(def_params)
416 d486baec Stavros Sachtouris
417 d486baec Stavros Sachtouris
418 b6a99832 Stavros Sachtouris
#  CLI Choice:
419 d486baec Stavros Sachtouris
420 f724cd35 Stavros Sachtouris
def run_one_cmd(exe_string, parser, auth_base):
421 b6a99832 Stavros Sachtouris
    global _history
422 b6a99832 Stavros Sachtouris
    _history = History(
423 362adf50 Stavros Sachtouris
        parser.arguments['config'].get_global('history_file'))
424 b6a99832 Stavros Sachtouris
    _history.add(' '.join([exe_string] + argv[1:]))
425 b6a99832 Stavros Sachtouris
    from kamaki.cli import one_command
426 f724cd35 Stavros Sachtouris
    one_command.run(auth_base, parser, _help)
427 d53062bd Stavros Sachtouris
428 d53062bd Stavros Sachtouris
429 f724cd35 Stavros Sachtouris
def run_shell(exe_string, parser, auth_base):
430 d53062bd Stavros Sachtouris
    from command_shell import _init_shell
431 074f5027 Stavros Sachtouris
    shell = _init_shell(exe_string, parser)
432 074f5027 Stavros Sachtouris
    _load_all_commands(shell.cmd_tree, parser.arguments)
433 f724cd35 Stavros Sachtouris
    shell.run(auth_base, parser)
434 fd5db045 Stavros Sachtouris
435 1c1fd2fa Stavros Sachtouris
436 362adf50 Stavros Sachtouris
def is_non_API(parser):
437 362adf50 Stavros Sachtouris
    nonAPIs = ('history', 'config')
438 362adf50 Stavros Sachtouris
    for term in parser.unparsed:
439 362adf50 Stavros Sachtouris
        if not term.startswith('-'):
440 362adf50 Stavros Sachtouris
            if term in nonAPIs:
441 362adf50 Stavros Sachtouris
                return True
442 362adf50 Stavros Sachtouris
            return False
443 362adf50 Stavros Sachtouris
    return False
444 362adf50 Stavros Sachtouris
445 362adf50 Stavros Sachtouris
446 1c1fd2fa Stavros Sachtouris
def main():
447 71882bca Stavros Sachtouris
    try:
448 71882bca Stavros Sachtouris
        exe = basename(argv[0])
449 e0da0f90 Stavros Sachtouris
        parser = ArgumentParseManager(exe)
450 7c2247a0 Stavros Sachtouris
451 074f5027 Stavros Sachtouris
        if parser.arguments['version'].value:
452 71882bca Stavros Sachtouris
            exit(0)
453 71882bca Stavros Sachtouris
454 362adf50 Stavros Sachtouris
        log_file = parser.arguments['config'].get_global('log_file')
455 f47417e7 Stavros Sachtouris
        if log_file:
456 7637d600 Stavros Sachtouris
            logger.set_log_filename(log_file)
457 9dc724e5 Stavros Sachtouris
        global filelog
458 9dc724e5 Stavros Sachtouris
        filelog = logger.add_file_logger(__name__.split('.')[0])
459 334338ce Stavros Sachtouris
        filelog.info('* Initial Call *\n%s\n- - -' % ' '.join(argv))
460 9dc724e5 Stavros Sachtouris
461 362adf50 Stavros Sachtouris
        remote_base = _init_session(parser.arguments, is_non_API(parser))
462 71882bca Stavros Sachtouris
463 6fb4af77 Stavros Sachtouris
        from kamaki.cli.utils import suggest_missing
464 6fb4af77 Stavros Sachtouris
        suggest_missing()
465 6fb4af77 Stavros Sachtouris
466 b3dd8f4b Stavros Sachtouris
        if parser.unparsed:
467 362adf50 Stavros Sachtouris
            run_one_cmd(exe, parser, remote_base)
468 71882bca Stavros Sachtouris
        elif _help:
469 e0da0f90 Stavros Sachtouris
            parser.parser.print_help()
470 074f5027 Stavros Sachtouris
            _groups_help(parser.arguments)
471 71882bca Stavros Sachtouris
        else:
472 362adf50 Stavros Sachtouris
            run_shell(exe, parser, remote_base)
473 71882bca Stavros Sachtouris
    except CLIError as err:
474 b6a99832 Stavros Sachtouris
        print_error_message(err)
475 71882bca Stavros Sachtouris
        if _debug:
476 71882bca Stavros Sachtouris
            raise err
477 71882bca Stavros Sachtouris
        exit(1)
478 6069b53b Stavros Sachtouris
    except Exception as er:
479 6069b53b Stavros Sachtouris
        print('Unknown Error: %s' % er)
480 71882bca Stavros Sachtouris
        if _debug:
481 6069b53b Stavros Sachtouris
            raise
482 6069b53b Stavros Sachtouris
        exit(1)