Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli.py @ 2f749e6e

History | View | Annotate | Download (11.6 kB)

1 5d1d131b Giorgos Verigakis
#!/usr/bin/env python
2 5d1d131b Giorgos Verigakis
3 43ca98ee Giorgos Verigakis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
4 5d1d131b Giorgos Verigakis
#
5 5d1d131b Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
6 5d1d131b Giorgos Verigakis
# without modification, are permitted provided that the following
7 5d1d131b Giorgos Verigakis
# conditions are met:
8 5d1d131b Giorgos Verigakis
#
9 5d1d131b Giorgos Verigakis
#   1. Redistributions of source code must retain the above
10 5d1d131b Giorgos Verigakis
#      copyright notice, this list of conditions and the following
11 5d1d131b Giorgos Verigakis
#      disclaimer.
12 5d1d131b Giorgos Verigakis
#
13 5d1d131b Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
14 5d1d131b Giorgos Verigakis
#      copyright notice, this list of conditions and the following
15 5d1d131b Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
16 5d1d131b Giorgos Verigakis
#      provided with the distribution.
17 5d1d131b Giorgos Verigakis
#
18 5d1d131b Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 5d1d131b Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 5d1d131b Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 5d1d131b Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 5d1d131b Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 5d1d131b Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 5d1d131b Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 5d1d131b Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 5d1d131b Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 5d1d131b Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 5d1d131b Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 5d1d131b Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
30 5d1d131b Giorgos Verigakis
#
31 5d1d131b Giorgos Verigakis
# The views and conclusions contained in the software and
32 5d1d131b Giorgos Verigakis
# documentation are those of the authors and should not be
33 5d1d131b Giorgos Verigakis
# interpreted as representing official policies, either expressed
34 5d1d131b Giorgos Verigakis
# or implied, of GRNET S.A.
35 5d1d131b Giorgos Verigakis
36 098ca087 Giorgos Verigakis
from __future__ import print_function
37 098ca087 Giorgos Verigakis
38 435008b6 Stavros Sachtouris
import gevent.monkey
39 435008b6 Stavros Sachtouris
#Monkey-patch everything for gevent early on
40 435008b6 Stavros Sachtouris
gevent.monkey.patch_all()
41 435008b6 Stavros Sachtouris
42 5d1d131b Giorgos Verigakis
import inspect
43 5d1d131b Giorgos Verigakis
import logging
44 8378faf2 Giorgos Verigakis
import sys
45 5d1d131b Giorgos Verigakis
46 8378faf2 Giorgos Verigakis
from argparse import ArgumentParser
47 57b8dd5a Giorgos Verigakis
from base64 import b64encode
48 d83a2834 Giorgos Verigakis
from os.path import abspath, basename, exists
49 8378faf2 Giorgos Verigakis
from sys import exit, stdout, stderr
50 5d1d131b Giorgos Verigakis
51 5f47b77d Giorgos Verigakis
try:
52 5f47b77d Giorgos Verigakis
    from collections import OrderedDict
53 5f47b77d Giorgos Verigakis
except ImportError:
54 5f47b77d Giorgos Verigakis
    from ordereddict import OrderedDict
55 5f47b77d Giorgos Verigakis
56 e92440bd Stavros Sachtouris
from colors import magenta, red, yellow, bold
57 b974d110 Stavros Sachtouris
#from progress.bar import IncrementalBar
58 1ff49234 Stavros Sachtouris
#from requests.exceptions import ConnectionError
59 6a0b1658 Giorgos Verigakis
60 71ff5136 Stavros Sachtouris
from . import clients
61 5f47b77d Giorgos Verigakis
from .config import Config
62 b974d110 Stavros Sachtouris
#from .utils import print_list, print_dict, print_items, format_size
63 5d1d131b Giorgos Verigakis
64 eb3ca8ca Giorgos Verigakis
_commands = OrderedDict()
65 eb3ca8ca Giorgos Verigakis
66 b974d110 Stavros Sachtouris
GROUPS = {}
67 a2e8e549 Stavros Sachtouris
CLI_LOCATIONS = ['', 'kamaki', 'kamaki.commands']
68 653b0597 Giorgos Verigakis
69 71ff5136 Stavros Sachtouris
class CLIError(Exception):
70 71ff5136 Stavros Sachtouris
    def __init__(self, message, status=0, details='', importance=0):
