Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / utils / __init__.py @ 36fa6ffb

History | View | Annotate | Download (16.1 kB)

1 27d3b17d Stavros Sachtouris
# Copyright 2011-2014 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 7493ccb6 Stavros Sachtouris
#      copyright notice, this list of conditions and the following
9 7493ccb6 Stavros Sachtouris
#      disclaimer.
10 7493ccb6 Stavros Sachtouris
#
11 7493ccb6 Stavros Sachtouris
#   2. Redistributions in binary form must reproduce the above
12 7493ccb6 Stavros Sachtouris
#      copyright notice, this list of conditions and the following
13 7493ccb6 Stavros Sachtouris
#      disclaimer in the documentation and/or other materials
14 7493ccb6 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 7493ccb6 Stavros Sachtouris
# or implied, of GRNET S.A.
33 3dabe5d2 Stavros Sachtouris
34 8df239df Stavros Sachtouris
from sys import stdout, stdin, stderr
35 efbcdc41 Stavros Sachtouris
from re import compile as regex_compile
36 14b25e00 Stavros Sachtouris
from os import walk, path
37 0399ac7e Stavros Sachtouris
from json import dumps
38 27d3b17d Stavros Sachtouris
from kamaki.cli.logger import get_logger
39 27d3b17d Stavros Sachtouris
from locale import getpreferredencoding
40 02846a75 Stavros Sachtouris
41 2ff0b7bd Stavros Sachtouris
from kamaki.cli.errors import raiseCLIError
42 3dabe5d2 Stavros Sachtouris
43 f55d3a15 Stavros Sachtouris
44 a0608786 Stavros Sachtouris
INDENT_TAB = 4
45 27d3b17d Stavros Sachtouris
log = get_logger(__name__)
46 27d3b17d Stavros Sachtouris
pref_enc = getpreferredencoding()
47 f55d3a15 Stavros Sachtouris
48 f55d3a15 Stavros Sachtouris
49 362adf50 Stavros Sachtouris
suggest = dict(ansicolors=dict(
50 6fb4af77 Stavros Sachtouris
        active=False,
51 df55e7aa Stavros Sachtouris
        url='#install-ansicolors',
52 362adf50 Stavros Sachtouris
        description='Add colors to console responses'))
53 6fb4af77 Stavros Sachtouris
54 dfee2caf Stavros Sachtouris
try:
55 dfee2caf Stavros Sachtouris
    from colors import magenta, red, yellow, bold
56 dfee2caf Stavros Sachtouris
except ImportError:
57 f93854ae Stavros Sachtouris
    def dummy(val):
58 dfee2caf Stavros Sachtouris
        return val
59 f93854ae Stavros Sachtouris
    red = yellow = magenta = bold = dummy
60 6fb4af77 Stavros Sachtouris
    suggest['ansicolors']['active'] = True
61 6fb4af77 Stavros Sachtouris
62 6fb4af77 Stavros Sachtouris
63 27d3b17d Stavros Sachtouris
def _encode_nicely(somestr, encoding, replacement='?'):
64 27d3b17d Stavros Sachtouris
    """Encode somestr as 'encoding', but don't raise errors (replace with ?)
65 27d3b17d Stavros Sachtouris
        This method is slow. Us it only for grace.
66 27d3b17d Stavros Sachtouris
        :param encoding: (str) encode every character in this encoding
67 27d3b17d Stavros Sachtouris
        :param replacement: (char) replace each char raising encode-decode errs
68 27d3b17d Stavros Sachtouris
    """
69 27d3b17d Stavros Sachtouris
    newstr, err_counter = '', 0
70 27d3b17d Stavros Sachtouris
    for c in somestr:
71 27d3b17d Stavros Sachtouris
        try:
72 90c22848 Stavros Sachtouris
            newc = c.decode('utf-8').encode(encoding)
73 27d3b17d Stavros Sachtouris
            newstr = '%s%s' % (newstr, newc)
74 6e24ad30 Stavros Sachtouris
        except UnicodeError as e:
75 27d3b17d Stavros Sachtouris
            newstr = '%s%s' % (newstr, replacement)
76 27d3b17d Stavros Sachtouris
            err_counter += 1
77 27d3b17d Stavros Sachtouris
    if err_counter:
78 6e24ad30 Stavros Sachtouris
        log.warning('WARNING: \t%s character%s failed to be encoded as %s' % (
79 27d3b17d Stavros Sachtouris
            err_counter, 's' if err_counter > 1 else '', encoding))
80 6e24ad30 Stavros Sachtouris
        log.debug('Unicode Error %s' % e)
81 27d3b17d Stavros Sachtouris
    return newstr
