Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / utils / __init__.py @ 8df239df

History | View | Annotate | Download (16.3 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 6fb4af77 Stavros Sachtouris
        url='#install-ansicolors-progress',
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 27d3b17d Stavros Sachtouris
            newc = c.encode(encoding)
73 27d3b17d Stavros Sachtouris
            newstr = '%s%s' % (newstr, newc)
74 27d3b17d Stavros Sachtouris
        except UnicodeError:
75 27d3b17d Stavros Sachtouris
            newstr = '%s%s' % (newstr, replacement)
76 27d3b17d Stavros Sachtouris
            err_counter += 1
77 27d3b17d Stavros Sachtouris
    if err_counter:
78 27d3b17d Stavros Sachtouris
        log.debug('\t%s character%s failed to be encoded as %s' % (
79 27d3b17d Stavros Sachtouris
            err_counter, 's' if err_counter > 1 else '', encoding))
80 27d3b17d Stavros Sachtouris
    return newstr
81 27d3b17d Stavros Sachtouris
82 27d3b17d Stavros Sachtouris
83 27d3b17d Stavros Sachtouris
def DontRaiseUnicodeError(foo):
84 27d3b17d Stavros Sachtouris
    def wrap(self, *args, **kwargs):
85 27d3b17d Stavros Sachtouris
        try:
86 27d3b17d Stavros Sachtouris
            s = kwargs.pop('s')
87 27d3b17d Stavros Sachtouris
        except KeyError:
88 27d3b17d Stavros Sachtouris
            try:
89 27d3b17d Stavros Sachtouris
                s = args[0]
90 27d3b17d Stavros Sachtouris
            except IndexError:
91 27d3b17d Stavros Sachtouris
                return foo(self, *args, **kwargs)
92 27d3b17d Stavros Sachtouris
            args = args[1:]
93 27d3b17d Stavros Sachtouris
        try:
94 27d3b17d Stavros Sachtouris
            s = s.encode(pref_enc)
95 27d3b17d Stavros Sachtouris
        except UnicodeError as ue:
96 27d3b17d Stavros Sachtouris
            log.debug('Encoding(%s): %s' % (pref_enc, ue))
97 27d3b17d Stavros Sachtouris
            s = _encode_nicely(s, pref_enc, replacement='?')
98 27d3b17d Stavros Sachtouris
        return foo(self, s, *args, **kwargs)
99 27d3b17d Stavros Sachtouris
    return wrap
100 27d3b17d Stavros Sachtouris
101 27d3b17d Stavros Sachtouris
102 8df239df Stavros Sachtouris
def encode_for_console(s, encoding=pref_enc, replacement='?'):
103 8df239df Stavros Sachtouris
    if encoding.lower() == 'utf-8':
104 8df239df Stavros Sachtouris
        return s
105 8df239df Stavros Sachtouris
    try:
106 8df239df Stavros Sachtouris
        return s.encode(encoding)
107 8df239df Stavros Sachtouris
    except UnicodeError as ue:
108 8df239df Stavros Sachtouris
        log.debug('Encoding(%s): %s' % (encoding, ue))
109 8df239df Stavros Sachtouris
        return _encode_nicely(s, encoding, replacement)
110 8df239df Stavros Sachtouris
111 8df239df Stavros Sachtouris
112 69691087 Stavros Sachtouris
def suggest_missing(miss=None, exclude=[]):
113 6fb4af77 Stavros Sachtouris
    global suggest
114 69691087 Stavros Sachtouris
    sgs = dict(suggest)
115 69691087 Stavros Sachtouris
    for exc in exclude:
116 69691087 Stavros Sachtouris
        try:
117 69691087 Stavros Sachtouris
            sgs.pop(exc)
118 69691087 Stavros Sachtouris
        except KeyError:
119 69691087 Stavros Sachtouris
            pass
120 6fb4af77 Stavros Sachtouris
    kamaki_docs = 'http://www.synnefo.org/docs/kamaki/latest'
121 8df239df Stavros Sachtouris
122 69691087 Stavros Sachtouris
    for k, v in (miss, sgs[miss]) if miss else sgs.items():
123 8df239df Stavros Sachtouris
        if v['active'] and stderr.isatty():
124 8df239df Stavros Sachtouris
            stderr.write('Suggestion: you may like to install %s\n' % k)
125 8df239df Stavros Sachtouris
            stderr.write('\t%s\n' % encode_for_console(v['description']))
126 8df239df Stavros Sachtouris
            stderr.write('\tIt is easy, here are the instructions:\n')
127 8df239df Stavros Sachtouris
            stderr.write('\t%s/installation.html%s\n' % (
128 8df239df Stavros Sachtouris
                kamaki_docs, v['url']))
129 8df239df Stavros Sachtouris
            stderr.flush()
130 f997679d Stavros Sachtouris
131 fd5db045 Stavros Sachtouris
132 f8426b5c Stavros Sachtouris
def guess_mime_type(
133 f8426b5c Stavros Sachtouris
        filename,
134 f8426b5c Stavros Sachtouris
        default_content_type='application/octet-stream',
135 f8426b5c Stavros Sachtouris
        default_encoding=None):
136 f8426b5c Stavros Sachtouris
    assert filename, 'Cannot guess mimetype for empty filename'
137 f8426b5c Stavros Sachtouris
    try:
138 f8426b5c Stavros Sachtouris
        from mimetypes import guess_type
139 f8426b5c Stavros Sachtouris
        ctype, cenc = guess_type(filename)
140 f8426b5c Stavros Sachtouris
        return ctype or default_content_type, cenc or default_encoding
141 f8426b5c Stavros Sachtouris
    except ImportError:
142 8df239df Stavros Sachtouris
        stderr.write('WARNING: Cannot import mimetypes, using defaults\n')
143 8df239df Stavros Sachtouris
        stderr.flush()
144 f8426b5c Stavros Sachtouris
        return (default_content_type, default_encoding)
145 f8426b5c Stavros Sachtouris
146 f8426b5c Stavros Sachtouris
147 67cea04c Stavros Sachtouris
def remove_colors():
148 67cea04c Stavros Sachtouris
    global bold
149 3dabe5d2 Stavros Sachtouris
    global red
150 3dabe5d2 Stavros Sachtouris
    global yellow
151 3dabe5d2 Stavros Sachtouris
    global magenta
152 fd5db045 Stavros Sachtouris
153 67cea04c Stavros Sachtouris
    def dummy(val):
154 67cea04c Stavros Sachtouris
        return val
155 3dabe5d2 Stavros Sachtouris
    red = yellow = magenta = bold = dummy
156 7493ccb6 Stavros Sachtouris
157 fd5db045 Stavros Sachtouris
158 cdeadadc Stavros Sachtouris
def pretty_keys(d, delim='_', recursive=False):
159 cdeadadc Stavros Sachtouris
    """<term>delim<term> to <term> <term> transformation"""
160 cdeadadc Stavros Sachtouris
    new_d = dict(d)
161 cdeadadc Stavros Sachtouris
    for k, v in d.items():
162 cdeadadc Stavros Sachtouris
        new_v = new_d.pop(k)
163 cdeadadc Stavros Sachtouris
        new_d[k.replace(delim, ' ').strip()] = pretty_keys(
164 cdeadadc Stavros Sachtouris
            new_v, delim, True) if (
165 cdeadadc Stavros Sachtouris
                recursive and isinstance(v, dict)) else new_v
166 7493ccb6 Stavros Sachtouris
    return new_d
167 7493ccb6 Stavros Sachtouris
168 fd5db045 Stavros Sachtouris
169 8df239df Stavros Sachtouris
def print_json(data, out=stdout, encoding=pref_enc):
170 0399ac7e Stavros Sachtouris
    """Print a list or dict as json in console
171 0399ac7e Stavros Sachtouris

172 0399ac7e Stavros Sachtouris
    :param data: json-dumpable data
173 0399ac7e Stavros Sachtouris

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

190 f55d3a15 Stavros Sachtouris
    :param d: (dict)
191 f8681ec8 Stavros Sachtouris

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

194 f55d3a15 Stavros Sachtouris
    :param indent: (int) initial indentation (recursive)
195 f8681ec8 Stavros Sachtouris

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

198 f55d3a15 Stavros Sachtouris
    :param recursive_enumeration: (bool) recursively enumerate iterables (does
199 f55d3a15 Stavros Sachtouris
        not enumerate 1st level keys)
200 f8681ec8 Stavros Sachtouris

201 fa9c0c38 Stavros Sachtouris
    :param out: Input/Output stream to dump values into
202 fa9c0c38 Stavros Sachtouris

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

239 f55d3a15 Stavros Sachtouris
    :param l: (list)
240 f8681ec8 Stavros Sachtouris

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

243 f55d3a15 Stavros Sachtouris
    :param indent: (int) initial indentation (recursive)
244 f8681ec8 Stavros Sachtouris

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

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

250 fa9c0c38 Stavros Sachtouris
    :param out: Input/Output stream to dump values into
251 fa9c0c38 Stavros Sachtouris

252 f55d3a15 Stavros Sachtouris
    :raises CLIError: if preconditions fail
253 f8681ec8 Stavros Sachtouris
    """
254 f55d3a15 Stavros Sachtouris
    assert isinstance(l, list) or isinstance(l, tuple), (
255 f55d3a15 Stavros Sachtouris
        'print_list prinbts a list or tuple')
256 f55d3a15 Stavros Sachtouris
    assert indent >= 0, 'print_list indent must be >= 0'
257 f551841a Stavros Sachtouris
258 f55d3a15 Stavros Sachtouris
    for i, item in enumerate(l):
259 1e92e97d Stavros Sachtouris
        print_str = ' ' * indent
260 1e92e97d Stavros Sachtouris
        print_str += '%s.' % (i + 1) if with_enumeration else ''
261 7493ccb6 Stavros Sachtouris
        if isinstance(item, dict):
262 c17b8bc0 Stavros Sachtouris
            if with_enumeration:
263 8df239df Stavros Sachtouris
                out.write(encode_for_console(print_str) + '\n')
264 0f383dcc Stavros Sachtouris
            elif i and i < len(l):
265 1e92e97d Stavros Sachtouris
                out.write('\n')
266 de73876b Stavros Sachtouris
            print_dict(
267 a0608786 Stavros Sachtouris
                item, exclude,
268 a0608786 Stavros Sachtouris
                indent + (INDENT_TAB if with_enumeration else 0),
269 fa9c0c38 Stavros Sachtouris
                recursive_enumeration, recursive_enumeration, out)
270 f55d3a15 Stavros Sachtouris
        elif isinstance(item, list) or isinstance(item, tuple):
271 c17b8bc0 Stavros Sachtouris
            if with_enumeration:
272 8df239df Stavros Sachtouris
                out.write(encode_for_console(print_str) + '\n')
273 0f383dcc Stavros Sachtouris
            elif i and i < len(l):
274 1e92e97d Stavros Sachtouris
                out.write('\n')
275 de73876b Stavros Sachtouris
            print_list(
276 a0608786 Stavros Sachtouris
                item, exclude, indent + INDENT_TAB,
277 fa9c0c38 Stavros Sachtouris
                recursive_enumeration, recursive_enumeration, out)
278 7493ccb6 Stavros Sachtouris
        else:
279 f55d3a15 Stavros Sachtouris
            item = ('%s' % item).strip()
280 f55d3a15 Stavros Sachtouris
            if item in exclude:
281 f55d3a15 Stavros Sachtouris
                continue
282 8df239df Stavros Sachtouris
            out.write(encode_for_console('%s%s\n' % (print_str, item)))
283 6acfcec4 Stavros Sachtouris
        out.flush()
284 6acfcec4 Stavros Sachtouris
    out.flush()
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 8df239df Stavros Sachtouris
        out.write(encode_for_console('%s\n' % items))
308 6acfcec4 Stavros Sachtouris
        out.flush()
309 31618e2a Stavros Sachtouris
        return
310 31618e2a Stavros Sachtouris
311 54d800e8 Stavros Sachtouris
    for i, item in enumerate(items):
312 a494a741 Stavros Sachtouris
        if with_enumeration:
313 8df239df Stavros Sachtouris
            out.write(encode_for_console('%s. ' % (i + 1)))
314 7493ccb6 Stavros Sachtouris
        if isinstance(item, dict):
315 46d130c9 Stavros Sachtouris
            item = dict(item)
316 46d130c9 Stavros Sachtouris
            title = sorted(set(title).intersection(item))
317 46d130c9 Stavros Sachtouris
            pick = item.get if with_redundancy else item.pop
318 1e92e97d Stavros Sachtouris
            header = ' '.join('%s' % pick(key) for key in title)
319 8df239df Stavros Sachtouris
            out.write(encode_for_console(
320 8df239df Stavros Sachtouris
                (unicode(bold(header) if header else '') + '\n')))
321 fa9c0c38 Stavros Sachtouris
            print_dict(item, indent=INDENT_TAB, out=out)
322 46d130c9 Stavros Sachtouris
        elif isinstance(item, list) or isinstance(item, tuple):
323 fa9c0c38 Stavros Sachtouris
            print_list(item, indent=INDENT_TAB, out=out)
324 a494a741 Stavros Sachtouris
        else:
325 8df239df Stavros Sachtouris
            out.write(encode_for_console(' %s\n' % item))
326 6acfcec4 Stavros Sachtouris
        out.flush()
327 6acfcec4 Stavros Sachtouris
    out.flush()
328 7493ccb6 Stavros Sachtouris
329 fd5db045 Stavros Sachtouris
330 23963422 Stavros Sachtouris
def format_size(size, decimal_factors=False):
331 23963422 Stavros Sachtouris
    units = ('B', 'KB', 'MB', 'GB', 'TB') if decimal_factors else (
332 23963422 Stavros Sachtouris
        'B', 'KiB', 'MiB', 'GiB', 'TiB')
333 23963422 Stavros Sachtouris
    step = 1000 if decimal_factors else 1024
334 23963422 Stavros Sachtouris
    fstep = float(step)
335 7493ccb6 Stavros Sachtouris
    try:
336 7493ccb6 Stavros Sachtouris
        size = float(size)
337 23963422 Stavros Sachtouris
    except (ValueError, TypeError) as err:
338 23963422 Stavros Sachtouris
        raiseCLIError(err, 'Cannot format %s in bytes' % (
339 23963422 Stavros Sachtouris
            ','.join(size) if isinstance(size, tuple) else size))
340 23963422 Stavros Sachtouris
    for i, unit in enumerate(units):
341 23963422 Stavros Sachtouris
        if size < step or i + 1 == len(units):
342 7493ccb6 Stavros Sachtouris
            break
343 23963422 Stavros Sachtouris
        size /= fstep
344 001200c3 Stavros Sachtouris
    s = ('%.2f' % size)
345 23963422 Stavros Sachtouris
    s = s.replace('%s' % step, '%s.99' % (step - 1)) if size <= fstep else s
346 001200c3 Stavros Sachtouris
    while '.' in s and s[-1] in ('0', '.'):
347 001200c3 Stavros Sachtouris
        s = s[:-1]
348 7493ccb6 Stavros Sachtouris
    return s + unit
349 7493ccb6 Stavros Sachtouris
350 fd5db045 Stavros Sachtouris
351 001200c3 Stavros Sachtouris
def to_bytes(size, format):
352 001200c3 Stavros Sachtouris
    """
353 001200c3 Stavros Sachtouris
    :param size: (float) the size in the given format
354 001200c3 Stavros Sachtouris
    :param format: (case insensitive) KiB, KB, MiB, MB, GiB, GB, TiB, TB
355 001200c3 Stavros Sachtouris

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

444 001200c3 Stavros Sachtouris
    :param true_resp: (tuple of chars)
445 7147e1ca Stavros Sachtouris

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

480 1716a15d Stavros Sachtouris
    :param filters: (dict) filters in key-value form
481 1716a15d Stavros Sachtouris

482 1716a15d Stavros Sachtouris
    :param exact_match: (bool) if false, check if the filter value is part of
483 1716a15d Stavros Sachtouris
        the actual value
484 1716a15d Stavros Sachtouris

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

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