71 71ff5136 Stavros Sachtouris
        """importance is set by the raiser
72 71ff5136 Stavros Sachtouris
        0 is the lowest possible importance
73 71ff5136 Stavros Sachtouris
        Suggested values: 0, 1, 2, 3
74 71ff5136 Stavros Sachtouris
        """
75 71ff5136 Stavros Sachtouris
        super(CLIError, self).__init__(message, status, details)
76 71ff5136 Stavros Sachtouris
        self.message = message
77 71ff5136 Stavros Sachtouris
        self.status = status
78 71ff5136 Stavros Sachtouris
        self.details = details
79 71ff5136 Stavros Sachtouris
        self.importance = importance
80 71ff5136 Stavros Sachtouris
81 c3659429 Stavros Sachtouris
    def __unicode__(self):
82 c3659429 Stavros Sachtouris
        return unicode(self.message)
83 c3659429 Stavros Sachtouris
84 b974d110 Stavros Sachtouris
def command(group=None, name=None, syntax=None):
85 eb3ca8ca Giorgos Verigakis
    """Class decorator that registers a class as a CLI command."""
86 44b8928d Giorgos Verigakis
87 eb3ca8ca Giorgos Verigakis
    def decorator(cls):
88 eb3ca8ca Giorgos Verigakis
        grp, sep, cmd = cls.__name__.partition('_')
89 eb3ca8ca Giorgos Verigakis
        if not sep:
90 eb3ca8ca Giorgos Verigakis
            grp, cmd = None, cls.__name__
91 44b8928d Giorgos Verigakis
92 b974d110 Stavros Sachtouris
        #cls.api = api
93 eb3ca8ca Giorgos Verigakis
        cls.group = group or grp
94 eb3ca8ca Giorgos Verigakis
        cls.name = name or cmd
95 44b8928d Giorgos Verigakis
96 f3ddb705 Giorgos Verigakis
        short_description, sep, long_description = cls.__doc__.partition('\n')
97 f3ddb705 Giorgos Verigakis
        cls.description = short_description
98 f3ddb705 Giorgos Verigakis
        cls.long_description = long_description or short_description
99 44b8928d Giorgos Verigakis
100 f3ddb705 Giorgos Verigakis
        cls.syntax = syntax
101 eb3ca8ca Giorgos Verigakis
        if cls.syntax is None:
102 eb3ca8ca Giorgos Verigakis
            # Generate a syntax string based on main's arguments
103 eb3ca8ca Giorgos Verigakis
            spec = inspect.getargspec(cls.main.im_func)
104 eb3ca8ca Giorgos Verigakis
            args = spec.args[1:]
105 eb3ca8ca Giorgos Verigakis
            n = len(args) - len(spec.defaults or ())
106 9aece4ba Stavros Sachtouris
            required = ' '.join('<%s>' % x.replace('____', '[:').replace('___', ':').replace('__',']').replace('_', ' ') for x in args[:n])
107 9aece4ba Stavros Sachtouris
            optional = ' '.join('[%s]' % x.replace('____', '[:').replace('___', ':').replace('__', ']').replace('_', ' ') for x in args[n:])
108 eb3ca8ca Giorgos Verigakis
            cls.syntax = ' '.join(x for x in [required, optional] if x)
109 8ab2c986 Giorgos Verigakis
            if spec.varargs:
110 8ab2c986 Giorgos Verigakis
                cls.syntax += ' <%s ...>' % spec.varargs
111 44b8928d Giorgos Verigakis
112 eb3ca8ca Giorgos Verigakis
        if cls.group not in _commands:
113 eb3ca8ca Giorgos Verigakis
            _commands[cls.group] = OrderedDict()
114 eb3ca8ca Giorgos Verigakis
        _commands[cls.group][cls.name] = cls
115 eb3ca8ca Giorgos Verigakis
        return cls