82 27d3b17d Stavros Sachtouris
83 27d3b17d Stavros Sachtouris
84 27d3b17d Stavros Sachtouris
def DontRaiseUnicodeError(foo):
85 90c22848 Stavros Sachtouris
    if pref_enc.lower() == 'utf-8':
86 90c22848 Stavros Sachtouris
        return foo
87 90c22848 Stavros Sachtouris
88 27d3b17d Stavros Sachtouris
    def wrap(self, *args, **kwargs):
89 27d3b17d Stavros Sachtouris
        try:
90 27d3b17d Stavros Sachtouris
            s = kwargs.pop('s')
91 27d3b17d Stavros Sachtouris
        except KeyError:
92 27d3b17d Stavros Sachtouris
            try:
93 27d3b17d Stavros Sachtouris
                s = args[0]
94 27d3b17d Stavros Sachtouris
            except IndexError:
95 27d3b17d Stavros Sachtouris
                return foo(self, *args, **kwargs)
96 27d3b17d Stavros Sachtouris
            args = args[1:]
97 27d3b17d Stavros Sachtouris
        try:
98 90c22848 Stavros Sachtouris
            s = (u'%s' % s).decode('utf-8').encode(pref_enc)
99 27d3b17d Stavros Sachtouris
        except UnicodeError as ue:
100 27d3b17d Stavros Sachtouris
            log.debug('Encoding(%s): %s' % (pref_enc, ue))
101 90c22848 Stavros Sachtouris
            s = _encode_nicely(u'%s' % s, pref_enc, replacement='?')
102 27d3b17d Stavros Sachtouris
        return foo(self, s, *args, **kwargs)
103 27d3b17d Stavros Sachtouris
    return wrap
104 27d3b17d Stavros Sachtouris
105 27d3b17d Stavros Sachtouris
106 8df239df Stavros Sachtouris
def encode_for_console(s, encoding=pref_enc, replacement='?'):
107 8df239df Stavros Sachtouris
    if encoding.lower() == 'utf-8':
108 8df239df Stavros Sachtouris
        return s
109 8df239df Stavros Sachtouris
    try:
110 90c22848 Stavros Sachtouris
        return s.decode('utf-8').encode(encoding)
111 8df239df Stavros Sachtouris
    except UnicodeError as ue:
112 8df239df Stavros Sachtouris
        log.debug('Encoding(%s): %s' % (encoding, ue))
113 8df239df Stavros Sachtouris
        return _encode_nicely(s, encoding, replacement)
114 8df239df Stavros Sachtouris
115 8df239df Stavros Sachtouris
116 69691087 Stavros Sachtouris
def suggest_missing(miss=None, exclude=[]):
117 6fb4af77 Stavros Sachtouris
    global suggest
118 69691087 Stavros Sachtouris
    sgs = dict(suggest)
119 69691087 Stavros Sachtouris
    for exc in exclude:
120 69691087 Stavros Sachtouris
        try:
121 69691087 Stavros Sachtouris
            sgs.pop(exc)
122 69691087 Stavros Sachtouris
        except KeyError:
123 69691087 Stavros Sachtouris
            pass
124 6fb4af77 Stavros Sachtouris
    kamaki_docs = 'http://www.synnefo.org/docs/kamaki/latest'
125 8df239df Stavros Sachtouris
126 69691087 Stavros Sachtouris
    for k, v in (miss, sgs[miss]) if miss else sgs.items():
127 8df239df Stavros Sachtouris
        if v['active'] and stderr.isatty():
128 8df239df Stavros Sachtouris
            stderr.write('Suggestion: you may like to install %s\n' % k)
129 8df239df Stavros Sachtouris
            stderr.write('\t%s\n' % encode_for_console(v['description']))
130 8df239df Stavros Sachtouris
            stderr.write('\tIt is easy, here are the instructions:\n')
131 8df239df Stavros Sachtouris
            stderr.write('\t%s/installation.html%s\n' % (
132 8df239df Stavros Sachtouris
                kamaki_docs, v['url']))
133 8df239df Stavros Sachtouris
            stderr.flush()
134 f997679d Stavros Sachtouris
135 fd5db045 Stavros Sachtouris
136 f8426b5c Stavros Sachtouris
def guess_mime_type(
137 f8426b5c Stavros Sachtouris
        filename,
138 f8426b5c Stavros Sachtouris
        default_content_type='application/octet-stream',
139 f8426b5c Stavros Sachtouris
        default_encoding=None):
140 f8426b5c Stavros Sachtouris
    assert filename, 'Cannot guess mimetype for empty filename'
141 f8426b5c Stavros Sachtouris
    try:
142 f8426b5c Stavros Sachtouris
        from mimetypes import guess_type
