Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / __init__.py @ 556e6916

History | View | Annotate | Download (16.7 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 df0045d8 Stavros Sachtouris
from os.path import basename, exists
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 7b2e4bf1 Stavros Sachtouris
from kamaki.cli.errors import CLIError, CLICmdSpecError
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 7b2e4bf1 Stavros Sachtouris
        try:
150 7b2e4bf1 Stavros Sachtouris
            (
151 7b2e4bf1 Stavros Sachtouris
                cls.description, sep, cls.long_description
152 7b2e4bf1 Stavros Sachtouris
            ) = cls.__doc__.partition('\n')
153 7b2e4bf1 Stavros Sachtouris
        except AttributeError:
154 7b2e4bf1 Stavros Sachtouris
            raise CLICmdSpecError(
155 7b2e4bf1 Stavros Sachtouris
                'No commend in %s (acts as cmd description)' % cls.__name__)
156 d486baec Stavros Sachtouris
        _construct_command_syntax(cls)
157 0b368c8c Stavros Sachtouris
158 d486baec Stavros Sachtouris
        cmd_tree.add_command(cls_name, cls.description, cls)
159 d486baec Stavros Sachtouris
        return cls
160 d486baec Stavros Sachtouris
    return wrap
161 fd5db045 Stavros Sachtouris
162 0b368c8c Stavros Sachtouris
163 d486baec Stavros Sachtouris
cmd_spec_locations = [
164 d486baec Stavros Sachtouris
    'kamaki.cli.commands',
165 d486baec Stavros Sachtouris
    'kamaki.commands',
166 d486baec Stavros Sachtouris
    'kamaki.cli',
167 d486baec Stavros Sachtouris
    'kamaki',
168 d486baec Stavros Sachtouris
    '']
169 fd5db045 Stavros Sachtouris
170 0b368c8c Stavros Sachtouris
171 b6a99832 Stavros Sachtouris
#  Generic init auxiliary functions
172 b6a99832 Stavros Sachtouris
173 b6a99832 Stavros Sachtouris
174 d486baec Stavros Sachtouris
def _setup_logging(silent=False, debug=False, verbose=False, include=False):
175 fd5db045 Stavros Sachtouris
    """handle logging for clients package"""
176 fd5db045 Stavros Sachtouris
177 fd5db045 Stavros Sachtouris
    if silent:
178 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger(__name__, logging.CRITICAL)
179 db8d1766 Stavros Sachtouris
        return
180 db8d1766 Stavros Sachtouris
181 6e1f863b Stavros Sachtouris
    sfmt, rfmt = '> %(message)s', '< %(message)s'
182 db8d1766 Stavros Sachtouris
    if debug:
183 9dc724e5 Stavros Sachtouris
        print('Logging location: %s' % logger.get_log_filename())
184 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger('kamaki.clients.send', logging.DEBUG, sfmt)
185 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger('kamaki.clients.recv', logging.DEBUG, rfmt)
186 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger(__name__, logging.DEBUG)
187 fd5db045 Stavros Sachtouris
    elif verbose:
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.INFO)
191 1a3c18fd Stavros Sachtouris
    if include:
192 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger('kamaki.clients.send', logging.INFO, sfmt)
193 9dc724e5 Stavros Sachtouris
        logger.add_stream_logger('kamaki.clients.recv', logging.INFO, rfmt)
194 9dc724e5 Stavros Sachtouris
    logger.add_stream_logger(__name__, logging.WARNING)
195 aa5c0458 Stavros Sachtouris
    global kloger
196 9dc724e5 Stavros Sachtouris
    kloger = logger.get_logger(__name__)
197 fd5db045 Stavros Sachtouris
198 ce48608f Stavros Sachtouris
199 ce9ccb40 Stavros Sachtouris
def _check_config_version(cnf):
200 ce9ccb40 Stavros Sachtouris
    guess = cnf.guess_version()
201 df0045d8 Stavros Sachtouris
    if exists(cnf.path) and guess < 0.9:
