2 # vim: ai ts=4 sts=4 et sw=4
4 # Copyright (c) 2009, 2010, 2011 Intel, Inc.
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the Free
8 # Software Foundation; version 2 of the License
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc., 59
17 # Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 __ALL__ = ['set_mode',
38 INFO_COLOR = 32 # green
39 WARN_COLOR = 33 # yellow
44 HOST_TIMEZONE = time.timezone
46 PREFIX_RE = re.compile('^<(.*?)>\s*(.*)', re.S)
61 CATCHERR_BUFFILE_FD = -1
62 CATCHERR_BUFFILE_PATH = None
65 def _general_print(head, color, msg = None, stream = None, level = 'normal'):
70 if LOG_LEVELS[level] > LOG_LEVEL:
74 # encode raw 'unicode' str to utf8 encoded str
75 if msg and isinstance(msg, unicode):
76 msg = msg.encode('utf-8', 'ignore')
79 if CATCHERR_BUFFILE_FD > 0:
80 size = os.lseek(CATCHERR_BUFFILE_FD , 0, os.SEEK_END)
81 os.lseek(CATCHERR_BUFFILE_FD, 0, os.SEEK_SET)
82 errormsg = os.read(CATCHERR_BUFFILE_FD, size)
83 os.ftruncate(CATCHERR_BUFFILE_FD, 0)
85 # append error msg to LOG
87 LOG_CONTENT += errormsg
89 # append normal msg to LOG
90 save_msg = msg.strip() if msg else None
93 timestr = time.strftime("[%m/%d %H:%M:%S] ",
94 time.gmtime(time.time() - HOST_TIMEZONE))
95 LOG_CONTENT += timestr + save_msg + '\n'
98 _color_print('', NO_COLOR, errormsg, stream, level)
100 _color_print(head, color, msg, stream, level)
102 def _color_print(head, color, msg, stream, level):
104 if color == NO_COLOR or \
105 not stream.isatty() or \
106 os.getenv('ANSI_COLORS_DISABLED') is not None:
109 if head.startswith('\r'):
110 # need not \n at last
116 head = '\033[%dm%s:\033[0m ' %(color, head)
118 # ESC cmd to clear line
119 head = '\033[2K' + head
123 if head.startswith('\r'):
128 if isinstance(msg, unicode):
129 msg = msg.encode('utf8', 'ignore')
131 stream.write('%s%s' % (head, msg))
137 def _color_perror(head, color, msg, level = 'normal'):
138 if CATCHERR_BUFFILE_FD > 0:
139 _general_print(head, color, msg, sys.stdout, level)
141 _general_print(head, color, msg, sys.stderr, level)
143 def _split_msg(head, msg):
144 if isinstance(msg, list):
145 msg = '\n'.join(map(str, msg))
147 if msg.startswith('\n'):
148 # means print \n at first
152 elif msg.startswith('\r'):
153 # means print \r at first
157 m = PREFIX_RE.match(msg)
159 head += ' <%s>' % m.group(1)
165 return (k for k,v in LOG_LEVELS.items() if v==LOG_LEVEL).next()
167 def set_loglevel(level):
169 if level not in LOG_LEVELS:
173 LOG_LEVEL = LOG_LEVELS[level]
175 def set_interactive(mode=True):
183 # log msg to LOG_CONTENT then save to logfile
189 _general_print('', NO_COLOR, msg)
192 head, msg = _split_msg('Info', msg)
193 _general_print(head, INFO_COLOR, msg)
196 head, msg = _split_msg('Verbose', msg)
197 _general_print(head, INFO_COLOR, msg, level = 'verbose')
200 head, msg = _split_msg('Warning', msg)
201 _color_perror(head, WARN_COLOR, msg)
204 head, msg = _split_msg('Debug', msg)
205 _color_perror(head, ERR_COLOR, msg, level = 'debug')
208 head, msg = _split_msg('Error', msg)
209 _color_perror(head, ERR_COLOR, msg)
212 def ask(msg, default=True):
213 _general_print('\rQ', ASK_COLOR, '')
221 repl = raw_input(msg)
222 if repl.lower() == 'y':
224 elif repl.lower() == 'n':
226 elif not repl.strip():
236 _general_print('', NO_COLOR, msg)
239 except KeyboardInterrupt:
240 sys.stdout.write('\n')
243 def choice(msg, choices, default=0):
244 if default >= len(choices):
246 _general_print('\rQ', ASK_COLOR, '')
248 msg += " [%s] " % '/'.join(choices)
251 repl = raw_input(msg)
254 elif not repl.strip():
255 return choices[default]
257 msg += choices[default]
258 _general_print('', NO_COLOR, msg)
260 return choices[default]
261 except KeyboardInterrupt:
262 sys.stdout.write('\n')
267 _general_print('\rQ', ASK_COLOR, '')
269 msg = 'press <ENTER> to continue ...'
272 def set_logfile(fpath):
277 fp = open(LOG_FILE_FP, 'w')
278 fp.write(LOG_CONTENT)
281 if LOG_FILE_FP is not None:
282 warning('duplicate log file configuration')
287 atexit.register(_savelogf)
289 def enable_logstderr(fpath):
290 global CATCHERR_BUFFILE_FD
291 global CATCHERR_BUFFILE_PATH
292 global CATCHERR_SAVED_2
294 if os.path.exists(fpath):
296 CATCHERR_BUFFILE_PATH = fpath
297 CATCHERR_BUFFILE_FD = os.open(CATCHERR_BUFFILE_PATH, os.O_RDWR|os.O_CREAT)
298 CATCHERR_SAVED_2 = os.dup(2)
299 os.dup2(CATCHERR_BUFFILE_FD, 2)
301 def disable_logstderr():
302 global CATCHERR_BUFFILE_FD
303 global CATCHERR_BUFFILE_PATH
304 global CATCHERR_SAVED_2
306 raw(msg = None) # flush message buffer and print it.
307 os.dup2(CATCHERR_SAVED_2, 2)
308 os.close(CATCHERR_SAVED_2)
309 os.close(CATCHERR_BUFFILE_FD)
310 os.unlink(CATCHERR_BUFFILE_PATH)
311 CATCHERR_BUFFILE_FD = -1
312 CATCHERR_BUFFILE_PATH = None
313 CATCHERR_SAVED_2 = -1