116 eb3ca8ca Giorgos Verigakis
    return decorator
117 5d1d131b Giorgos Verigakis
118 b974d110 Stavros Sachtouris
def set_api_description(api, description):
119 b974d110 Stavros Sachtouris
    """Method to be called by api CLIs
120 b974d110 Stavros Sachtouris
    Each CLI can set more than one api descriptions"""
121 b974d110 Stavros Sachtouris
    GROUPS[api] = description
122 8ab2c986 Giorgos Verigakis
123 b974d110 Stavros Sachtouris
def main():
124 44b8928d Giorgos Verigakis
125 b974d110 Stavros Sachtouris
    def print_groups():
126 b974d110 Stavros Sachtouris
        print('\nGroups:')
127 b974d110 Stavros Sachtouris
        for group in _commands:
128 b974d110 Stavros Sachtouris
            description = GROUPS.get(group, '')
129 b974d110 Stavros Sachtouris
            print(' ', group.ljust(12), description)
130 43ca98ee Giorgos Verigakis
131 b974d110 Stavros Sachtouris
    def print_commands(group):
132 098ca087 Giorgos Verigakis
        description = GROUPS.get(group, '')
133 b974d110 Stavros Sachtouris
        if description:
134 b974d110 Stavros Sachtouris
            print('\n' + description)
135 b974d110 Stavros Sachtouris
136 b974d110 Stavros Sachtouris
        print('\nCommands:')
137 b974d110 Stavros Sachtouris
        for name, cls in _commands[group].items():
138 b974d110 Stavros Sachtouris
            print(' ', name.ljust(14), cls.description)
139 b974d110 Stavros Sachtouris
140 b974d110 Stavros Sachtouris
    def manage_logging_handlers(args):
141 b974d110 Stavros Sachtouris
        """This is mostly to handle logging for clients package"""
142 b974d110 Stavros Sachtouris
143 b974d110 Stavros Sachtouris
        def add_handler(name, level, prefix=''):
144 b974d110 Stavros Sachtouris
            h = logging.StreamHandler()
145 b974d110 Stavros Sachtouris
            fmt = logging.Formatter(prefix + '%(message)s')
146 b974d110 Stavros Sachtouris
            h.setFormatter(fmt)
147 b974d110 Stavros Sachtouris
            logger = logging.getLogger(name)
148 b974d110 Stavros Sachtouris
            logger.addHandler(h)
149 b974d110 Stavros Sachtouris
            logger.setLevel(level)
150 b974d110 Stavros Sachtouris
151 b974d110 Stavros Sachtouris
        if args.silent:
152 b974d110 Stavros Sachtouris
            add_handler('', logging.CRITICAL)
153 b974d110 Stavros Sachtouris
        elif args.debug:
154 b974d110 Stavros Sachtouris
            add_handler('requests', logging.INFO, prefix='* ')
155 b974d110 Stavros Sachtouris
            add_handler('clients.send', logging.DEBUG, prefix='> ')
156 b974d110 Stavros Sachtouris
            add_handler('clients.recv', logging.DEBUG, prefix='< ')
157 b974d110 Stavros Sachtouris
        elif args.verbose:
158 b974d110 Stavros Sachtouris
            add_handler('requests', logging.INFO, prefix='* ')
159 b974d110 Stavros Sachtouris
            add_handler('clients.send', logging.INFO, prefix='> ')
160 b974d110 Stavros Sachtouris
            add_handler('clients.recv', logging.INFO, prefix='< ')
161 b974d110 Stavros Sachtouris
        elif args.include:
162 b974d110 Stavros Sachtouris
            add_handler('clients.recv', logging.INFO)
163 b974d110 Stavros Sachtouris
        else:
164 b974d110 Stavros Sachtouris
            add_handler('', logging.WARNING)
165 b974d110 Stavros Sachtouris
166 b974d110 Stavros Sachtouris
    def load_groups(config):
167 b974d110 Stavros Sachtouris
        """load groups and import CLIs and Modules"""
168 b974d110 Stavros Sachtouris
        loaded_modules = {}
169 b974d110 Stavros Sachtouris
        for api in config.apis():