202 c825ddc9 Stavros Sachtouris
        print('Config file format version >= 9.0 is required')
203 df0045d8 Stavros Sachtouris
        print('Configuration file: %s' % cnf.path)
204 fa382f9e Stavros Sachtouris
        print('Attempting to fix this:')
205 362adf50 Stavros Sachtouris
        print('Calculating changes while preserving information')
206 ce9ccb40 Stavros Sachtouris
        lost_terms = cnf.rescue_old_file()
207 ce9ccb40 Stavros Sachtouris
        print('... DONE')
208 362adf50 Stavros Sachtouris
        if lost_terms:
209 362adf50 Stavros Sachtouris
            print 'The following information will NOT be preserved:'
210 362adf50 Stavros Sachtouris
            print '\t', '\n\t'.join(lost_terms)
211 fa382f9e Stavros Sachtouris
        print('Kamaki is ready to convert the config file')
212 904091dd Stavros Sachtouris
        stdout.write('Create (overwrite) file %s ? [y/N] ' % cnf.path)
213 ce9ccb40 Stavros Sachtouris
        from sys import stdin
214 ce9ccb40 Stavros Sachtouris
        reply = stdin.readline()
215 ce9ccb40 Stavros Sachtouris
        if reply in ('Y\n', 'y\n'):
216 ce9ccb40 Stavros Sachtouris
            cnf.write()
217 ce9ccb40 Stavros Sachtouris
            print('... DONE')
218 ce9ccb40 Stavros Sachtouris
        else:
219 ce9ccb40 Stavros Sachtouris
            print('... ABORTING')
220 ce9ccb40 Stavros Sachtouris
            raise CLIError(
221 ce9ccb40 Stavros Sachtouris
                'Invalid format for config file %s' % cnf.path,
222 362adf50 Stavros Sachtouris
                importance=3, details=[
223 fa382f9e Stavros Sachtouris
                    'Please, update config file',
224 362adf50 Stavros Sachtouris
                    'For automatic conversion, rerun and say Y'])
225 ce9ccb40 Stavros Sachtouris
226 ce9ccb40 Stavros Sachtouris
227 362adf50 Stavros Sachtouris
def _init_session(arguments, is_non_API=False):
228 844a6bdb Stavros Sachtouris
    """
229 144b3551 Stavros Sachtouris
    :returns: (AuthCachedClient, str) authenticator and cloud name
230 844a6bdb Stavros Sachtouris
    """
231 d486baec Stavros Sachtouris
    global _help
232 d486baec Stavros Sachtouris
    _help = arguments['help'].value
233 d486baec Stavros Sachtouris
    global _debug
234 d486baec Stavros Sachtouris
    _debug = arguments['debug'].value
235 1a3c18fd Stavros Sachtouris
    global _include
236 1a3c18fd Stavros Sachtouris
    _include = arguments['include'].value
237 d486baec Stavros Sachtouris
    global _verbose
238 d486baec Stavros Sachtouris
    _verbose = arguments['verbose'].value
239 cb4a5d9c Stavros Sachtouris
    _cnf = arguments['config']
240 df0045d8 Stavros Sachtouris
241 df0045d8 Stavros Sachtouris
    if _help or is_non_API:
242 df0045d8 Stavros Sachtouris
        return None, None
243 df0045d8 Stavros Sachtouris
244 ce9ccb40 Stavros Sachtouris
    _check_config_version(_cnf.value)
245 3f0eae61 Stavros Sachtouris
246 d486baec Stavros Sachtouris
    global _colors
247 362adf50 Stavros Sachtouris
    _colors = _cnf.value.get_global('colors')
248 87565d2c Stavros Sachtouris
    if not (stdout.isatty() and _colors == 'on'):
249 4f6a21f6 Stavros Sachtouris
        from kamaki.cli.utils import remove_colors
250 4f6a21f6 Stavros Sachtouris
        remove_colors()
251 d486baec Stavros Sachtouris
    _silent = arguments['silent'].value
252 d486baec Stavros Sachtouris
    _setup_logging(_silent, _debug, _verbose, _include)
