1 |
Author: zmedico |
2 |
Date: 2009-06-22 18:21:56 +0000 (Mon, 22 Jun 2009) |
3 |
New Revision: 13667 |
4 |
|
5 |
Added: |
6 |
main/trunk/pym/_emerge/JobStatusDisplay.py |
7 |
main/trunk/pym/_emerge/UninstallFailure.py |
8 |
main/trunk/pym/_emerge/getloadavg.py |
9 |
main/trunk/pym/_emerge/stdout_spinner.py |
10 |
Modified: |
11 |
main/trunk/pym/_emerge/__init__.py |
12 |
Log: |
13 |
Bug #275047 - Split _emerge/__init__.py into smaller pieces (part 2). |
14 |
Thanks to Sebastian Mingramm (few) <s.mingramm@×××.de> for this patch. |
15 |
|
16 |
|
17 |
Added: main/trunk/pym/_emerge/JobStatusDisplay.py |
18 |
=================================================================== |
19 |
--- main/trunk/pym/_emerge/JobStatusDisplay.py (rev 0) |
20 |
+++ main/trunk/pym/_emerge/JobStatusDisplay.py 2009-06-22 18:21:56 UTC (rev 13667) |
21 |
@@ -0,0 +1,267 @@ |
22 |
+import formatter |
23 |
+import os |
24 |
+import sys |
25 |
+import time |
26 |
+ |
27 |
+try: |
28 |
+ from cStringIO import StringIO |
29 |
+except ImportError: |
30 |
+ from StringIO import StringIO |
31 |
+ |
32 |
+try: |
33 |
+ import portage |
34 |
+except ImportError: |
35 |
+ from os import path as osp |
36 |
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) |
37 |
+ import portage |
38 |
+ |
39 |
+from portage.output import xtermTitle |
40 |
+ |
41 |
+from _emerge.getloadavg import getloadavg |
42 |
+ |
43 |
+class JobStatusDisplay(object): |
44 |
+ |
45 |
+ _bound_properties = ("curval", "failed", "running") |
46 |
+ _jobs_column_width = 48 |
47 |
+ |
48 |
+ # Don't update the display unless at least this much |
49 |
+ # time has passed, in units of seconds. |
50 |
+ _min_display_latency = 2 |
51 |
+ |
52 |
+ _default_term_codes = { |
53 |
+ 'cr' : '\r', |
54 |
+ 'el' : '\x1b[K', |
55 |
+ 'nel' : '\n', |
56 |
+ } |
57 |
+ |
58 |
+ _termcap_name_map = { |
59 |
+ 'carriage_return' : 'cr', |
60 |
+ 'clr_eol' : 'el', |
61 |
+ 'newline' : 'nel', |
62 |
+ } |
63 |
+ |
64 |
+ def __init__(self, out=sys.stdout, quiet=False, xterm_titles=True): |
65 |
+ object.__setattr__(self, "out", out) |
66 |
+ object.__setattr__(self, "quiet", quiet) |
67 |
+ object.__setattr__(self, "xterm_titles", xterm_titles) |
68 |
+ object.__setattr__(self, "maxval", 0) |
69 |
+ object.__setattr__(self, "merges", 0) |
70 |
+ object.__setattr__(self, "_changed", False) |
71 |
+ object.__setattr__(self, "_displayed", False) |
72 |
+ object.__setattr__(self, "_last_display_time", 0) |
73 |
+ object.__setattr__(self, "width", 80) |
74 |
+ self.reset() |
75 |
+ |
76 |
+ isatty = hasattr(out, "isatty") and out.isatty() |
77 |
+ object.__setattr__(self, "_isatty", isatty) |
78 |
+ if not isatty or not self._init_term(): |
79 |
+ term_codes = {} |
80 |
+ for k, capname in self._termcap_name_map.iteritems(): |
81 |
+ term_codes[k] = self._default_term_codes[capname] |
82 |
+ object.__setattr__(self, "_term_codes", term_codes) |
83 |
+ encoding = sys.getdefaultencoding() |
84 |
+ for k, v in self._term_codes.items(): |
85 |
+ if not isinstance(v, basestring): |
86 |
+ self._term_codes[k] = v.decode(encoding, 'replace') |
87 |
+ |
88 |
+ def _init_term(self): |
89 |
+ """ |
90 |
+ Initialize term control codes. |
91 |
+ @rtype: bool |
92 |
+ @returns: True if term codes were successfully initialized, |
93 |
+ False otherwise. |
94 |
+ """ |
95 |
+ |
96 |
+ term_type = os.environ.get("TERM", "vt100") |
97 |
+ tigetstr = None |
98 |
+ |
99 |
+ try: |
100 |
+ import curses |
101 |
+ try: |
102 |
+ curses.setupterm(term_type, self.out.fileno()) |
103 |
+ tigetstr = curses.tigetstr |
104 |
+ except curses.error: |
105 |
+ pass |
106 |
+ except ImportError: |
107 |
+ pass |
108 |
+ |
109 |
+ if tigetstr is None: |
110 |
+ return False |
111 |
+ |
112 |
+ term_codes = {} |
113 |
+ for k, capname in self._termcap_name_map.iteritems(): |
114 |
+ code = tigetstr(capname) |
115 |
+ if code is None: |
116 |
+ code = self._default_term_codes[capname] |
117 |
+ term_codes[k] = code |
118 |
+ object.__setattr__(self, "_term_codes", term_codes) |
119 |
+ return True |
120 |
+ |
121 |
+ def _format_msg(self, msg): |
122 |
+ return ">>> %s" % msg |
123 |
+ |
124 |
+ def _erase(self): |
125 |
+ self.out.write( |
126 |
+ self._term_codes['carriage_return'] + \ |
127 |
+ self._term_codes['clr_eol']) |
128 |
+ self.out.flush() |
129 |
+ self._displayed = False |
130 |
+ |
131 |
+ def _display(self, line): |
132 |
+ self.out.write(line) |
133 |
+ self.out.flush() |
134 |
+ self._displayed = True |
135 |
+ |
136 |
+ def _update(self, msg): |
137 |
+ |
138 |
+ out = self.out |
139 |
+ if not self._isatty: |
140 |
+ out.write(self._format_msg(msg) + self._term_codes['newline']) |
141 |
+ self.out.flush() |
142 |
+ self._displayed = True |
143 |
+ return |
144 |
+ |
145 |
+ if self._displayed: |
146 |
+ self._erase() |
147 |
+ |
148 |
+ self._display(self._format_msg(msg)) |
149 |
+ |
150 |
+ def displayMessage(self, msg): |
151 |
+ |
152 |
+ was_displayed = self._displayed |
153 |
+ |
154 |
+ if self._isatty and self._displayed: |
155 |
+ self._erase() |
156 |
+ |
157 |
+ self.out.write(self._format_msg(msg) + self._term_codes['newline']) |
158 |
+ self.out.flush() |
159 |
+ self._displayed = False |
160 |
+ |
161 |
+ if was_displayed: |
162 |
+ self._changed = True |
163 |
+ self.display() |
164 |
+ |
165 |
+ def reset(self): |
166 |
+ self.maxval = 0 |
167 |
+ self.merges = 0 |
168 |
+ for name in self._bound_properties: |
169 |
+ object.__setattr__(self, name, 0) |
170 |
+ |
171 |
+ if self._displayed: |
172 |
+ self.out.write(self._term_codes['newline']) |
173 |
+ self.out.flush() |
174 |
+ self._displayed = False |
175 |
+ |
176 |
+ def __setattr__(self, name, value): |
177 |
+ old_value = getattr(self, name) |
178 |
+ if value == old_value: |
179 |
+ return |
180 |
+ object.__setattr__(self, name, value) |
181 |
+ if name in self._bound_properties: |
182 |
+ self._property_change(name, old_value, value) |
183 |
+ |
184 |
+ def _property_change(self, name, old_value, new_value): |
185 |
+ self._changed = True |
186 |
+ self.display() |
187 |
+ |
188 |
+ def _load_avg_str(self): |
189 |
+ try: |
190 |
+ avg = getloadavg() |
191 |
+ except OSError: |
192 |
+ return 'unknown' |
193 |
+ |
194 |
+ max_avg = max(avg) |
195 |
+ |
196 |
+ if max_avg < 10: |
197 |
+ digits = 2 |
198 |
+ elif max_avg < 100: |
199 |
+ digits = 1 |
200 |
+ else: |
201 |
+ digits = 0 |
202 |
+ |
203 |
+ return ", ".join(("%%.%df" % digits ) % x for x in avg) |
204 |
+ |
205 |
+ def display(self): |
206 |
+ """ |
207 |
+ Display status on stdout, but only if something has |
208 |
+ changed since the last call. |
209 |
+ """ |
210 |
+ |
211 |
+ if self.quiet: |
212 |
+ return |
213 |
+ |
214 |
+ current_time = time.time() |
215 |
+ time_delta = current_time - self._last_display_time |
216 |
+ if self._displayed and \ |
217 |
+ not self._changed: |
218 |
+ if not self._isatty: |
219 |
+ return |
220 |
+ if time_delta < self._min_display_latency: |
221 |
+ return |
222 |
+ |
223 |
+ self._last_display_time = current_time |
224 |
+ self._changed = False |
225 |
+ self._display_status() |
226 |
+ |
227 |
+ def _display_status(self): |
228 |
+ # Don't use len(self._completed_tasks) here since that also |
229 |
+ # can include uninstall tasks. |
230 |
+ curval_str = str(self.curval) |
231 |
+ maxval_str = str(self.maxval) |
232 |
+ running_str = str(self.running) |
233 |
+ failed_str = str(self.failed) |
234 |
+ load_avg_str = self._load_avg_str() |
235 |
+ |
236 |
+ color_output = StringIO() |
237 |
+ plain_output = StringIO() |
238 |
+ style_file = portage.output.ConsoleStyleFile(color_output) |
239 |
+ style_file.write_listener = plain_output |
240 |
+ style_writer = portage.output.StyleWriter(file=style_file, maxcol=9999) |
241 |
+ style_writer.style_listener = style_file.new_styles |
242 |
+ f = formatter.AbstractFormatter(style_writer) |
243 |
+ |
244 |
+ number_style = "INFORM" |
245 |
+ f.add_literal_data("Jobs: ") |
246 |
+ f.push_style(number_style) |
247 |
+ f.add_literal_data(curval_str) |
248 |
+ f.pop_style() |
249 |
+ f.add_literal_data(" of ") |
250 |
+ f.push_style(number_style) |
251 |
+ f.add_literal_data(maxval_str) |
252 |
+ f.pop_style() |
253 |
+ f.add_literal_data(" complete") |
254 |
+ |
255 |
+ if self.running: |
256 |
+ f.add_literal_data(", ") |
257 |
+ f.push_style(number_style) |
258 |
+ f.add_literal_data(running_str) |
259 |
+ f.pop_style() |
260 |
+ f.add_literal_data(" running") |
261 |
+ |
262 |
+ if self.failed: |
263 |
+ f.add_literal_data(", ") |
264 |
+ f.push_style(number_style) |
265 |
+ f.add_literal_data(failed_str) |
266 |
+ f.pop_style() |
267 |
+ f.add_literal_data(" failed") |
268 |
+ |
269 |
+ padding = self._jobs_column_width - len(plain_output.getvalue()) |
270 |
+ if padding > 0: |
271 |
+ f.add_literal_data(padding * " ") |
272 |
+ |
273 |
+ f.add_literal_data("Load avg: ") |
274 |
+ f.add_literal_data(load_avg_str) |
275 |
+ |
276 |
+ # Truncate to fit width, to avoid making the terminal scroll if the |
277 |
+ # line overflows (happens when the load average is large). |
278 |
+ plain_output = plain_output.getvalue() |
279 |
+ if self._isatty and len(plain_output) > self.width: |
280 |
+ # Use plain_output here since it's easier to truncate |
281 |
+ # properly than the color output which contains console |
282 |
+ # color codes. |
283 |
+ self._update(plain_output[:self.width]) |
284 |
+ else: |
285 |
+ self._update(color_output.getvalue()) |
286 |
+ |
287 |
+ if self.xterm_titles: |
288 |
+ xtermTitle(" ".join(plain_output.split())) |
289 |
|
290 |
|
291 |
Property changes on: main/trunk/pym/_emerge/JobStatusDisplay.py |
292 |
___________________________________________________________________ |
293 |
Name: svn:keywords |
294 |
+ Id |
295 |
|
296 |
Added: main/trunk/pym/_emerge/UninstallFailure.py |
297 |
=================================================================== |
298 |
--- main/trunk/pym/_emerge/UninstallFailure.py (rev 0) |
299 |
+++ main/trunk/pym/_emerge/UninstallFailure.py 2009-06-22 18:21:56 UTC (rev 13667) |
300 |
@@ -0,0 +1,18 @@ |
301 |
+try: |
302 |
+ import portage |
303 |
+except ImportError: |
304 |
+ from os import path as osp |
305 |
+ import sys |
306 |
+ sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) |
307 |
+ import portage |
308 |
+ |
309 |
+class UninstallFailure(portage.exception.PortageException): |
310 |
+ """ |
311 |
+ An instance of this class is raised by unmerge() when |
312 |
+ an uninstallation fails. |
313 |
+ """ |
314 |
+ status = 1 |
315 |
+ def __init__(self, *pargs): |
316 |
+ portage.exception.PortageException.__init__(self, pargs) |
317 |
+ if pargs: |
318 |
+ self.status = pargs[0] |
319 |
|
320 |
|
321 |
Property changes on: main/trunk/pym/_emerge/UninstallFailure.py |
322 |
___________________________________________________________________ |
323 |
Name: svn:keywords |
324 |
+ Id |
325 |
|
326 |
Modified: main/trunk/pym/_emerge/__init__.py |
327 |
=================================================================== |
328 |
--- main/trunk/pym/_emerge/__init__.py 2009-06-22 18:12:37 UTC (rev 13666) |
329 |
+++ main/trunk/pym/_emerge/__init__.py 2009-06-22 18:21:56 UTC (rev 13667) |
330 |
@@ -83,87 +83,11 @@ |
331 |
from _emerge.PollSelectAdapter import PollSelectAdapter |
332 |
from _emerge.SequentialTaskQueue import SequentialTaskQueue |
333 |
from _emerge.ProgressHandler import ProgressHandler |
334 |
+from _emerge.stdout_spinner import stdout_spinner |
335 |
+from _emerge.UninstallFailure import UninstallFailure |
336 |
+from _emerge.JobStatusDisplay import JobStatusDisplay |
337 |
+from _emerge.getloadavg import getloadavg |
338 |
|
339 |
-try: |
340 |
- from cStringIO import StringIO |
341 |
-except ImportError: |
342 |
- from StringIO import StringIO |
343 |
- |
344 |
-class stdout_spinner(object): |
345 |
- scroll_msgs = [ |
346 |
- "Gentoo Rocks ("+platform.system()+")", |
347 |
- "Thank you for using Gentoo. :)", |
348 |
- "Are you actually trying to read this?", |
349 |
- "How many times have you stared at this?", |
350 |
- "We are generating the cache right now", |
351 |
- "You are paying too much attention.", |
352 |
- "A theory is better than its explanation.", |
353 |
- "Phasers locked on target, Captain.", |
354 |
- "Thrashing is just virtual crashing.", |
355 |
- "To be is to program.", |
356 |
- "Real Users hate Real Programmers.", |
357 |
- "When all else fails, read the instructions.", |
358 |
- "Functionality breeds Contempt.", |
359 |
- "The future lies ahead.", |
360 |
- "3.1415926535897932384626433832795028841971694", |
361 |
- "Sometimes insanity is the only alternative.", |
362 |
- "Inaccuracy saves a world of explanation.", |
363 |
- ] |
364 |
- |
365 |
- twirl_sequence = "/-\\|/-\\|/-\\|/-\\|\\-/|\\-/|\\-/|\\-/|" |
366 |
- |
367 |
- def __init__(self): |
368 |
- self.spinpos = 0 |
369 |
- self.update = self.update_twirl |
370 |
- self.scroll_sequence = self.scroll_msgs[ |
371 |
- int(time.time() * 100) % len(self.scroll_msgs)] |
372 |
- self.last_update = 0 |
373 |
- self.min_display_latency = 0.05 |
374 |
- |
375 |
- def _return_early(self): |
376 |
- """ |
377 |
- Flushing ouput to the tty too frequently wastes cpu time. Therefore, |
378 |
- each update* method should return without doing any output when this |
379 |
- method returns True. |
380 |
- """ |
381 |
- cur_time = time.time() |
382 |
- if cur_time - self.last_update < self.min_display_latency: |
383 |
- return True |
384 |
- self.last_update = cur_time |
385 |
- return False |
386 |
- |
387 |
- def update_basic(self): |
388 |
- self.spinpos = (self.spinpos + 1) % 500 |
389 |
- if self._return_early(): |
390 |
- return |
391 |
- if (self.spinpos % 100) == 0: |
392 |
- if self.spinpos == 0: |
393 |
- sys.stdout.write(". ") |
394 |
- else: |
395 |
- sys.stdout.write(".") |
396 |
- sys.stdout.flush() |
397 |
- |
398 |
- def update_scroll(self): |
399 |
- if self._return_early(): |
400 |
- return |
401 |
- if(self.spinpos >= len(self.scroll_sequence)): |
402 |
- sys.stdout.write(darkgreen(" \b\b\b" + self.scroll_sequence[ |
403 |
- len(self.scroll_sequence) - 1 - (self.spinpos % len(self.scroll_sequence))])) |
404 |
- else: |
405 |
- sys.stdout.write(green("\b " + self.scroll_sequence[self.spinpos])) |
406 |
- sys.stdout.flush() |
407 |
- self.spinpos = (self.spinpos + 1) % (2 * len(self.scroll_sequence)) |
408 |
- |
409 |
- def update_twirl(self): |
410 |
- self.spinpos = (self.spinpos + 1) % len(self.twirl_sequence) |
411 |
- if self._return_early(): |
412 |
- return |
413 |
- sys.stdout.write("\b\b " + self.twirl_sequence[self.spinpos]) |
414 |
- sys.stdout.flush() |
415 |
- |
416 |
- def update_quiet(self): |
417 |
- return |
418 |
- |
419 |
def userquery(prompt, responses=None, colours=None): |
420 |
"""Displays a prompt and a set of responses, then waits for a response |
421 |
which is checked against the responses and the first to match is |
422 |
@@ -6569,29 +6493,6 @@ |
423 |
return select.poll() |
424 |
return PollSelectAdapter() |
425 |
|
426 |
-getloadavg = getattr(os, "getloadavg", None) |
427 |
-if getloadavg is None: |
428 |
- def getloadavg(): |
429 |
- """ |
430 |
- Uses /proc/loadavg to emulate os.getloadavg(). |
431 |
- Raises OSError if the load average was unobtainable. |
432 |
- """ |
433 |
- try: |
434 |
- loadavg_str = open('/proc/loadavg').readline() |
435 |
- except IOError: |
436 |
- # getloadavg() is only supposed to raise OSError, so convert |
437 |
- raise OSError('unknown') |
438 |
- loadavg_split = loadavg_str.split() |
439 |
- if len(loadavg_split) < 3: |
440 |
- raise OSError('unknown') |
441 |
- loadavg_floats = [] |
442 |
- for i in xrange(3): |
443 |
- try: |
444 |
- loadavg_floats.append(float(loadavg_split[i])) |
445 |
- except ValueError: |
446 |
- raise OSError('unknown') |
447 |
- return tuple(loadavg_floats) |
448 |
- |
449 |
class PollScheduler(object): |
450 |
|
451 |
class _sched_iface_class(SlotObject): |
452 |
@@ -6879,253 +6780,6 @@ |
453 |
def add(self, task): |
454 |
self._queue.add(task) |
455 |
|
456 |
-class JobStatusDisplay(object): |
457 |
- |
458 |
- _bound_properties = ("curval", "failed", "running") |
459 |
- _jobs_column_width = 48 |
460 |
- |
461 |
- # Don't update the display unless at least this much |
462 |
- # time has passed, in units of seconds. |
463 |
- _min_display_latency = 2 |
464 |
- |
465 |
- _default_term_codes = { |
466 |
- 'cr' : '\r', |
467 |
- 'el' : '\x1b[K', |
468 |
- 'nel' : '\n', |
469 |
- } |
470 |
- |
471 |
- _termcap_name_map = { |
472 |
- 'carriage_return' : 'cr', |
473 |
- 'clr_eol' : 'el', |
474 |
- 'newline' : 'nel', |
475 |
- } |
476 |
- |
477 |
- def __init__(self, out=sys.stdout, quiet=False, xterm_titles=True): |
478 |
- object.__setattr__(self, "out", out) |
479 |
- object.__setattr__(self, "quiet", quiet) |
480 |
- object.__setattr__(self, "xterm_titles", xterm_titles) |
481 |
- object.__setattr__(self, "maxval", 0) |
482 |
- object.__setattr__(self, "merges", 0) |
483 |
- object.__setattr__(self, "_changed", False) |
484 |
- object.__setattr__(self, "_displayed", False) |
485 |
- object.__setattr__(self, "_last_display_time", 0) |
486 |
- object.__setattr__(self, "width", 80) |
487 |
- self.reset() |
488 |
- |
489 |
- isatty = hasattr(out, "isatty") and out.isatty() |
490 |
- object.__setattr__(self, "_isatty", isatty) |
491 |
- if not isatty or not self._init_term(): |
492 |
- term_codes = {} |
493 |
- for k, capname in self._termcap_name_map.iteritems(): |
494 |
- term_codes[k] = self._default_term_codes[capname] |
495 |
- object.__setattr__(self, "_term_codes", term_codes) |
496 |
- encoding = sys.getdefaultencoding() |
497 |
- for k, v in self._term_codes.items(): |
498 |
- if not isinstance(v, basestring): |
499 |
- self._term_codes[k] = v.decode(encoding, 'replace') |
500 |
- |
501 |
- def _init_term(self): |
502 |
- """ |
503 |
- Initialize term control codes. |
504 |
- @rtype: bool |
505 |
- @returns: True if term codes were successfully initialized, |
506 |
- False otherwise. |
507 |
- """ |
508 |
- |
509 |
- term_type = os.environ.get("TERM", "vt100") |
510 |
- tigetstr = None |
511 |
- |
512 |
- try: |
513 |
- import curses |
514 |
- try: |
515 |
- curses.setupterm(term_type, self.out.fileno()) |
516 |
- tigetstr = curses.tigetstr |
517 |
- except curses.error: |
518 |
- pass |
519 |
- except ImportError: |
520 |
- pass |
521 |
- |
522 |
- if tigetstr is None: |
523 |
- return False |
524 |
- |
525 |
- term_codes = {} |
526 |
- for k, capname in self._termcap_name_map.iteritems(): |
527 |
- code = tigetstr(capname) |
528 |
- if code is None: |
529 |
- code = self._default_term_codes[capname] |
530 |
- term_codes[k] = code |
531 |
- object.__setattr__(self, "_term_codes", term_codes) |
532 |
- return True |
533 |
- |
534 |
- def _format_msg(self, msg): |
535 |
- return ">>> %s" % msg |
536 |
- |
537 |
- def _erase(self): |
538 |
- self.out.write( |
539 |
- self._term_codes['carriage_return'] + \ |
540 |
- self._term_codes['clr_eol']) |
541 |
- self.out.flush() |
542 |
- self._displayed = False |
543 |
- |
544 |
- def _display(self, line): |
545 |
- self.out.write(line) |
546 |
- self.out.flush() |
547 |
- self._displayed = True |
548 |
- |
549 |
- def _update(self, msg): |
550 |
- |
551 |
- out = self.out |
552 |
- if not self._isatty: |
553 |
- out.write(self._format_msg(msg) + self._term_codes['newline']) |
554 |
- self.out.flush() |
555 |
- self._displayed = True |
556 |
- return |
557 |
- |
558 |
- if self._displayed: |
559 |
- self._erase() |
560 |
- |
561 |
- self._display(self._format_msg(msg)) |
562 |
- |
563 |
- def displayMessage(self, msg): |
564 |
- |
565 |
- was_displayed = self._displayed |
566 |
- |
567 |
- if self._isatty and self._displayed: |
568 |
- self._erase() |
569 |
- |
570 |
- self.out.write(self._format_msg(msg) + self._term_codes['newline']) |
571 |
- self.out.flush() |
572 |
- self._displayed = False |
573 |
- |
574 |
- if was_displayed: |
575 |
- self._changed = True |
576 |
- self.display() |
577 |
- |
578 |
- def reset(self): |
579 |
- self.maxval = 0 |
580 |
- self.merges = 0 |
581 |
- for name in self._bound_properties: |
582 |
- object.__setattr__(self, name, 0) |
583 |
- |
584 |
- if self._displayed: |
585 |
- self.out.write(self._term_codes['newline']) |
586 |
- self.out.flush() |
587 |
- self._displayed = False |
588 |
- |
589 |
- def __setattr__(self, name, value): |
590 |
- old_value = getattr(self, name) |
591 |
- if value == old_value: |
592 |
- return |
593 |
- object.__setattr__(self, name, value) |
594 |
- if name in self._bound_properties: |
595 |
- self._property_change(name, old_value, value) |
596 |
- |
597 |
- def _property_change(self, name, old_value, new_value): |
598 |
- self._changed = True |
599 |
- self.display() |
600 |
- |
601 |
- def _load_avg_str(self): |
602 |
- try: |
603 |
- avg = getloadavg() |
604 |
- except OSError: |
605 |
- return 'unknown' |
606 |
- |
607 |
- max_avg = max(avg) |
608 |
- |
609 |
- if max_avg < 10: |
610 |
- digits = 2 |
611 |
- elif max_avg < 100: |
612 |
- digits = 1 |
613 |
- else: |
614 |
- digits = 0 |
615 |
- |
616 |
- return ", ".join(("%%.%df" % digits ) % x for x in avg) |
617 |
- |
618 |
- def display(self): |
619 |
- """ |
620 |
- Display status on stdout, but only if something has |
621 |
- changed since the last call. |
622 |
- """ |
623 |
- |
624 |
- if self.quiet: |
625 |
- return |
626 |
- |
627 |
- current_time = time.time() |
628 |
- time_delta = current_time - self._last_display_time |
629 |
- if self._displayed and \ |
630 |
- not self._changed: |
631 |
- if not self._isatty: |
632 |
- return |
633 |
- if time_delta < self._min_display_latency: |
634 |
- return |
635 |
- |
636 |
- self._last_display_time = current_time |
637 |
- self._changed = False |
638 |
- self._display_status() |
639 |
- |
640 |
- def _display_status(self): |
641 |
- # Don't use len(self._completed_tasks) here since that also |
642 |
- # can include uninstall tasks. |
643 |
- curval_str = str(self.curval) |
644 |
- maxval_str = str(self.maxval) |
645 |
- running_str = str(self.running) |
646 |
- failed_str = str(self.failed) |
647 |
- load_avg_str = self._load_avg_str() |
648 |
- |
649 |
- color_output = StringIO() |
650 |
- plain_output = StringIO() |
651 |
- style_file = portage.output.ConsoleStyleFile(color_output) |
652 |
- style_file.write_listener = plain_output |
653 |
- style_writer = portage.output.StyleWriter(file=style_file, maxcol=9999) |
654 |
- style_writer.style_listener = style_file.new_styles |
655 |
- f = formatter.AbstractFormatter(style_writer) |
656 |
- |
657 |
- number_style = "INFORM" |
658 |
- f.add_literal_data("Jobs: ") |
659 |
- f.push_style(number_style) |
660 |
- f.add_literal_data(curval_str) |
661 |
- f.pop_style() |
662 |
- f.add_literal_data(" of ") |
663 |
- f.push_style(number_style) |
664 |
- f.add_literal_data(maxval_str) |
665 |
- f.pop_style() |
666 |
- f.add_literal_data(" complete") |
667 |
- |
668 |
- if self.running: |
669 |
- f.add_literal_data(", ") |
670 |
- f.push_style(number_style) |
671 |
- f.add_literal_data(running_str) |
672 |
- f.pop_style() |
673 |
- f.add_literal_data(" running") |
674 |
- |
675 |
- if self.failed: |
676 |
- f.add_literal_data(", ") |
677 |
- f.push_style(number_style) |
678 |
- f.add_literal_data(failed_str) |
679 |
- f.pop_style() |
680 |
- f.add_literal_data(" failed") |
681 |
- |
682 |
- padding = self._jobs_column_width - len(plain_output.getvalue()) |
683 |
- if padding > 0: |
684 |
- f.add_literal_data(padding * " ") |
685 |
- |
686 |
- f.add_literal_data("Load avg: ") |
687 |
- f.add_literal_data(load_avg_str) |
688 |
- |
689 |
- # Truncate to fit width, to avoid making the terminal scroll if the |
690 |
- # line overflows (happens when the load average is large). |
691 |
- plain_output = plain_output.getvalue() |
692 |
- if self._isatty and len(plain_output) > self.width: |
693 |
- # Use plain_output here since it's easier to truncate |
694 |
- # properly than the color output which contains console |
695 |
- # color codes. |
696 |
- self._update(plain_output[:self.width]) |
697 |
- else: |
698 |
- self._update(color_output.getvalue()) |
699 |
- |
700 |
- if self.xterm_titles: |
701 |
- xtermTitle(" ".join(plain_output.split())) |
702 |
- |
703 |
class Scheduler(PollScheduler): |
704 |
|
705 |
_opts_ignore_blockers = \ |
706 |
@@ -8875,17 +8529,6 @@ |
707 |
|
708 |
self._schedule() |
709 |
|
710 |
-class UninstallFailure(portage.exception.PortageException): |
711 |
- """ |
712 |
- An instance of this class is raised by unmerge() when |
713 |
- an uninstallation fails. |
714 |
- """ |
715 |
- status = 1 |
716 |
- def __init__(self, *pargs): |
717 |
- portage.exception.PortageException.__init__(self, pargs) |
718 |
- if pargs: |
719 |
- self.status = pargs[0] |
720 |
- |
721 |
def unmerge(root_config, myopts, unmerge_action, |
722 |
unmerge_files, ldpath_mtimes, autoclean=0, |
723 |
clean_world=1, clean_delay=1, ordered=0, raise_on_error=0, |
724 |
|
725 |
Added: main/trunk/pym/_emerge/getloadavg.py |
726 |
=================================================================== |
727 |
--- main/trunk/pym/_emerge/getloadavg.py (rev 0) |
728 |
+++ main/trunk/pym/_emerge/getloadavg.py 2009-06-22 18:21:56 UTC (rev 13667) |
729 |
@@ -0,0 +1,24 @@ |
730 |
+import os |
731 |
+ |
732 |
+getloadavg = getattr(os, "getloadavg", None) |
733 |
+if getloadavg is None: |
734 |
+ def getloadavg(): |
735 |
+ """ |
736 |
+ Uses /proc/loadavg to emulate os.getloadavg(). |
737 |
+ Raises OSError if the load average was unobtainable. |
738 |
+ """ |
739 |
+ try: |
740 |
+ loadavg_str = open('/proc/loadavg').readline() |
741 |
+ except IOError: |
742 |
+ # getloadavg() is only supposed to raise OSError, so convert |
743 |
+ raise OSError('unknown') |
744 |
+ loadavg_split = loadavg_str.split() |
745 |
+ if len(loadavg_split) < 3: |
746 |
+ raise OSError('unknown') |
747 |
+ loadavg_floats = [] |
748 |
+ for i in xrange(3): |
749 |
+ try: |
750 |
+ loadavg_floats.append(float(loadavg_split[i])) |
751 |
+ except ValueError: |
752 |
+ raise OSError('unknown') |
753 |
+ return tuple(loadavg_floats) |
754 |
|
755 |
|
756 |
Property changes on: main/trunk/pym/_emerge/getloadavg.py |
757 |
___________________________________________________________________ |
758 |
Name: svn:keywords |
759 |
+ Id |
760 |
|
761 |
Added: main/trunk/pym/_emerge/stdout_spinner.py |
762 |
=================================================================== |
763 |
--- main/trunk/pym/_emerge/stdout_spinner.py (rev 0) |
764 |
+++ main/trunk/pym/_emerge/stdout_spinner.py 2009-06-22 18:21:56 UTC (rev 13667) |
765 |
@@ -0,0 +1,80 @@ |
766 |
+import platform |
767 |
+import sys |
768 |
+import time |
769 |
+ |
770 |
+from portage.output import darkgreen, green |
771 |
+ |
772 |
+class stdout_spinner(object): |
773 |
+ scroll_msgs = [ |
774 |
+ "Gentoo Rocks ("+platform.system()+")", |
775 |
+ "Thank you for using Gentoo. :)", |
776 |
+ "Are you actually trying to read this?", |
777 |
+ "How many times have you stared at this?", |
778 |
+ "We are generating the cache right now", |
779 |
+ "You are paying too much attention.", |
780 |
+ "A theory is better than its explanation.", |
781 |
+ "Phasers locked on target, Captain.", |
782 |
+ "Thrashing is just virtual crashing.", |
783 |
+ "To be is to program.", |
784 |
+ "Real Users hate Real Programmers.", |
785 |
+ "When all else fails, read the instructions.", |
786 |
+ "Functionality breeds Contempt.", |
787 |
+ "The future lies ahead.", |
788 |
+ "3.1415926535897932384626433832795028841971694", |
789 |
+ "Sometimes insanity is the only alternative.", |
790 |
+ "Inaccuracy saves a world of explanation.", |
791 |
+ ] |
792 |
+ |
793 |
+ twirl_sequence = "/-\\|/-\\|/-\\|/-\\|\\-/|\\-/|\\-/|\\-/|" |
794 |
+ |
795 |
+ def __init__(self): |
796 |
+ self.spinpos = 0 |
797 |
+ self.update = self.update_twirl |
798 |
+ self.scroll_sequence = self.scroll_msgs[ |
799 |
+ int(time.time() * 100) % len(self.scroll_msgs)] |
800 |
+ self.last_update = 0 |
801 |
+ self.min_display_latency = 0.05 |
802 |
+ |
803 |
+ def _return_early(self): |
804 |
+ """ |
805 |
+ Flushing ouput to the tty too frequently wastes cpu time. Therefore, |
806 |
+ each update* method should return without doing any output when this |
807 |
+ method returns True. |
808 |
+ """ |
809 |
+ cur_time = time.time() |
810 |
+ if cur_time - self.last_update < self.min_display_latency: |
811 |
+ return True |
812 |
+ self.last_update = cur_time |
813 |
+ return False |
814 |
+ |
815 |
+ def update_basic(self): |
816 |
+ self.spinpos = (self.spinpos + 1) % 500 |
817 |
+ if self._return_early(): |
818 |
+ return |
819 |
+ if (self.spinpos % 100) == 0: |
820 |
+ if self.spinpos == 0: |
821 |
+ sys.stdout.write(". ") |
822 |
+ else: |
823 |
+ sys.stdout.write(".") |
824 |
+ sys.stdout.flush() |
825 |
+ |
826 |
+ def update_scroll(self): |
827 |
+ if self._return_early(): |
828 |
+ return |
829 |
+ if(self.spinpos >= len(self.scroll_sequence)): |
830 |
+ sys.stdout.write(darkgreen(" \b\b\b" + self.scroll_sequence[ |
831 |
+ len(self.scroll_sequence) - 1 - (self.spinpos % len(self.scroll_sequence))])) |
832 |
+ else: |
833 |
+ sys.stdout.write(green("\b " + self.scroll_sequence[self.spinpos])) |
834 |
+ sys.stdout.flush() |
835 |
+ self.spinpos = (self.spinpos + 1) % (2 * len(self.scroll_sequence)) |
836 |
+ |
837 |
+ def update_twirl(self): |
838 |
+ self.spinpos = (self.spinpos + 1) % len(self.twirl_sequence) |
839 |
+ if self._return_early(): |
840 |
+ return |
841 |
+ sys.stdout.write("\b\b " + self.twirl_sequence[self.spinpos]) |
842 |
+ sys.stdout.flush() |
843 |
+ |
844 |
+ def update_quiet(self): |
845 |
+ return |
846 |
|
847 |
|
848 |
Property changes on: main/trunk/pym/_emerge/stdout_spinner.py |
849 |
___________________________________________________________________ |
850 |
Name: svn:keywords |
851 |
+ Id |