diff options
Diffstat (limited to 'scripts/lib/wic/msger.py')
-rw-r--r-- | scripts/lib/wic/msger.py | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/scripts/lib/wic/msger.py b/scripts/lib/wic/msger.py new file mode 100644 index 0000000000..9afc85be93 --- /dev/null +++ b/scripts/lib/wic/msger.py | |||
@@ -0,0 +1,309 @@ | |||
1 | #!/usr/bin/python -tt | ||
2 | # vim: ai ts=4 sts=4 et sw=4 | ||
3 | # | ||
4 | # Copyright (c) 2009, 2010, 2011 Intel, Inc. | ||
5 | # | ||
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 | ||
9 | # | ||
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 | ||
13 | # for more details. | ||
14 | # | ||
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. | ||
18 | |||
19 | import os,sys | ||
20 | import re | ||
21 | import time | ||
22 | |||
23 | __ALL__ = ['set_mode', | ||
24 | 'get_loglevel', | ||
25 | 'set_loglevel', | ||
26 | 'set_logfile', | ||
27 | 'raw', | ||
28 | 'debug', | ||
29 | 'verbose', | ||
30 | 'info', | ||
31 | 'warning', | ||
32 | 'error', | ||
33 | 'ask', | ||
34 | 'pause', | ||
35 | ] | ||
36 | |||
37 | # COLORs in ANSI | ||
38 | INFO_COLOR = 32 # green | ||
39 | WARN_COLOR = 33 # yellow | ||
40 | ERR_COLOR = 31 # red | ||
41 | ASK_COLOR = 34 # blue | ||
42 | NO_COLOR = 0 | ||
43 | |||
44 | PREFIX_RE = re.compile('^<(.*?)>\s*(.*)', re.S) | ||
45 | |||
46 | INTERACTIVE = True | ||
47 | |||
48 | LOG_LEVEL = 1 | ||
49 | LOG_LEVELS = { | ||
50 | 'quiet': 0, | ||
51 | 'normal': 1, | ||
52 | 'verbose': 2, | ||
53 | 'debug': 3, | ||
54 | 'never': 4, | ||
55 | } | ||
56 | |||
57 | LOG_FILE_FP = None | ||
58 | LOG_CONTENT = '' | ||
59 | CATCHERR_BUFFILE_FD = -1 | ||
60 | CATCHERR_BUFFILE_PATH = None | ||
61 | CATCHERR_SAVED_2 = -1 | ||
62 | |||
63 | def _general_print(head, color, msg = None, stream = None, level = 'normal'): | ||
64 | global LOG_CONTENT | ||
65 | if not stream: | ||
66 | stream = sys.stdout | ||
67 | |||
68 | if LOG_LEVELS[level] > LOG_LEVEL: | ||
69 | # skip | ||
70 | return | ||
71 | |||
72 | # encode raw 'unicode' str to utf8 encoded str | ||
73 | if msg and isinstance(msg, unicode): | ||
74 | msg = msg.encode('utf-8', 'ignore') | ||
75 | |||
76 | errormsg = '' | ||
77 | if CATCHERR_BUFFILE_FD > 0: | ||
78 | size = os.lseek(CATCHERR_BUFFILE_FD , 0, os.SEEK_END) | ||
79 | os.lseek(CATCHERR_BUFFILE_FD, 0, os.SEEK_SET) | ||
80 | errormsg = os.read(CATCHERR_BUFFILE_FD, size) | ||
81 | os.ftruncate(CATCHERR_BUFFILE_FD, 0) | ||
82 | |||
83 | # append error msg to LOG | ||
84 | if errormsg: | ||
85 | LOG_CONTENT += errormsg | ||
86 | |||
87 | # append normal msg to LOG | ||
88 | save_msg = msg.strip() if msg else None | ||
89 | if save_msg: | ||
90 | timestr = time.strftime("[%m/%d %H:%M:%S %Z] ", time.localtime()) | ||
91 | LOG_CONTENT += timestr + save_msg + '\n' | ||
92 | |||
93 | if errormsg: | ||
94 | _color_print('', NO_COLOR, errormsg, stream, level) | ||
95 | |||
96 | _color_print(head, color, msg, stream, level) | ||
97 | |||
98 | def _color_print(head, color, msg, stream, level): | ||
99 | colored = True | ||
100 | if color == NO_COLOR or \ | ||
101 | not stream.isatty() or \ | ||
102 | os.getenv('ANSI_COLORS_DISABLED') is not None: | ||
103 | colored = False | ||
104 | |||
105 | if head.startswith('\r'): | ||
106 | # need not \n at last | ||
107 | newline = False | ||
108 | else: | ||
109 | newline = True | ||
110 | |||
111 | if colored: | ||
112 | head = '\033[%dm%s:\033[0m ' %(color, head) | ||
113 | if not newline: | ||
114 | # ESC cmd to clear line | ||
115 | head = '\033[2K' + head | ||
116 | else: | ||
117 | if head: | ||
118 | head += ': ' | ||
119 | if head.startswith('\r'): | ||
120 | head = head.lstrip() | ||
121 | newline = True | ||
122 | |||
123 | if msg is not None: | ||
124 | if isinstance(msg, unicode): | ||
125 | msg = msg.encode('utf8', 'ignore') | ||
126 | |||
127 | stream.write('%s%s' % (head, msg)) | ||
128 | if newline: | ||
129 | stream.write('\n') | ||
130 | |||
131 | stream.flush() | ||
132 | |||
133 | def _color_perror(head, color, msg, level = 'normal'): | ||
134 | if CATCHERR_BUFFILE_FD > 0: | ||
135 | _general_print(head, color, msg, sys.stdout, level) | ||
136 | else: | ||
137 | _general_print(head, color, msg, sys.stderr, level) | ||
138 | |||
139 | def _split_msg(head, msg): | ||
140 | if isinstance(msg, list): | ||
141 | msg = '\n'.join(map(str, msg)) | ||
142 | |||
143 | if msg.startswith('\n'): | ||
144 | # means print \n at first | ||
145 | msg = msg.lstrip() | ||
146 | head = '\n' + head | ||
147 | |||
148 | elif msg.startswith('\r'): | ||
149 | # means print \r at first | ||
150 | msg = msg.lstrip() | ||
151 | head = '\r' + head | ||
152 | |||
153 | m = PREFIX_RE.match(msg) | ||
154 | if m: | ||
155 | head += ' <%s>' % m.group(1) | ||
156 | msg = m.group(2) | ||
157 | |||
158 | return head, msg | ||
159 | |||
160 | def get_loglevel(): | ||
161 | return (k for k,v in LOG_LEVELS.items() if v==LOG_LEVEL).next() | ||
162 | |||
163 | def set_loglevel(level): | ||
164 | global LOG_LEVEL | ||
165 | if level not in LOG_LEVELS: | ||
166 | # no effect | ||
167 | return | ||
168 | |||
169 | LOG_LEVEL = LOG_LEVELS[level] | ||
170 | |||
171 | def set_interactive(mode=True): | ||
172 | global INTERACTIVE | ||
173 | if mode: | ||
174 | INTERACTIVE = True | ||
175 | else: | ||
176 | INTERACTIVE = False | ||
177 | |||
178 | def log(msg=''): | ||
179 | # log msg to LOG_CONTENT then save to logfile | ||
180 | global LOG_CONTENT | ||
181 | if msg: | ||
182 | LOG_CONTENT += msg | ||
183 | |||
184 | def raw(msg=''): | ||
185 | _general_print('', NO_COLOR, msg) | ||
186 | |||
187 | def info(msg): | ||
188 | head, msg = _split_msg('Info', msg) | ||
189 | _general_print(head, INFO_COLOR, msg) | ||
190 | |||
191 | def verbose(msg): | ||
192 | head, msg = _split_msg('Verbose', msg) | ||
193 | _general_print(head, INFO_COLOR, msg, level = 'verbose') | ||
194 | |||
195 | def warning(msg): | ||
196 | head, msg = _split_msg('Warning', msg) | ||
197 | _color_perror(head, WARN_COLOR, msg) | ||
198 | |||
199 | def debug(msg): | ||
200 | head, msg = _split_msg('Debug', msg) | ||
201 | _color_perror(head, ERR_COLOR, msg, level = 'debug') | ||
202 | |||
203 | def error(msg): | ||
204 | head, msg = _split_msg('Error', msg) | ||
205 | _color_perror(head, ERR_COLOR, msg) | ||
206 | sys.exit(1) | ||
207 | |||
208 | def ask(msg, default=True): | ||
209 | _general_print('\rQ', ASK_COLOR, '') | ||
210 | try: | ||
211 | if default: | ||
212 | msg += '(Y/n) ' | ||
213 | else: | ||
214 | msg += '(y/N) ' | ||
215 | if INTERACTIVE: | ||
216 | while True: | ||
217 | repl = raw_input(msg) | ||
218 | if repl.lower() == 'y': | ||
219 | return True | ||
220 | elif repl.lower() == 'n': | ||
221 | return False | ||
222 | elif not repl.strip(): | ||
223 | # <Enter> | ||
224 | return default | ||
225 | |||
226 | # else loop | ||
227 | else: | ||
228 | if default: | ||
229 | msg += ' Y' | ||
230 | else: | ||
231 | msg += ' N' | ||
232 | _general_print('', NO_COLOR, msg) | ||
233 | |||
234 | return default | ||
235 | except KeyboardInterrupt: | ||
236 | sys.stdout.write('\n') | ||
237 | sys.exit(2) | ||
238 | |||
239 | def choice(msg, choices, default=0): | ||
240 | if default >= len(choices): | ||
241 | return None | ||
242 | _general_print('\rQ', ASK_COLOR, '') | ||
243 | try: | ||
244 | msg += " [%s] " % '/'.join(choices) | ||
245 | if INTERACTIVE: | ||
246 | while True: | ||
247 | repl = raw_input(msg) | ||
248 | if repl in choices: | ||
249 | return repl | ||
250 | elif not repl.strip(): | ||
251 | return choices[default] | ||
252 | else: | ||
253 | msg += choices[default] | ||
254 | _general_print('', NO_COLOR, msg) | ||
255 | |||
256 | return choices[default] | ||
257 | except KeyboardInterrupt: | ||
258 | sys.stdout.write('\n') | ||
259 | sys.exit(2) | ||
260 | |||
261 | def pause(msg=None): | ||
262 | if INTERACTIVE: | ||
263 | _general_print('\rQ', ASK_COLOR, '') | ||
264 | if msg is None: | ||
265 | msg = 'press <ENTER> to continue ...' | ||
266 | raw_input(msg) | ||
267 | |||
268 | def set_logfile(fpath): | ||
269 | global LOG_FILE_FP | ||
270 | |||
271 | def _savelogf(): | ||
272 | if LOG_FILE_FP: | ||
273 | fp = open(LOG_FILE_FP, 'w') | ||
274 | fp.write(LOG_CONTENT) | ||
275 | fp.close() | ||
276 | |||
277 | if LOG_FILE_FP is not None: | ||
278 | warning('duplicate log file configuration') | ||
279 | |||
280 | LOG_FILE_FP = fpath | ||
281 | |||
282 | import atexit | ||
283 | atexit.register(_savelogf) | ||
284 | |||
285 | def enable_logstderr(fpath): | ||
286 | global CATCHERR_BUFFILE_FD | ||
287 | global CATCHERR_BUFFILE_PATH | ||
288 | global CATCHERR_SAVED_2 | ||
289 | |||
290 | if os.path.exists(fpath): | ||
291 | os.remove(fpath) | ||
292 | CATCHERR_BUFFILE_PATH = fpath | ||
293 | CATCHERR_BUFFILE_FD = os.open(CATCHERR_BUFFILE_PATH, os.O_RDWR|os.O_CREAT) | ||
294 | CATCHERR_SAVED_2 = os.dup(2) | ||
295 | os.dup2(CATCHERR_BUFFILE_FD, 2) | ||
296 | |||
297 | def disable_logstderr(): | ||
298 | global CATCHERR_BUFFILE_FD | ||
299 | global CATCHERR_BUFFILE_PATH | ||
300 | global CATCHERR_SAVED_2 | ||
301 | |||
302 | raw(msg = None) # flush message buffer and print it. | ||
303 | os.dup2(CATCHERR_SAVED_2, 2) | ||
304 | os.close(CATCHERR_SAVED_2) | ||
305 | os.close(CATCHERR_BUFFILE_FD) | ||
306 | os.unlink(CATCHERR_BUFFILE_PATH) | ||
307 | CATCHERR_BUFFILE_FD = -1 | ||
308 | CATCHERR_BUFFILE_PATH = None | ||
309 | CATCHERR_SAVED_2 = -1 | ||