253 362adf50 Stavros Sachtouris
254 c825ddc9 Stavros Sachtouris
    cloud = arguments['cloud'].value or _cnf.value.get(
255 c825ddc9 Stavros Sachtouris
        'global', 'default_cloud')
256 c825ddc9 Stavros Sachtouris
    if not cloud:
257 c825ddc9 Stavros Sachtouris
        num_of_clouds = len(_cnf.value.keys('cloud'))
258 c825ddc9 Stavros Sachtouris
        if num_of_clouds == 1:
259 c825ddc9 Stavros Sachtouris
            cloud = _cnf.value.keys('cloud')[0]
260 df0045d8 Stavros Sachtouris
        elif num_of_clouds > 1:
261 c825ddc9 Stavros Sachtouris
            raise CLIError(
262 44101d8a Stavros Sachtouris
                'Found %s clouds but none of them is set as default' % (
263 44101d8a Stavros Sachtouris
                    num_of_clouds),
264 c825ddc9 Stavros Sachtouris
                importance=2, details=[
265 c825ddc9 Stavros Sachtouris
                    'Please, choose one of the following cloud names:',
266 c825ddc9 Stavros Sachtouris
                    ', '.join(_cnf.value.keys('cloud')),
267 44101d8a Stavros Sachtouris
                    'To see all cloud settings:',
268 44101d8a Stavros Sachtouris
                    '  kamaki config get cloud.<cloud name>',
269 c825ddc9 Stavros Sachtouris
                    'To set a default cloud:',
270 c825ddc9 Stavros Sachtouris
                    '  kamaki config set default_cloud <cloud name>',
271 c825ddc9 Stavros Sachtouris
                    'To pick a cloud for the current session, use --cloud:',
272 c825ddc9 Stavros Sachtouris
                    '  kamaki --cloud=<cloud name> ...'])
273 144b3551 Stavros Sachtouris
    if not cloud in _cnf.value.keys('cloud'):
274 362adf50 Stavros Sachtouris
        raise CLIError(
275 df0045d8 Stavros Sachtouris
            'No cloud%s is configured' % ((' "%s"' % cloud) if cloud else ''),
276 362adf50 Stavros Sachtouris
            importance=3, details=[
277 df0045d8 Stavros Sachtouris
                'To configure a new cloud "%s", find and set the' % (
278 df0045d8 Stavros Sachtouris
                    cloud or '<cloud name>'),
279 362adf50 Stavros Sachtouris
                'single authentication URL and token:',
280 df0045d8 Stavros Sachtouris
                '  kamaki config set cloud.%s.url <URL>' % (
281 df0045d8 Stavros Sachtouris
                    cloud or '<cloud name>'),
282 df0045d8 Stavros Sachtouris
                '  kamaki config set cloud.%s.token <t0k3n>' % (
283 df0045d8 Stavros Sachtouris
                    cloud or '<cloud name>')])
284 844a6bdb Stavros Sachtouris
    auth_args = dict()
285 844a6bdb Stavros Sachtouris
    for term in ('url', 'token'):
286 c825ddc9 Stavros Sachtouris
        try:
287 c825ddc9 Stavros Sachtouris
            auth_args[term] = _cnf.get_cloud(cloud, term)
288 c825ddc9 Stavros Sachtouris
        except KeyError:
289 c825ddc9 Stavros Sachtouris
            auth_args[term] = ''
290 844a6bdb Stavros Sachtouris
        if not auth_args[term]:
291 844a6bdb Stavros Sachtouris
            raise CLIError(
292 b4ed3a7e Stavros Sachtouris
                'No authentication %s provided for cloud "%s"' % (
293 b4ed3a7e Stavros Sachtouris
                    term.upper(), cloud),
294 844a6bdb Stavros Sachtouris
                importance=3, details=[
295 b4ed3a7e Stavros Sachtouris
                    'Set a %s for cloud %s:' % (term.upper(), cloud),
296 44101d8a Stavros Sachtouris
                    '  kamaki config set cloud.%s.%s <%s>' % (
297 b4ed3a7e Stavros Sachtouris
                        cloud, term, term.upper())])