170 b974d110 Stavros Sachtouris
            api_cli = config.get(api, 'cli')
171 b974d110 Stavros Sachtouris
            if None == api_cli or len(api_cli)==0:
172 1ff49234 Stavros Sachtouris
                print('Warnig: No Command Line Interface "%s" given for API "%s"'%(api_cli, api))
173 1ff49234 Stavros Sachtouris
                print('\t(cli option in config file)')
174 b974d110 Stavros Sachtouris
                continue
175 b974d110 Stavros Sachtouris
            if not loaded_modules.has_key(api_cli):
176 1ff49234 Stavros Sachtouris
                loaded_modules[api_cli] = False
177 1ff49234 Stavros Sachtouris
                for location in CLI_LOCATIONS:
178 1ff49234 Stavros Sachtouris
                    location += api_cli if location == '' else '.%s'%api_cli
179 b974d110 Stavros Sachtouris
                    try:
180 1ff49234 Stavros Sachtouris
                        __import__(location)
181 1ff49234 Stavros Sachtouris
                        loaded_modules[api_cli] = True
182 1ff49234 Stavros Sachtouris
                        break
183 b974d110 Stavros Sachtouris
                    except ImportError:
184 1ff49234 Stavros Sachtouris
                        pass
185 1ff49234 Stavros Sachtouris
                if not loaded_modules[api_cli]:
186 1ff49234 Stavros Sachtouris
                    print('Warning: failed to load Command Line Interface "%s" for API "%s"'%(api_cli, api))
187 1ff49234 Stavros Sachtouris
                    print('\t(No suitable cli in known paths)')
188 1ff49234 Stavros Sachtouris
                    continue
189 b974d110 Stavros Sachtouris
            if not GROUPS.has_key(api):
190 b974d110 Stavros Sachtouris
                GROUPS[api] = 'No description (interface: %s)'%api_cli
191 b974d110 Stavros Sachtouris
192 b974d110 Stavros Sachtouris
    def init_parser(exe):
193 b974d110 Stavros Sachtouris
        parser = ArgumentParser(add_help=False)
194 b974d110 Stavros Sachtouris
        parser.prog = '%s <group> <command>' % exe
195 b974d110 Stavros Sachtouris
        parser.add_argument('-h', '--help', dest='help', action='store_true',
196 b974d110 Stavros Sachtouris
                          default=False,
197 b974d110 Stavros Sachtouris
                          help="Show this help message and exit")
198 b974d110 Stavros Sachtouris
        parser.add_argument('--config', dest='config', metavar='PATH',
199 b974d110 Stavros Sachtouris
                          help="Specify the path to the configuration file")
200 b974d110 Stavros Sachtouris
        parser.add_argument('-d', '--debug', dest='debug', action='store_true',
201 b974d110 Stavros Sachtouris
                          default=False,
202 b974d110 Stavros Sachtouris
                          help="Include debug output")
203 b974d110 Stavros Sachtouris
        parser.add_argument('-i', '--include', dest='include', action='store_true',
204 b974d110 Stavros Sachtouris
                          default=False,
205 b974d110 Stavros Sachtouris
                          help="Include protocol headers in the output")
206 b974d110 Stavros Sachtouris
        parser.add_argument('-s', '--silent', dest='silent', action='store_true',
207 b974d110 Stavros Sachtouris
                          default=False,
208 b974d110 Stavros Sachtouris
                          help="Silent mode, don't output anything")
209 b974d110 Stavros Sachtouris
        parser.add_argument('-v', '--verbose', dest='verbose', action='store_true',
210 b974d110 Stavros Sachtouris
                          default=False,
211 b974d110 Stavros Sachtouris
                          help="Make the operation more talkative")
212 b974d110 Stavros Sachtouris
        parser.add_argument('-V', '--version', dest='version', action='store_true',
213 b974d110 Stavros Sachtouris
                          default=False,
214 b974d110 Stavros Sachtouris
                          help="Show version number and quit")
