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