298 362adf50 Stavros Sachtouris
299 f724cd35 Stavros Sachtouris
    from kamaki.clients.astakos import AstakosClient as AuthCachedClient
300 8cec3671 Stavros Sachtouris
    try:
301 844a6bdb Stavros Sachtouris
        return AuthCachedClient(auth_args['url'], auth_args['token']), cloud
302 8cec3671 Stavros Sachtouris
    except AssertionError as ae:
303 844a6bdb Stavros Sachtouris
        kloger.warning('WARNING: Failed to load authenticator [%s]' % ae)
304 844a6bdb Stavros Sachtouris
        return None, cloud
305 d486baec Stavros Sachtouris
306 d486baec Stavros Sachtouris
307 d486baec Stavros Sachtouris
def _load_spec_module(spec, arguments, module):
308 f724cd35 Stavros Sachtouris
    if not spec:
309 d486baec Stavros Sachtouris
        return None
310 d486baec Stavros Sachtouris
    pkg = None
311 d486baec Stavros Sachtouris
    for location in cmd_spec_locations:
312 f724cd35 Stavros Sachtouris
        location += spec if location == '' else '.%s' % spec
313 d486baec Stavros Sachtouris
        try:
314 d486baec Stavros Sachtouris
            pkg = __import__(location, fromlist=[module])
315 d486baec Stavros Sachtouris
            return pkg
316 f724cd35 Stavros Sachtouris
        except ImportError as ie:
317 d486baec Stavros Sachtouris
            continue
318 f724cd35 Stavros Sachtouris
    if not pkg:
319 f724cd35 Stavros Sachtouris
        kloger.debug('Loading cmd grp %s failed: %s' % (spec, ie))
320 d486baec Stavros Sachtouris
    return pkg
321 d486baec Stavros Sachtouris
322 d486baec Stavros Sachtouris
323 d486baec Stavros Sachtouris
def _groups_help(arguments):
324 d486baec Stavros Sachtouris
    global _debug
325 aa5c0458 Stavros Sachtouris
    global kloger
326 d486baec Stavros Sachtouris
    descriptions = {}
327 f724cd35 Stavros Sachtouris
    for cmd_group, spec in arguments['config'].get_cli_specs():
328 d486baec Stavros Sachtouris
        pkg = _load_spec_module(spec, arguments, '_commands')
329 d486baec Stavros Sachtouris
        if pkg:
330 f724cd35 Stavros Sachtouris
            cmds = getattr(pkg, '_commands')
331 d486baec Stavros Sachtouris
            try:
332 d486baec Stavros Sachtouris
                for cmd in cmds:
333 d486baec Stavros Sachtouris
                    descriptions[cmd.name] = cmd.description
334 d486baec Stavros Sachtouris
            except TypeError:
335 d486baec Stavros Sachtouris
                if _debug:
336 f724cd35 Stavros Sachtouris
                    kloger.warning(
337 f724cd35 Stavros Sachtouris
                        'No cmd description for module %s' % cmd_group)
338 d486baec Stavros Sachtouris
        elif _debug:
339 f724cd35 Stavros Sachtouris
            kloger.warning('Loading of %s cmd spec failed' % cmd_group)
340 d486baec Stavros Sachtouris
    print('\nOptions:\n - - - -')
341 d486baec Stavros Sachtouris
    print_dict(descriptions)
342 d486baec Stavros Sachtouris
343 d486baec Stavros Sachtouris
344 b6a99832 Stavros Sachtouris
def _load_all_commands(cmd_tree, arguments):
345 24ff0a35 Stavros Sachtouris
    _cnf = arguments['config']
346 f724cd35 Stavros Sachtouris
    for cmd_group, spec in _cnf.get_cli_specs():
347 b6a99832 Stavros Sachtouris
        try:
348 b6a99832 Stavros Sachtouris
            spec_module = _load_spec_module(spec, arguments, '_commands')