215 b974d110 Stavros Sachtouris
        parser.add_argument('-o', dest='options', action='append',
216 b974d110 Stavros Sachtouris
                          default=[], metavar="KEY=VAL",
217 b974d110 Stavros Sachtouris
                          help="Override a config value")
218 b974d110 Stavros Sachtouris
        return parser
219 b974d110 Stavros Sachtouris
220 25062837 Stavros Sachtouris
    def find_term_in_args(arg_list, term_list):
221 8e8af8ce Stavros Sachtouris
        """find an arg_list term in term_list. All other terms up to found
222 8e8af8ce Stavros Sachtouris
        term are rearanged at the end of arg_list, preserving relative order
223 8e8af8ce Stavros Sachtouris
        """
224 25062837 Stavros Sachtouris
        arg_tail = []
225 25062837 Stavros Sachtouris
        while len(arg_list) > 0:
226 25062837 Stavros Sachtouris
            group = arg_list.pop(0)
227 8e8af8ce Stavros Sachtouris
            if group not in term_list:
228 25062837 Stavros Sachtouris
                arg_tail.append(group)
229 25062837 Stavros Sachtouris
            else:
230 25062837 Stavros Sachtouris
                arg_list += arg_tail
231 25062837 Stavros Sachtouris
                return group
232 25062837 Stavros Sachtouris
        return None
233 25062837 Stavros Sachtouris
234 b974d110 Stavros Sachtouris
    """Main Code"""
235 8378faf2 Giorgos Verigakis
    exe = basename(sys.argv[0])
236 b974d110 Stavros Sachtouris
    parser = init_parser(exe)
237 8378faf2 Giorgos Verigakis
    args, argv = parser.parse_known_args()
238 8378faf2 Giorgos Verigakis
239 b974d110 Stavros Sachtouris
    #print version
240 8378faf2 Giorgos Verigakis
    if args.version:
241 f3ddb705 Giorgos Verigakis
        import kamaki
242 098ca087 Giorgos Verigakis
        print("kamaki %s" % kamaki.__version__)
243 f3ddb705 Giorgos Verigakis
        exit(0)
244 d83a2834 Giorgos Verigakis
245 8378faf2 Giorgos Verigakis
    config = Config(args.config) if args.config else Config()
246 8378faf2 Giorgos Verigakis
247 b974d110 Stavros Sachtouris
    #load config options from command line
248 8378faf2 Giorgos Verigakis
    for option in args.options:
249 f3ddb705 Giorgos Verigakis
        keypath, sep, val = option.partition('=')
250 f3ddb705 Giorgos Verigakis
        if not sep:
251 098ca087 Giorgos Verigakis
            print("Invalid option '%s'" % option)
252 f3ddb705 Giorgos Verigakis
            exit(1)
253 f3ddb705 Giorgos Verigakis
        section, sep, key = keypath.partition('.')
254 f3ddb705 Giorgos Verigakis
        if not sep:
255 098ca087 Giorgos Verigakis
            print("Invalid option '%s'" % option)
256 f3ddb705 Giorgos Verigakis
            exit(1)
257 f3ddb705 Giorgos Verigakis
        config.override(section.strip(), key.strip(), val.strip())
258 44b8928d Giorgos Verigakis
259 b974d110 Stavros Sachtouris
    load_groups(config)
260 25062837 Stavros Sachtouris
    group = find_term_in_args(argv, _commands)
261 8378faf2 Giorgos Verigakis
    if not group:
262 eb3ca8ca Giorgos Verigakis
        parser.print_help()
263 f3ddb705 Giorgos Verigakis
        print_groups()
264 8e8af8ce Stavros Sachtouris
        exit(0)
265 8378faf2 Giorgos Verigakis
266 8378faf2 Giorgos Verigakis
    parser.prog = '%s %s <command>' % (exe, group)
267 25062837 Stavros Sachtouris
    command = find_term_in_args(argv, _commands[group])
268 8378faf2 Giorgos Verigakis
269 8378faf2 Giorgos Verigakis
    if not command:
270 eb3ca8ca Giorgos Verigakis
        parser.print_help()
271 f3ddb705 Giorgos Verigakis
        print_commands(group)