143 f8426b5c Stavros Sachtouris
        ctype, cenc = guess_type(filename)
144 f8426b5c Stavros Sachtouris
        return ctype or default_content_type, cenc or default_encoding
145 f8426b5c Stavros Sachtouris
    except ImportError:
146 8df239df Stavros Sachtouris
        stderr.write('WARNING: Cannot import mimetypes, using defaults\n')
147 8df239df Stavros Sachtouris
        stderr.flush()
148 f8426b5c Stavros Sachtouris
        return (default_content_type, default_encoding)
149 f8426b5c Stavros Sachtouris
150 f8426b5c Stavros Sachtouris
151 67cea04c Stavros Sachtouris
def remove_colors():
152 67cea04c Stavros Sachtouris
    global bold
153 3dabe5d2 Stavros Sachtouris
    global red
154 3dabe5d2 Stavros Sachtouris
    global yellow
155 3dabe5d2 Stavros Sachtouris
    global magenta
156 fd5db045 Stavros Sachtouris
157 67cea04c Stavros Sachtouris
    def dummy(val):
158 67cea04c Stavros Sachtouris
        return val
159 3dabe5d2 Stavros Sachtouris
    red = yellow = magenta = bold = dummy
160 7493ccb6 Stavros Sachtouris
161 fd5db045 Stavros Sachtouris
162 cdeadadc Stavros Sachtouris
def pretty_keys(d, delim='_', recursive=False):
163 cdeadadc Stavros Sachtouris
    """<term>delim<term> to <term> <term> transformation"""
164 cdeadadc Stavros Sachtouris
    new_d = dict(d)
165 cdeadadc Stavros Sachtouris
    for k, v in d.items():
166 cdeadadc Stavros Sachtouris
        new_v = new_d.pop(k)
167 cdeadadc Stavros Sachtouris
        new_d[k.replace(delim, ' ').strip()] = pretty_keys(
168 cdeadadc Stavros Sachtouris
            new_v, delim, True) if (
169 cdeadadc Stavros Sachtouris
                recursive and isinstance(v, dict)) else new_v
170 7493ccb6 Stavros Sachtouris
    return new_d
171 7493ccb6 Stavros Sachtouris
172 fd5db045 Stavros Sachtouris
173 8df239df Stavros Sachtouris
def print_json(data, out=stdout, encoding=pref_enc):
174 0399ac7e Stavros Sachtouris
    """Print a list or dict as json in console
175 0399ac7e Stavros Sachtouris

176 0399ac7e Stavros Sachtouris
    :param data: json-dumpable data
177 0399ac7e Stavros Sachtouris

178 fa9c0c38 Stavros Sachtouris
    :param out: Input/Output stream to dump values into
179 fa9c0c38 Stavros Sachtouris
    """
180 df55e7aa Stavros Sachtouris
    out.write(dumps(data, indent=INDENT_TAB))
181 df55e7aa Stavros Sachtouris
    out.write('\n')
182 545c6c29 Stavros Sachtouris
183 545c6c29 Stavros Sachtouris
184 de73876b Stavros Sachtouris
def print_dict(
185 f55d3a15 Stavros Sachtouris
        d,
186 f55d3a15 Stavros Sachtouris
        exclude=(), indent=0,
187 fa9c0c38 Stavros Sachtouris
        with_enumeration=False, recursive_enumeration=False, out=stdout):
188 f55d3a15 Stavros Sachtouris
    """Pretty-print a dictionary object
189 f55d3a15 Stavros Sachtouris
    <indent>key: <non iterable item>
190 f55d3a15 Stavros Sachtouris
    <indent>key:
191 a0608786 Stavros Sachtouris
    <indent + INDENT_TAB><pretty-print iterable>
192 f8681ec8 Stavros Sachtouris

193 f55d3a15 Stavros Sachtouris
    :param d: (dict)
194 f8681ec8 Stavros Sachtouris

195 f55d3a15 Stavros Sachtouris
    :param exclude: (iterable of strings) keys to exclude from printing
196 f8681ec8 Stavros Sachtouris

197 f55d3a15 Stavros Sachtouris
    :param indent: (int) initial indentation (recursive)
198 f8681ec8 Stavros Sachtouris

199 f55d3a15 Stavros Sachtouris
    :param with_enumeration: (bool) enumerate 1st-level keys
200 f8681ec8 Stavros Sachtouris

201 f55d3a15 Stavros Sachtouris
    :param recursive_enumeration: (bool) recursively enumerate iterables (does
202 f55d3a15 Stavros Sachtouris
        not enumerate 1st level keys)
203 f8681ec8 Stavros Sachtouris

204 fa9c0c38 Stavros Sachtouris
    :param out: Input/Output stream to dump values into
205 fa9c0c38 Stavros Sachtouris

206 f55d3a15 Stavros Sachtouris
    :raises CLIError: if preconditions fail
207 f8681ec8 Stavros Sachtouris
    """
