]> git.proxmox.com Git - ceph.git/blame - ceph/src/ceph-volume/ceph_volume/terminal.py
buildsys: auto-determine current version for makefile
[ceph.git] / ceph / src / ceph-volume / ceph_volume / terminal.py
CommitLineData
b32b8144 1import logging
d2e6a577
FG
2import sys
3
4
494da23a
TL
5terminal_logger = logging.getLogger('terminal')
6
7
d2e6a577
FG
8class colorize(str):
9 """
10 Pretty simple to use::
11
12 colorize.make('foo').bold
13 colorize.make('foo').green
14 colorize.make('foo').yellow
15 colorize.make('foo').red
16 colorize.make('foo').blue
17
18 Otherwise you could go the long way (for example if you are
19 testing this class)::
20
21 string = colorize('foo')
22 string._set_attributes()
23 string.red
24
25 """
26
27 def __init__(self, string):
d2e6a577
FG
28 self.appends = ''
29 self.prepends = ''
494da23a 30 self.isatty = sys.__stderr__.isatty()
d2e6a577
FG
31
32 def _set_attributes(self):
33 """
34 Sets the attributes here because the str class does not
35 allow to pass in anything other than a string to the constructor
36 so we can't really mess with the other attributes.
37 """
38 for k, v in self.__colors__.items():
39 setattr(self, k, self.make_color(v))
40
41 def make_color(self, color):
42 if not self.isatty:
43 return self
44 return color + self + '\033[0m' + self.appends
45
46 @property
47 def __colors__(self):
48 return dict(
49 blue='\033[34m',
50 green='\033[92m',
51 yellow='\033[33m',
52 red='\033[91m',
53 bold='\033[1m',
54 ends='\033[0m'
55 )
56
57 @classmethod
58 def make(cls, string):
59 """
60 A helper method to return itself and workaround the fact that
61 the str object doesn't allow extra arguments passed in to the
62 constructor
63 """
64 obj = cls(string)
65 obj._set_attributes()
66 return obj
67
68#
69# Common string manipulations
70#
71yellow = lambda x: colorize.make(x).yellow # noqa
72blue = lambda x: colorize.make(x).blue # noqa
73green = lambda x: colorize.make(x).green # noqa
74red = lambda x: colorize.make(x).red # noqa
75bold = lambda x: colorize.make(x).bold # noqa
76red_arrow = red('--> ')
77blue_arrow = blue('--> ')
78green_arrow = green('--> ')
79yellow_arrow = yellow('--> ')
80
81
82class _Write(object):
83
84 def __init__(self, _writer=None, prefix='', suffix='', flush=False):
494da23a
TL
85 # we can't set sys.stderr as the default for _writer. otherwise
86 # pytest's capturing gets confused
87 self._writer = _writer or sys.stderr
d2e6a577
FG
88 self.suffix = suffix
89 self.prefix = prefix
90 self.flush = flush
91
92 def bold(self, string):
93 self.write(bold(string))
94
95 def raw(self, string):
96 if not string.endswith('\n'):
97 string = '%s\n' % string
98 self.write(string)
99
100 def write(self, line):
494da23a
TL
101 entry = self.prefix + line + self.suffix
102
103 try:
104 self._writer.write(entry)
105 if self.flush:
106 self._writer.flush()
107 except (UnicodeDecodeError, UnicodeEncodeError):
108 try:
109 terminal_logger.info(entry.strip('\n'))
110 except (AttributeError, TypeError):
111 terminal_logger.info(entry)
d2e6a577
FG
112
113
114def stdout(msg):
115 return _Write(prefix=blue(' stdout: ')).raw(msg)
116
117
118def stderr(msg):
119 return _Write(prefix=yellow(' stderr: ')).raw(msg)
120
121
122def write(msg):
123 return _Write().raw(msg)
124
125
126def error(msg):
127 return _Write(prefix=red_arrow).raw(msg)
128
129
b32b8144
FG
130def info(msg):
131 return _Write(prefix=blue_arrow).raw(msg)
132
133
134def debug(msg):
135 return _Write(prefix=blue_arrow).raw(msg)
136
137
d2e6a577
FG
138def warning(msg):
139 return _Write(prefix=yellow_arrow).raw(msg)
140
141
142def success(msg):
143 return _Write(prefix=green_arrow).raw(msg)
144
145
b32b8144
FG
146class MultiLogger(object):
147 """
148 Proxy class to be able to report on both logger instances and terminal
149 messages avoiding the issue of having to call them both separately
150
151 Initialize it in the same way a logger object::
152
153 logger = terminal.MultiLogger(__name__)
154 """
155
156 def __init__(self, name):
157 self.logger = logging.getLogger(name)
158
159 def _make_record(self, msg, *args):
160 if len(str(args)):
161 try:
162 return msg % args
163 except TypeError:
164 self.logger.exception('unable to produce log record: %s' % msg)
165 return msg
166
167 def warning(self, msg, *args):
168 record = self._make_record(msg, *args)
169 warning(record)
170 self.logger.warning(record)
171
172 def debug(self, msg, *args):
173 record = self._make_record(msg, *args)
174 debug(record)
175 self.logger.debug(record)
176
177 def info(self, msg, *args):
178 record = self._make_record(msg, *args)
179 info(record)
180 self.logger.info(record)
181
182 def error(self, msg, *args):
183 record = self._make_record(msg, *args)
184 error(record)
185 self.logger.error(record)
186
187
d2e6a577
FG
188def dispatch(mapper, argv=None):
189 argv = argv or sys.argv
190 for count, arg in enumerate(argv, 1):
191 if arg in mapper.keys():
192 instance = mapper.get(arg)(argv[count:])
193 if hasattr(instance, 'main'):
194 instance.main()
195 raise SystemExit(0)
196
197
198def subhelp(mapper):
199 """
200 Look at every value of every key in the mapper and will output any
201 ``class.help`` possible to return it as a string that will be sent to
494da23a 202 stderr.
d2e6a577
FG
203 """
204 help_text_lines = []
205 for key, value in mapper.items():
206 try:
207 help_text = value.help
208 except AttributeError:
209 continue
210 help_text_lines.append("%-24s %s" % (key, help_text))
211
212 if help_text_lines:
213 return "Available subcommands:\n\n%s" % '\n'.join(help_text_lines)
214 return ''