272 a1c50326 Giorgos Verigakis
        exit(0)
273 8378faf2 Giorgos Verigakis
274 8378faf2 Giorgos Verigakis
    cmd = _commands[group][command]()
275 8378faf2 Giorgos Verigakis
276 8378faf2 Giorgos Verigakis
    parser.prog = '%s %s %s' % (exe, group, command)
277 8378faf2 Giorgos Verigakis
    if cmd.syntax:
278 8378faf2 Giorgos Verigakis
        parser.prog += '  %s' % cmd.syntax
279 f3ddb705 Giorgos Verigakis
    parser.description = cmd.description
280 eb3ca8ca Giorgos Verigakis
    parser.epilog = ''
281 f3ddb705 Giorgos Verigakis
    if hasattr(cmd, 'update_parser'):
282 f3ddb705 Giorgos Verigakis
        cmd.update_parser(parser)
283 44b8928d Giorgos Verigakis
284 b974d110 Stavros Sachtouris
    #check other args
285 8378faf2 Giorgos Verigakis
    args, argv = parser.parse_known_args()
286 e92440bd Stavros Sachtouris
    if group != argv[0]:
287 e92440bd Stavros Sachtouris
        errmsg = red('Invalid command group '+argv[0])
288 e92440bd Stavros Sachtouris
        print(errmsg, file=stderr)
289 e92440bd Stavros Sachtouris
        exit(1)
290 e92440bd Stavros Sachtouris
    if command != argv[1]:
291 e92440bd Stavros Sachtouris
        errmsg = red('Invalid command "%s" in group "%s"'%(argv[1], argv[0]))
292 e92440bd Stavros Sachtouris
        print(errmsg, file=stderr)
293 e92440bd Stavros Sachtouris
        exit(1)
294 44b8928d Giorgos Verigakis
295 8378faf2 Giorgos Verigakis
    if args.help:
296 eb3ca8ca Giorgos Verigakis
        parser.print_help()
297 a1c50326 Giorgos Verigakis
        exit(0)
298 44b8928d Giorgos Verigakis
299 b974d110 Stavros Sachtouris
    manage_logging_handlers(args)
300 8378faf2 Giorgos Verigakis
    cmd.args = args
301 6a0b1658 Giorgos Verigakis
    cmd.config = config
302 5d1d131b Giorgos Verigakis
    try:
303 8378faf2 Giorgos Verigakis
        ret = cmd.main(*argv[2:])
304 a1c50326 Giorgos Verigakis
        exit(ret)
305 a6757cbc Giorgos Verigakis
    except TypeError as e:
306 a6757cbc Giorgos Verigakis
        if e.args and e.args[0].startswith('main()'):
307 a6757cbc Giorgos Verigakis
            parser.print_help()
308 a1c50326 Giorgos Verigakis
            exit(1)
309 a6757cbc Giorgos Verigakis
        else:
310 a6757cbc Giorgos Verigakis
            raise
311 71ff5136 Stavros Sachtouris
    except CLIError as err:
312 71ff5136 Stavros Sachtouris
        errmsg = 'CLI Error '
313 71ff5136 Stavros Sachtouris
        errmsg += '(%s): '%err.status if err.status else ': '
314 71ff5136 Stavros Sachtouris
        errmsg += err.message if err.message else ''
315 71ff5136 Stavros Sachtouris
        if err.importance == 1:
316 71ff5136 Stavros Sachtouris
            errmsg = yellow(errmsg)
317 71ff5136 Stavros Sachtouris
        elif err.importance == 2:
318 71ff5136 Stavros Sachtouris
            errmsg = magenta(errmsg)
319 71ff5136 Stavros Sachtouris
        elif err.importance > 2:
320 71ff5136 Stavros Sachtouris
            errmsg = red(errmsg)
321 71ff5136 Stavros Sachtouris
        print(errmsg, file=stderr)
322 b974d110 Stavros Sachtouris
        exit(1)
323 5d1d131b Giorgos Verigakis
324 5d1d131b Giorgos Verigakis
if __name__ == '__main__':
325 a1c50326 Giorgos Verigakis
    main()