Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / utils.py @ c17b8bc0

History | View | Annotate | Download (8.3 kB)

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

    
34
from sys import stdout
35
from re import compile as regex_compile
36
from kamaki.cli.errors import raiseCLIError
37

    
38
try:
39
    from colors import magenta, red, yellow, bold
40
except ImportError:
41
    # No colours? No worries, use dummy foo instead
42
    def dummy(val):
43
        return val
44
    red = yellow = magenta = bold = dummy
45

    
46

    
47
def remove_colors():
48
    global bold
49
    global red
50
    global yellow
51
    global magenta
52

    
53
    def dummy(val):
54
        return val
55
    red = yellow = magenta = bold = dummy
56

    
57

    
58
def pretty_keys(d, delim='_', recurcive=False):
59
    """<term>delim<term> to <term> <term> transformation
60
    """
61
    new_d = {}
62
    for key, val in d.items():
63
        new_key = key.split(delim)[-1]
64
        if recurcive and isinstance(val, dict):
65
            new_val = pretty_keys(val, delim, recurcive)
66
        else:
67
            new_val = val
68
        new_d[new_key] = new_val
69
    return new_d
70

    
71

    
72
def print_dict(d,
73
    exclude=(),
74
    ident=0,
75
    with_enumeration=False,
76
    recursive_enumeration=False):
77
    """
78
    Pretty-print a dictionary object
79

80
    :param d: (dict) the input
81

82
    :param excelude: (set or list) keys to exclude from printing
83

84
    :param ident: (int) initial indentation (recursive)
85

86
    :param with_enumeration: (bool) enumerate each 1st level key if true
87

88
    :recursive_enumeration: (bool) recursively enumerate dicts and lists of
89
        2nd level or deeper
90

91
    :raises CLIError: (TypeError wrapper) non-dict input
92
    """
93
    if not isinstance(d, dict):
94
        raiseCLIError(TypeError('Cannot dict_print a non-dict object'))
95

    
96
    if d:
97
        margin = max(len(unicode(key).strip())\
98
            for key in d.keys() if key not in exclude)
99

    
100
    counter = 1
101
    for key, val in sorted(d.items()):
102
        if key in exclude:
103
            continue
104
        print_str = ''
105
        if with_enumeration:
106
            print_str = '%s. ' % counter
107
            counter += 1
108
        print_str = '%s%s' % (' ' * (ident - len(print_str)), print_str)
109
        print_str += ('%s' % key).strip()
110
        print_str += ' ' * (margin - len(unicode(key).strip()))
111
        print_str += ': '
112
        if isinstance(val, dict):
113
            print(print_str)
114
            print_dict(val,
115
                exclude=exclude,
116
                ident=margin + ident,
117
                with_enumeration=recursive_enumeration,
118
                recursive_enumeration=recursive_enumeration)
119
        elif isinstance(val, list):
120
            print(print_str)
121
            print_list(val,
122
                exclude=exclude,
123
                ident=margin + ident,
124
                with_enumeration=recursive_enumeration,
125
                recursive_enumeration=recursive_enumeration)
126
        else:
127
            print print_str + ' ' + unicode(val).strip()
128

    
129

    
130
def print_list(l,
131
    exclude=(),
132
    ident=0,
133
    with_enumeration=False,
134
    recursive_enumeration=False):
135
    """
136
    Pretty-print a list object
137

138
    :param l: (list) the input
139

140
    :param excelude: (object - anytype) values to exclude from printing
141

142
    :param ident: (int) initial indentation (recursive)
143

144
    :param with_enumeration: (bool) enumerate each 1st level value if true
145

146
    :recursive_enumeration: (bool) recursively enumerate dicts and lists of
147
        2nd level or deeper
148

149
    :raises CLIError: (TypeError wrapper) non-list input
150
    """
151
    if not isinstance(l, list):
152
        raiseCLIError(TypeError('Cannot list_print a non-list object'))
153

    
154
    if l:
155
        try:
156
            margin = max(len(unicode(item).strip()) for item in l\
157
                if not (isinstance(item, dict)\
158
                or isinstance(item, list)\
159
                or item in exclude))