208 f55d3a15 Stavros Sachtouris
    assert isinstance(d, dict), 'print_dict input must be a dict'
209 f55d3a15 Stavros Sachtouris
    assert indent >= 0, 'print_dict indent must be >= 0'
210 7493ccb6 Stavros Sachtouris
211 f55d3a15 Stavros Sachtouris
    for i, (k, v) in enumerate(d.items()):
212 f55d3a15 Stavros Sachtouris
        k = ('%s' % k).strip()
213 f55d3a15 Stavros Sachtouris
        if k in exclude:
214 7493ccb6 Stavros Sachtouris
            continue
215 1e92e97d Stavros Sachtouris
        print_str = ' ' * indent
216 1e92e97d Stavros Sachtouris
        print_str += '%s.' % (i + 1) if with_enumeration else ''
217 1e92e97d Stavros Sachtouris
        print_str += '%s:' % k
218 f55d3a15 Stavros Sachtouris
        if isinstance(v, dict):
219 df55e7aa Stavros Sachtouris
            out.write(print_str + '\n')
220 de73876b Stavros Sachtouris
            print_dict(
221 a0608786 Stavros Sachtouris
                v, exclude, indent + INDENT_TAB,
222 fa9c0c38 Stavros Sachtouris
                recursive_enumeration, recursive_enumeration, out)
223 f55d3a15 Stavros Sachtouris
        elif isinstance(v, list) or isinstance(v, tuple):
224 df55e7aa Stavros Sachtouris
            out.write(print_str + '\n')
225 de73876b Stavros Sachtouris
            print_list(
226 a0608786 Stavros Sachtouris
                v, exclude, indent + INDENT_TAB,
227 fa9c0c38 Stavros Sachtouris
                recursive_enumeration, recursive_enumeration, out)
228 7493ccb6 Stavros Sachtouris
        else:
229 df55e7aa Stavros Sachtouris
            out.write('%s %s\n' % (print_str, v))
230 fd5db045 Stavros Sachtouris
231 7493ccb6 Stavros Sachtouris
232 de73876b Stavros Sachtouris
def print_list(
233 f55d3a15 Stavros Sachtouris
        l,
234 f55d3a15 Stavros Sachtouris
        exclude=(), indent=0,
235 fa9c0c38 Stavros Sachtouris
        with_enumeration=False, recursive_enumeration=False, out=stdout):
236 f55d3a15 Stavros Sachtouris
    """Pretty-print a list of items
237 f55d3a15 Stavros Sachtouris
    <indent>key: <non iterable item>
238 f55d3a15 Stavros Sachtouris
    <indent>key:
239 a0608786 Stavros Sachtouris
    <indent + INDENT_TAB><pretty-print iterable>
240 f8681ec8 Stavros Sachtouris

241 f55d3a15 Stavros Sachtouris
    :param l: (list)
242 f8681ec8 Stavros Sachtouris

243 f55d3a15 Stavros Sachtouris
    :param exclude: (iterable of strings) items to exclude from printing
244 f8681ec8 Stavros Sachtouris

245 f55d3a15 Stavros Sachtouris
    :param indent: (int) initial indentation (recursive)
246 f8681ec8 Stavros Sachtouris

247 f55d3a15 Stavros Sachtouris
    :param with_enumeration: (bool) enumerate 1st-level items
248 f8681ec8 Stavros Sachtouris

249 f55d3a15 Stavros Sachtouris
    :param recursive_enumeration: (bool) recursively enumerate iterables (does
250 f55d3a15 Stavros Sachtouris
        not enumerate 1st level keys)
251 f8681ec8 Stavros Sachtouris

252 fa9c0c38 Stavros Sachtouris
    :param out: Input/Output stream to dump values into
253 fa9c0c38 Stavros Sachtouris

254 f55d3a15 Stavros Sachtouris
    :raises CLIError: if preconditions fail
255 f8681ec8 Stavros Sachtouris
    """
256 f55d3a15 Stavros Sachtouris
    assert isinstance(l, list) or isinstance(l, tuple), (
257 f55d3a15 Stavros Sachtouris
        'print_list prinbts a list or tuple')
258 f55d3a15 Stavros Sachtouris
    assert indent >= 0, 'print_list indent must be >= 0'
259 f551841a Stavros Sachtouris
260 f55d3a15 Stavros Sachtouris
    for i, item in enumerate(l):
261 1e92e97d Stavros Sachtouris
        print_str = ' ' * indent
262 1e92e97d Stavros Sachtouris
        print_str += '%s.' % (i + 1) if with_enumeration else ''