349 b6a99832 Stavros Sachtouris
            spec_commands = getattr(spec_module, '_commands')
350 b6a99832 Stavros Sachtouris
        except AttributeError:
351 b6a99832 Stavros Sachtouris
            if _debug:
352 b6a99832 Stavros Sachtouris
                global kloger
353 f724cd35 Stavros Sachtouris
                kloger.warning('No valid description for %s' % cmd_group)
354 b6a99832 Stavros Sachtouris
            continue
355 b6a99832 Stavros Sachtouris
        for spec_tree in spec_commands:
356 f724cd35 Stavros Sachtouris
            if spec_tree.name == cmd_group:
357 b6a99832 Stavros Sachtouris
                cmd_tree.add_tree(spec_tree)
358 b6a99832 Stavros Sachtouris
                break
359 b6a99832 Stavros Sachtouris
360 b6a99832 Stavros Sachtouris
361 b6a99832 Stavros Sachtouris
#  Methods to be used by CLI implementations
362 b6a99832 Stavros Sachtouris
363 b6a99832 Stavros Sachtouris
364 b6a99832 Stavros Sachtouris
def print_subcommands_help(cmd):
365 d486baec Stavros Sachtouris
    printout = {}
366 d486baec Stavros Sachtouris
    for subcmd in cmd.get_subcommands():
367 4f6a21f6 Stavros Sachtouris
        spec, sep, print_path = subcmd.path.partition('_')
368 4f6a21f6 Stavros Sachtouris
        printout[print_path.replace('_', ' ')] = subcmd.description
369 d486baec Stavros Sachtouris
    if printout:
370 d486baec Stavros Sachtouris
        print('\nOptions:\n - - - -')
371 d486baec Stavros Sachtouris
        print_dict(printout)
372 d486baec Stavros Sachtouris
373 d486baec Stavros Sachtouris
374 b6a99832 Stavros Sachtouris
def update_parser_help(parser, cmd):
375 d486baec Stavros Sachtouris
    global _best_match
376 7c2247a0 Stavros Sachtouris
    parser.syntax = parser.syntax.split('<')[0]
377 7c2247a0 Stavros Sachtouris
    parser.syntax += ' '.join(_best_match)
378 d486baec Stavros Sachtouris
379 a71bb904 Stavros Sachtouris
    description = ''
380 d486baec Stavros Sachtouris
    if cmd.is_command:
381 d486baec Stavros Sachtouris
        cls = cmd.get_class()
382 7c2247a0 Stavros Sachtouris
        parser.syntax += ' ' + cls.syntax
383 7c2247a0 Stavros Sachtouris
        parser.update_arguments(cls().arguments)
384 a71bb904 Stavros Sachtouris
        description = getattr(cls, 'long_description', '')
385 a71bb904 Stavros Sachtouris
        description = description.strip()
386 d486baec Stavros Sachtouris
    else:
387 7c2247a0 Stavros Sachtouris
        parser.syntax += ' <...>'
388 d486baec Stavros Sachtouris
    if cmd.has_description:
389 de73876b Stavros Sachtouris
        parser.parser.description = cmd.help + (
390 de73876b Stavros Sachtouris
            ('\n%s' % description) if description else '')
391 2fbca093 Stavros Sachtouris
    else:
392 2fbca093 Stavros Sachtouris
        parser.parser.description = description
393 d486baec Stavros Sachtouris
394 d486baec Stavros Sachtouris
395 b6a99832 Stavros Sachtouris
def print_error_message(cli_err):
396 d486baec Stavros Sachtouris
    errmsg = '%s' % cli_err
397 d486baec Stavros Sachtouris
    if cli_err.importance == 1:
398 d486baec Stavros Sachtouris
        errmsg = magenta(errmsg)
399 d486baec Stavros Sachtouris
    elif cli_err.importance == 2:
400 d486baec Stavros Sachtouris
        errmsg = yellow(errmsg)
401 d486baec Stavros Sachtouris
    elif cli_err.importance > 2:
402 d486baec Stavros Sachtouris
        errmsg = red(errmsg)
