Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / __init__.py @ dfee2caf

History | View | Annotate | Download (4.4 kB)

1
#!/usr/bin/env python
2

    
3
# Copyright 2011-2012 GRNET S.A. All rights reserved.
4
#
5
# Redistribution and use in source and binary forms, with or
6
# without modification, are permitted provided that the following
7
# conditions are met:
8
#
9
#   1. Redistributions of source code must retain the above
10
#      copyright notice, this list of conditions and the following
11
#      disclaimer.
12
#
13
#   2. Redistributions in binary form must reproduce the above
14
#      copyright notice, this list of conditions and the following
15
#      disclaimer in the documentation and/or other materials
16
#      provided with the distribution.
17
#
18
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
# POSSIBILITY OF SUCH DAMAGE.
30
#
31
# The views and conclusions contained in the software and
32
# documentation are those of the authors and should not be
33
# interpreted as representing official policies, either expressed
34
# or implied, of GRNET S.A.
35

    
36
from __future__ import print_function
37

    
38
import gevent.monkey
39
#Monkey-patch everything for gevent early on
40
gevent.monkey.patch_all()
41

    
42
import logging
43

    
44
from inspect import getargspec
45
from argparse import ArgumentParser
46
from base64 import b64encode
47
from os.path import abspath, basename, exists
48
from sys import exit, stdout, stderr, argv
49

    
50
try:
51
    from collections import OrderedDict
52
except ImportError:
53
    from ordereddict import OrderedDict
54

    
55
#from kamaki import clients
56
from .errors import CLIError
57
from .config import Config #TO BE REMOVED
58
from .utils import magenta, red, yellow, CommandTree
59
from argument import _arguments, parse_known_args
60

    
61
_commands = CommandTree()
62

    
63
GROUPS={}
64
CLI_LOCATIONS = ['kamaki.cli.commands', 'kamaki.commands', 'kamaki.cli', 'kamaki', '']
65

    
66
def command():
67
    """Class decorator that registers a class as a CLI command"""
68

    
69
    def decorator(cls):
70
        """Any class with name of the form cmd1_cmd2_cmd3_... is accepted"""
71
        cls.description, sep, cls.long_description = cls.__doc__.partition('\n')
72

    
73
        # Generate a syntax string based on main's arguments
74
        spec = getargspec(cls.main.im_func)
75
        args = spec.args[1:]
76
        n = len(args) - len(spec.defaults or ())
77
        required = ' '.join('<%s>' % x.replace('____', '[:').replace('___', ':').replace('__',']').\
78
            replace('_', ' ') for x in args[:n])
79
        optional = ' '.join('[%s]' % x.replace('____', '[:').replace('___', ':').replace('__', ']').\
80
            replace('_', ' ') for x in args[n:])
81
        cls.syntax = ' '.join(x for x in [required, optional] if x)
82
        if spec.varargs:
83
            cls.syntax += ' <%s ...>' % spec.varargs
84

    
85
        _commands.add(cls.__name__, cls)
86
        return cls
87
    return decorator
88

    
89
def set_api_description(api, description):
90
    """Method to be called by api CLIs
91
    Each CLI can set more than one api descriptions"""
92
    GROUPS[api] = description
93

    
94
def _init_parser(exe):
95
    parser = ArgumentParser(add_help=True)
96
    parser.prog='%s <cmd_group> [<cmd_subbroup> ...] <cmd>'%exe
97
    for name, argument in _arguments.items():
98
        argument.update_parser(parser, name)
99
    return parser
100

    
101
def _print_error_message(cli_err):
102
    errmsg = '%s'%unicode(cli_err) +' (%s)'%cli_err.status if cli_err.status else ' '
103
    if cli_err.importance == 1:
104
        errmsg = magenta(errmsg)
105
    elif cli_err.importance == 2:
106
        errmsg = yellow(errmsg)
107
    elif cli_err.importance > 2:
108
        errmsg = red(errmsg)
109
    stdout.write(errmsg)
110
    if cli_err.details is not None and len(cli_err.details) > 0:
111
        print(': %s'%cli_err.details)
112
    else:
113
        print
114

    
115
def one_command():
116
    try:
117
        exe = basename(argv[0])
118
        parser = _init_parser(exe)
119
        parsed, unparsed = parse_known_args(parser)
120
        if _arguments['version'].value:
121
            exit(0)
122
    except CLIError as err:
123
        _print_error_message(err)
124
        exit(1)