263 7493ccb6 Stavros Sachtouris
        if isinstance(item, dict):
264 c17b8bc0 Stavros Sachtouris
            if with_enumeration:
265 df55e7aa Stavros Sachtouris
                out.write(print_str + '\n')
266 0f383dcc Stavros Sachtouris
            elif i and i < len(l):
267 1e92e97d Stavros Sachtouris
                out.write('\n')
268 de73876b Stavros Sachtouris
            print_dict(
269 a0608786 Stavros Sachtouris
                item, exclude,
270 a0608786 Stavros Sachtouris
                indent + (INDENT_TAB if with_enumeration else 0),
271 fa9c0c38 Stavros Sachtouris
                recursive_enumeration, recursive_enumeration, out)
272 f55d3a15 Stavros Sachtouris
        elif isinstance(item, list) or isinstance(item, tuple):
273 c17b8bc0 Stavros Sachtouris
            if with_enumeration:
274 df55e7aa Stavros Sachtouris
                out.write(print_str + '\n')
275 0f383dcc Stavros Sachtouris
            elif i and i < len(l):
276 1e92e97d Stavros Sachtouris
                out.write('\n')
277 de73876b Stavros Sachtouris
            print_list(
278 a0608786 Stavros Sachtouris
                item, exclude, indent + INDENT_TAB,
279 fa9c0c38 Stavros Sachtouris
                recursive_enumeration, recursive_enumeration, out)
280 7493ccb6 Stavros Sachtouris
        else:
281 f55d3a15 Stavros Sachtouris
            item = ('%s' % item).strip()
282 f55d3a15 Stavros Sachtouris
            if item in exclude:
283 f55d3a15 Stavros Sachtouris
                continue
284 df55e7aa Stavros Sachtouris
            out.write('%s%s\n' % (print_str, item))
285 439826ec Stavros Sachtouris
286 439826ec Stavros Sachtouris
287 de73876b Stavros Sachtouris
def print_items(
288 24ff0a35 Stavros Sachtouris
        items, title=('id', 'name'),
289 fa9c0c38 Stavros Sachtouris
        with_enumeration=False, with_redundancy=False, out=stdout):
290 a494a741 Stavros Sachtouris
    """print dict or list items in a list, using some values as title
291 a494a741 Stavros Sachtouris
    Objects of next level don't inherit enumeration (default: off) or titles
292 a494a741 Stavros Sachtouris

293 a494a741 Stavros Sachtouris
    :param items: (list) items are lists or dict
294 f55d3a15 Stavros Sachtouris

295 a494a741 Stavros Sachtouris
    :param title: (tuple) keys to use their values as title
296 f55d3a15 Stavros Sachtouris

297 a494a741 Stavros Sachtouris
    :param with_enumeration: (boolean) enumerate items (order id on title)
298 f55d3a15 Stavros Sachtouris

299 a494a741 Stavros Sachtouris
    :param with_redundancy: (boolean) values in title also appear on body
300 f55d3a15 Stavros Sachtouris

301 fa9c0c38 Stavros Sachtouris
    :param out: Input/Output stream to dump values into
302 a494a741 Stavros Sachtouris
    """
303 daedfe3c Stavros Sachtouris
    if not items:
304 daedfe3c Stavros Sachtouris
        return
305 46d130c9 Stavros Sachtouris
    if not (isinstance(items, dict) or isinstance(items, list) or isinstance(
306 46d130c9 Stavros Sachtouris
                items, tuple)):
307 df55e7aa Stavros Sachtouris
        out.write('%s\n' % items)
308 31618e2a Stavros Sachtouris
        return
309 31618e2a Stavros Sachtouris
310 54d800e8 Stavros Sachtouris
    for i, item in enumerate(items):
311 a494a741 Stavros Sachtouris
        if with_enumeration:
312 df55e7aa Stavros Sachtouris
            out.write('%s. ' % (i + 1))
313 7493ccb6 Stavros Sachtouris
        if isinstance(item, dict):
314 46d130c9 Stavros Sachtouris
            item = dict(item)
315 46d130c9 Stavros Sachtouris
            title = sorted(set(title).intersection(item))
316 46d130c9 Stavros Sachtouris
            pick = item.get if with_redundancy else item.pop
317 1e92e97d Stavros Sachtouris
            header = ' '.join('%s' % pick(key) for key in title)
318 df55e7aa Stavros Sachtouris
            out.write((unicode(bold(header) if header else '') + '\n'))
319 fa9c0c38 Stavros Sachtouris
            print_dict(item, indent=INDENT_TAB, out=out)
320 46d130c9 Stavros Sachtouris
        elif isinstance(item, list) or isinstance(item, tuple):