160
        except ValueError:
161
            margin = (2 + len(unicode(len(l)))) if enumerate else 1
162

    
163
    counter = 1
164
    prefix = ''
165
    for item in sorted(l):
166
        if item in exclude:
167
            continue
168
        elif with_enumeration:
169
            prefix = '%s. ' % counter
170
            counter += 1
171
            prefix = '%s%s' % (' ' * (ident - len(prefix)), prefix)
172
        else:
173
            prefix = ' ' * ident
174
        if isinstance(item, dict):
175
            if with_enumeration:
176
                print(prefix)
177
            print_dict(item,
178
                exclude=exclude,
179
                ident=margin + ident,
180
                with_enumeration=recursive_enumeration,
181
                recursive_enumeration=recursive_enumeration)
182
        elif isinstance(item, list):
183
            if with_enumeration:
184
                print(prefix)
185
            print_list(item,
186
                exclude=exclude,
187
                ident=margin + ident,
188
                with_enumeration=recursive_enumeration,
189
                recursive_enumeration=recursive_enumeration)
190
        else:
191
            print('%s%s' % (prefix, item))
192

    
193

    
194
def print_items(items, title=('id', 'name')):
195
    for item in items:
196
        if isinstance(item, dict) or isinstance(item, list):
197
            header = ' '.join(unicode(item.pop(key))\
198
                for key in title if key in item)
199
            print(' ')
200
            print(bold(header))
201
        if isinstance(item, dict):
202
            print_dict(item, ident=1)
203
        elif isinstance(item, list):
204
            print_list(item, ident=1)
205

    
206

    
207
def format_size(size):
208
    units = ('B', 'K', 'M', 'G', 'T')
209
    try:
210
        size = float(size)
211
    except ValueError as err:
212
        raiseCLIError(err, 'Cannot format %s in bytes' % size)
213
    for unit in units:
214
        if size < 1024:
215
            break
216
        size /= 1024
217
    s = ('%.1f' % size)
218
    if '.0' == s[-2:]:
219
        s = s[:-2]
220
    return s + unit
221

    
222

    
223
def dict2file(d, f, depth=0):
224
    for k, v in d.items():
225
        f.write('%s%s: ' % ('\t' * depth, k))
226
        if isinstance(v, dict):
227
            f.write('\n')
228
            dict2file(v, f, depth + 1)
229
        elif isinstance(v, list):
230
            f.write('\n')
231
            list2file(v, f, depth + 1)
232
        else:
233
            f.write(' %s\n' % unicode(v))
234

    
235

    
236
def list2file(l, f, depth=1):
237
    for item in l:
238
        if isinstance(item, dict):
239
            dict2file(item, f, depth + 1)
240
        elif isinstance(item, list):
241
            list2file(item, f, depth + 1)
242
        else:
243
            f.write('%s%s\n' % ('\t' * depth, unicode(item)))
244

    
245
# Split input auxiliary
246

    
247

    
248
def _parse_with_regex(line, regex):
249
    re_parser = regex_compile(regex)
250
    return (re_parser.split(line), re_parser.findall(line))
251

    
252

    
253
def _sub_split(line):
254
    terms = []
255
    (sub_trivials, sub_interesting) = _parse_with_regex(line, ' ".*?" ')
256
    for subi, subipart in enumerate(sub_interesting):
257
        terms += sub_trivials[subi].split()
258
        terms.append(subipart[2:-2])
259
    terms += sub_trivials[-1].split()
260
    return terms
261

    
262

    
263
def split_input(line):
264
    """Use regular expressions to split a line correctly
265
    """
266
    line = ' %s ' % line
267
    (trivial_parts, interesting_parts) = _parse_with_regex(line, ' \'.*?\' ')
268
    terms = []
269
    for i, ipart in enumerate(interesting_parts):
270
        terms += _sub_split(trivial_parts[i])
271
        terms.append(ipart[2:-2])
272
    terms += _sub_split(trivial_parts[-1])
273
    return terms