403 d486baec Stavros Sachtouris
    stdout.write(errmsg)
404 66f1ff99 Stavros Sachtouris
    for errmsg in cli_err.details:
405 f724cd35 Stavros Sachtouris
        print('|  %s' % errmsg)
406 d486baec Stavros Sachtouris
407 d486baec Stavros Sachtouris
408 b6a99832 Stavros Sachtouris
def exec_cmd(instance, cmd_args, help_method):
409 fd5db045 Stavros Sachtouris
    try:
410 fd5db045 Stavros Sachtouris
        return instance.main(*cmd_args)
411 fd5db045 Stavros Sachtouris
    except TypeError as err:
412 fd5db045 Stavros Sachtouris
        if err.args and err.args[0].startswith('main()'):
413 fd5db045 Stavros Sachtouris
            print(magenta('Syntax error'))
414 d486baec Stavros Sachtouris
            if _debug:
415 d486baec Stavros Sachtouris
                raise err
416 d486baec Stavros Sachtouris
            if _verbose:
417 fd5db045 Stavros Sachtouris
                print(unicode(err))
418 fd5db045 Stavros Sachtouris
            help_method()
419 fd5db045 Stavros Sachtouris
        else:
420 fd5db045 Stavros Sachtouris
            raise
421 fd5db045 Stavros Sachtouris
    return 1
422 fd5db045 Stavros Sachtouris
423 f247bcb4 Stavros Sachtouris
424 b6a99832 Stavros Sachtouris
def get_command_group(unparsed, arguments):
425 b6a99832 Stavros Sachtouris
    groups = arguments['config'].get_groups()
426 b6a99832 Stavros Sachtouris
    for term in unparsed:
427 b6a99832 Stavros Sachtouris
        if term.startswith('-'):
428 b6a99832 Stavros Sachtouris
            continue
429 b6a99832 Stavros Sachtouris
        if term in groups:
430 b6a99832 Stavros Sachtouris
            unparsed.remove(term)
431 b6a99832 Stavros Sachtouris
            return term
432 b6a99832 Stavros Sachtouris
        return None
433 b6a99832 Stavros Sachtouris
    return None
434 b6a99832 Stavros Sachtouris
435 b6a99832 Stavros Sachtouris
436 7c2247a0 Stavros Sachtouris
def set_command_params(parameters):
437 7c2247a0 Stavros Sachtouris
    """Add a parameters list to a command
438 7c2247a0 Stavros Sachtouris

439 7c2247a0 Stavros Sachtouris
    :param paramters: (list of str) a list of parameters
440 7c2247a0 Stavros Sachtouris
    """
441 d486baec Stavros Sachtouris
    global command
442 d486baec Stavros Sachtouris
    def_params = list(command.func_defaults)
443 7c2247a0 Stavros Sachtouris
    def_params[0] = parameters
444 d486baec Stavros Sachtouris
    command.func_defaults = tuple(def_params)
445 d486baec Stavros Sachtouris
446 d486baec Stavros Sachtouris
447 b6a99832 Stavros Sachtouris
#  CLI Choice:
448 d486baec Stavros Sachtouris
449 844a6bdb Stavros Sachtouris
def run_one_cmd(exe_string, parser, auth_base, cloud):
450 b6a99832 Stavros Sachtouris
    global _history
451 b6a99832 Stavros Sachtouris
    _history = History(
452 362adf50 Stavros Sachtouris
        parser.arguments['config'].get_global('history_file'))
453 b6a99832 Stavros Sachtouris
    _history.add(' '.join([exe_string] + argv[1:]))
454 b6a99832 Stavros Sachtouris
    from kamaki.cli import one_command
455 844a6bdb Stavros Sachtouris
    one_command.run(auth_base, cloud, parser, _help)
456 d53062bd Stavros Sachtouris
457 d53062bd Stavros Sachtouris
458 844a6bdb Stavros Sachtouris
def run_shell(exe_string, parser, auth_base, cloud):
459 d53062bd Stavros Sachtouris
    from command_shell import _init_shell