321 fa9c0c38 Stavros Sachtouris
            print_list(item, indent=INDENT_TAB, out=out)
322 a494a741 Stavros Sachtouris
        else:
323 df55e7aa Stavros Sachtouris
            out.write(' %s\n' % item)
324 7493ccb6 Stavros Sachtouris
325 fd5db045 Stavros Sachtouris
326 23963422 Stavros Sachtouris
def format_size(size, decimal_factors=False):
327 23963422 Stavros Sachtouris
    units = ('B', 'KB', 'MB', 'GB', 'TB') if decimal_factors else (
328 23963422 Stavros Sachtouris
        'B', 'KiB', 'MiB', 'GiB', 'TiB')
329 23963422 Stavros Sachtouris
    step = 1000 if decimal_factors else 1024
330 23963422 Stavros Sachtouris
    fstep = float(step)
331 7493ccb6 Stavros Sachtouris
    try:
332 7493ccb6 Stavros Sachtouris
        size = float(size)
333 23963422 Stavros Sachtouris
    except (ValueError, TypeError) as err:
334 23963422 Stavros Sachtouris
        raiseCLIError(err, 'Cannot format %s in bytes' % (
335 23963422 Stavros Sachtouris
            ','.join(size) if isinstance(size, tuple) else size))
336 23963422 Stavros Sachtouris
    for i, unit in enumerate(units):
337 23963422 Stavros Sachtouris
        if size < step or i + 1 == len(units):
338 7493ccb6 Stavros Sachtouris
            break
339 23963422 Stavros Sachtouris
        size /= fstep
340 001200c3 Stavros Sachtouris
    s = ('%.2f' % size)
341 23963422 Stavros Sachtouris
    s = s.replace('%s' % step, '%s.99' % (step - 1)) if size <= fstep else s
342 001200c3 Stavros Sachtouris
    while '.' in s and s[-1] in ('0', '.'):
343 001200c3 Stavros Sachtouris
        s = s[:-1]
344 7493ccb6 Stavros Sachtouris
    return s + unit
345 7493ccb6 Stavros Sachtouris
346 fd5db045 Stavros Sachtouris
347 001200c3 Stavros Sachtouris
def to_bytes(size, format):
348 001200c3 Stavros Sachtouris
    """
349 001200c3 Stavros Sachtouris
    :param size: (float) the size in the given format
350 001200c3 Stavros Sachtouris
    :param format: (case insensitive) KiB, KB, MiB, MB, GiB, GB, TiB, TB
351 001200c3 Stavros Sachtouris

352 001200c3 Stavros Sachtouris
    :returns: (int) the size in bytes
353 23963422 Stavros Sachtouris
    :raises ValueError: if invalid size or format
354 23963422 Stavros Sachtouris
    :raises AttributeError: if format is not str
355 23963422 Stavros Sachtouris
    :raises TypeError: if size is not arithmetic or convertible to arithmetic
356 001200c3 Stavros Sachtouris
    """
357 001200c3 Stavros Sachtouris
    format = format.upper()
358 001200c3 Stavros Sachtouris
    if format == 'B':
359 001200c3 Stavros Sachtouris
        return int(size)
360 001200c3 Stavros Sachtouris
    size = float(size)
361 001200c3 Stavros Sachtouris
    units_dc = ('KB', 'MB', 'GB', 'TB')
362 001200c3 Stavros Sachtouris
    units_bi = ('KIB', 'MIB', 'GIB', 'TIB')
363 001200c3 Stavros Sachtouris
364 001200c3 Stavros Sachtouris
    factor = 1024 if format in units_bi else 1000 if format in units_dc else 0
365 001200c3 Stavros Sachtouris
    if not factor:
366 001200c3 Stavros Sachtouris
        raise ValueError('Invalid data size format %s' % format)
367 001200c3 Stavros Sachtouris
    for prefix in ('K', 'M', 'G', 'T'):
368 001200c3 Stavros Sachtouris
        size *= factor
369 001200c3 Stavros Sachtouris
        if format.startswith(prefix):
370 001200c3 Stavros Sachtouris
            break
371 001200c3 Stavros Sachtouris
    return int(size)
372 001200c3 Stavros Sachtouris
373 001200c3 Stavros Sachtouris
374 fd5db045 Stavros Sachtouris
def dict2file(d, f, depth=0):
375 7493ccb6 Stavros Sachtouris
    for k, v in d.items():
376 23963422 Stavros Sachtouris
        f.write('%s%s: ' % (' ' * INDENT_TAB * depth, k))
377 fd5db045 Stavros Sachtouris
        if isinstance(v, dict):
378 7493ccb6 Stavros Sachtouris
            f.write('\n')
379 fd5db045 Stavros Sachtouris
            dict2file(v, f, depth + 1)
380 23963422 Stavros Sachtouris
        elif isinstance(v, list) or isinstance(v, tuple):
381 7493ccb6 Stavros Sachtouris
            f.write('\n')
382 fd5db045 Stavros Sachtouris
            list2file(v, f, depth + 1)
383 7493ccb6 Stavros Sachtouris
        else:
384 23963422 Stavros Sachtouris
            f.write('%s\n' % v)
385 fd5db045 Stavros Sachtouris
386 7493ccb6 Stavros Sachtouris
387 fd5db045 Stavros Sachtouris
def list2file(l, f, depth=1):
388 7493ccb6 Stavros Sachtouris
    for item in l:
389 fd5db045 Stavros Sachtouris
        if isinstance(item, dict):
390 fd5db045 Stavros Sachtouris
            dict2file(item, f, depth + 1)
391 23963422 Stavros Sachtouris
        elif isinstance(item, list) or isinstance(item, tuple):
392 fd5db045 Stavros Sachtouris
            list2file(item, f, depth + 1)
393 7493ccb6 Stavros Sachtouris
        else:
394 23963422 Stavros Sachtouris
            f.write('%s%s\n' % (' ' * INDENT_TAB * depth, item))
395 efbcdc41 Stavros Sachtouris
396 efbcdc41 Stavros Sachtouris
# Split input auxiliary
397 efbcdc41 Stavros Sachtouris
398 efbcdc41 Stavros Sachtouris
399 efbcdc41 Stavros Sachtouris
def _parse_with_regex(line, regex):
400 efbcdc41 Stavros Sachtouris
    re_parser = regex_compile(regex)
401 efbcdc41 Stavros Sachtouris
    return (re_parser.split(line), re_parser.findall(line))
402 efbcdc41 Stavros Sachtouris
403 efbcdc41 Stavros Sachtouris
404 0ba7b031 Stavros Sachtouris
def _get_from_parsed(parsed_str):
405 0ba7b031 Stavros Sachtouris
    try:
406 0ba7b031 Stavros Sachtouris
        parsed_str = parsed_str.strip()
407 0ba7b031 Stavros Sachtouris
    except:
408 0ba7b031 Stavros Sachtouris
        return None
409 23963422 Stavros Sachtouris
    return ([parsed_str[1:-1]] if (
410 23963422 Stavros Sachtouris
        parsed_str[0] == parsed_str[-1] and parsed_str[0] in ("'", '"')) else (
411 23963422 Stavros Sachtouris
            parsed_str.split(' '))) if parsed_str else None
412 0ba7b031 Stavros Sachtouris
413 0ba7b031 Stavros Sachtouris
414 0ba7b031 Stavros Sachtouris
def split_input(line):
415 0ba7b031 Stavros Sachtouris
    if not line:
416 0ba7b031 Stavros Sachtouris
        return []
417 0ba7b031 Stavros Sachtouris
    reg_expr = '\'.*?\'|".*?"|^[\S]*$'
418 0ba7b031 Stavros Sachtouris
    (trivial_parts, interesting_parts) = _parse_with_regex(line, reg_expr)
419 0ba7b031 Stavros Sachtouris
    assert(len(trivial_parts) == 1 + len(interesting_parts))
420 0ba7b031 Stavros Sachtouris
    terms = []
421 0ba7b031 Stavros Sachtouris
    for i, tpart in enumerate(trivial_parts):
422 0ba7b031 Stavros Sachtouris
        part = _get_from_parsed(tpart)
423 0ba7b031 Stavros Sachtouris
        if part:
424 0ba7b031 Stavros Sachtouris
            terms += part
425 0ba7b031 Stavros Sachtouris
        try:
426 0ba7b031 Stavros Sachtouris
            part = _get_from_parsed(interesting_parts[i])
427 0ba7b031 Stavros Sachtouris
        except IndexError:
428 0ba7b031 Stavros Sachtouris
            break
429 0ba7b031 Stavros Sachtouris
        if part:
430 b9eebf2a Stavros Sachtouris
            if tpart and not tpart[-1].endswith(' '):
431 b9eebf2a Stavros Sachtouris
                terms[-1] += ' '.join(part)
432 b9eebf2a Stavros Sachtouris
            else:
433 b9eebf2a Stavros Sachtouris
                terms += part
434 0ba7b031 Stavros Sachtouris
    return terms