460 074f5027 Stavros Sachtouris
    shell = _init_shell(exe_string, parser)
461 074f5027 Stavros Sachtouris
    _load_all_commands(shell.cmd_tree, parser.arguments)
462 844a6bdb Stavros Sachtouris
    shell.run(auth_base, cloud, parser)
463 fd5db045 Stavros Sachtouris
464 1c1fd2fa Stavros Sachtouris
465 362adf50 Stavros Sachtouris
def is_non_API(parser):
466 362adf50 Stavros Sachtouris
    nonAPIs = ('history', 'config')
467 362adf50 Stavros Sachtouris
    for term in parser.unparsed:
468 362adf50 Stavros Sachtouris
        if not term.startswith('-'):
469 362adf50 Stavros Sachtouris
            if term in nonAPIs:
470 362adf50 Stavros Sachtouris
                return True
471 362adf50 Stavros Sachtouris
            return False
472 362adf50 Stavros Sachtouris
    return False
473 362adf50 Stavros Sachtouris
474 362adf50 Stavros Sachtouris
475 1c1fd2fa Stavros Sachtouris
def main():
476 71882bca Stavros Sachtouris
    try:
477 71882bca Stavros Sachtouris
        exe = basename(argv[0])
478 e0da0f90 Stavros Sachtouris
        parser = ArgumentParseManager(exe)
479 7c2247a0 Stavros Sachtouris
480 074f5027 Stavros Sachtouris
        if parser.arguments['version'].value:
481 71882bca Stavros Sachtouris
            exit(0)
482 71882bca Stavros Sachtouris
483 362adf50 Stavros Sachtouris
        log_file = parser.arguments['config'].get_global('log_file')
484 f47417e7 Stavros Sachtouris
        if log_file:
485 7637d600 Stavros Sachtouris
            logger.set_log_filename(log_file)
486 9dc724e5 Stavros Sachtouris
        global filelog
487 9dc724e5 Stavros Sachtouris
        filelog = logger.add_file_logger(__name__.split('.')[0])
488 334338ce Stavros Sachtouris
        filelog.info('* Initial Call *\n%s\n- - -' % ' '.join(argv))
489 9dc724e5 Stavros Sachtouris
490 844a6bdb Stavros Sachtouris
        auth_base, cloud = _init_session(parser.arguments, is_non_API(parser))
491 71882bca Stavros Sachtouris
492 6fb4af77 Stavros Sachtouris
        from kamaki.cli.utils import suggest_missing
493 69691087 Stavros Sachtouris
        global _colors
494 69691087 Stavros Sachtouris
        exclude = ['ansicolors'] if not _colors == 'on' else []
495 69691087 Stavros Sachtouris
        suggest_missing(exclude=exclude)
496 6fb4af77 Stavros Sachtouris
497 b3dd8f4b Stavros Sachtouris
        if parser.unparsed:
498 844a6bdb Stavros Sachtouris
            run_one_cmd(exe, parser, auth_base, cloud)
499 71882bca Stavros Sachtouris
        elif _help:
500 e0da0f90 Stavros Sachtouris
            parser.parser.print_help()
501 074f5027 Stavros Sachtouris
            _groups_help(parser.arguments)
502 71882bca Stavros Sachtouris
        else:
503 844a6bdb Stavros Sachtouris
            run_shell(exe, parser, auth_base, cloud)
504 71882bca Stavros Sachtouris
    except CLIError as err:
505 b6a99832 Stavros Sachtouris
        print_error_message(err)
506 71882bca Stavros Sachtouris
        if _debug:
507 71882bca Stavros Sachtouris
            raise err
508 71882bca Stavros Sachtouris
        exit(1)
509 6069b53b Stavros Sachtouris
    except Exception as er:
510 6069b53b Stavros Sachtouris
        print('Unknown Error: %s' % er)
511 71882bca Stavros Sachtouris
        if _debug:
512 6069b53b Stavros Sachtouris
            raise
513 6069b53b Stavros Sachtouris
        exit(1)