435 0ba7b031 Stavros Sachtouris
436 0ba7b031 Stavros Sachtouris
437 36fa6ffb Stavros Sachtouris
def ask_user(msg, true_resp=('y', ), **kwargs):
438 7147e1ca Stavros Sachtouris
    """Print msg and read user response
439 7147e1ca Stavros Sachtouris

440 001200c3 Stavros Sachtouris
    :param true_resp: (tuple of chars)
441 7147e1ca Stavros Sachtouris

442 7147e1ca Stavros Sachtouris
    :returns: (bool) True if reponse in true responses, False otherwise
443 7147e1ca Stavros Sachtouris
    """
444 fa9c0c38 Stavros Sachtouris
    yep = ', '.join(true_resp)
445 fa9c0c38 Stavros Sachtouris
    nope = '<not %s>' % yep if 'n' in true_resp or 'N' in true_resp else 'N'
446 36fa6ffb Stavros Sachtouris
    user_response = raw_input('%s [%s/%s]: ' % (msg, yep, nope))
447 fa9c0c38 Stavros Sachtouris
    return user_response[0].lower() in [s.lower() for s in true_resp]
448 b482315a Stavros Sachtouris
449 14b25e00 Stavros Sachtouris
450 14b25e00 Stavros Sachtouris
def get_path_size(testpath):
451 14b25e00 Stavros Sachtouris
    if path.isfile(testpath):
452 14b25e00 Stavros Sachtouris
        return path.getsize(testpath)
453 14b25e00 Stavros Sachtouris
    total_size = 0
454 14b25e00 Stavros Sachtouris
    for top, dirs, files in walk(path.abspath(testpath)):
455 14b25e00 Stavros Sachtouris
        for f in files:
456 14b25e00 Stavros Sachtouris
            f = path.join(top, f)
457 14b25e00 Stavros Sachtouris
            if path.isfile(f):
458 14b25e00 Stavros Sachtouris
                total_size += path.getsize(f)
459 14b25e00 Stavros Sachtouris
    return total_size
460 7ba195e5 Stavros Sachtouris
461 7ba195e5 Stavros Sachtouris
462 7ba195e5 Stavros Sachtouris
def remove_from_items(list_of_dicts, key_to_remove):
463 7ba195e5 Stavros Sachtouris
    for item in list_of_dicts:
464 7ba195e5 Stavros Sachtouris
        assert isinstance(item, dict), 'Item %s not a dict' % item
465 7ba195e5 Stavros Sachtouris
        item.pop(key_to_remove, None)
466 1716a15d Stavros Sachtouris
467 1716a15d Stavros Sachtouris
468 1716a15d Stavros Sachtouris
def filter_dicts_by_dict(
469 1716a15d Stavros Sachtouris
    list_of_dicts, filters,
470 1716a15d Stavros Sachtouris
    exact_match=True, case_sensitive=False):
471 1716a15d Stavros Sachtouris
    """
472 1716a15d Stavros Sachtouris
    :param list_of_dicts: (list) each dict contains "raw" key-value pairs
473 1716a15d Stavros Sachtouris

474 1716a15d Stavros Sachtouris
    :param filters: (dict) filters in key-value form
475 1716a15d Stavros Sachtouris

476 1716a15d Stavros Sachtouris
    :param exact_match: (bool) if false, check if the filter value is part of
477 1716a15d Stavros Sachtouris
        the actual value
478 1716a15d Stavros Sachtouris

479 27d3b17d Stavros Sachtouris
    :param case_sensitive: (bool) refers to values only (not keys)
480 1716a15d Stavros Sachtouris

481 1716a15d Stavros Sachtouris
    :returns: (list) only the dicts that match all filters
482 1716a15d Stavros Sachtouris
    """
483 1716a15d Stavros Sachtouris
    new_dicts = []
484 1716a15d Stavros Sachtouris
    for d in list_of_dicts:
485 1716a15d Stavros Sachtouris
        if set(filters).difference(d):
486 1716a15d Stavros Sachtouris
            continue
487 1716a15d Stavros Sachtouris
        match = True
488 1716a15d Stavros Sachtouris
        for k, v in filters.items():
489 1716a15d Stavros Sachtouris
            dv, v = ('%s' % d[k]), ('%s' % v)
490 1716a15d Stavros Sachtouris
            if not case_sensitive:
491 1716a15d Stavros Sachtouris
                dv, v = dv.lower(), v.lower()
492 1716a15d Stavros Sachtouris
            if not ((
493 1716a15d Stavros Sachtouris
                    exact_match and v == dv) or (
494 1716a15d Stavros Sachtouris
                    (not exact_match) and v in dv)):
495 1716a15d Stavros Sachtouris
                match = False
496 1716a15d Stavros Sachtouris
                break
497 1716a15d Stavros Sachtouris
        if match:
498 1716a15d Stavros Sachtouris
            new_dicts.append(d)
499 1716a15d Stavros Sachtouris
    return new_dicts