summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2008-07-19 03:18:21 +0000
committerZac Medico <zmedico@gentoo.org>2008-07-19 03:18:21 +0000
commit23ab040fa6adb92b45ff35dc170adb8264124e48 (patch)
treeb8e06947fe772cca4115eb39b03da2ea77bee74d
parentcb95ea298f10add8e27404e7cc25db0a60782c07 (diff)
downloadportage-23ab040fa6adb92b45ff35dc170adb8264124e48.tar.gz
portage-23ab040fa6adb92b45ff35dc170adb8264124e48.tar.bz2
portage-23ab040fa6adb92b45ff35dc170adb8264124e48.zip
Add support to JobStatusDisplay() to update the current line on the terminal,
which in the future can be used to erase the line and update it with new information such as the latest load average measurement. This uses curses to obtain the simple control codes that are needed, and has fallback codes in case the curses module is unavailable or raises an error. When stdout is not a tty then the line erasing behavior is automatically disabled and display updates are simply show on a new line. svn path=/main/trunk/; revision=11128
-rw-r--r--pym/_emerge/__init__.py96
1 files changed, 91 insertions, 5 deletions
diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py
index bfc5767e9..6ebdb6ff7 100644
--- a/pym/_emerge/__init__.py
+++ b/pym/_emerge/__init__.py
@@ -8388,19 +8388,107 @@ class JobStatusDisplay(object):
_bound_properties = ("curval", "running")
_jobs_column_width = 45
- def __init__(self, quiet=False):
+ _default_term_codes = {
+ 'cr' : '\r',
+ 'el' : '\x1b[K',
+ 'nel' : '\n',
+ }
+
+ _termcap_name_map = {
+ 'carriage_return' : 'cr',
+ 'clr_eol' : 'el',
+ 'newline' : 'nel',
+ }
+
+ def __init__(self, out=sys.stdout, quiet=False):
+ object.__setattr__(self, "out", out)
object.__setattr__(self, "quiet", quiet)
object.__setattr__(self, "maxval", 0)
object.__setattr__(self, "merges", 0)
object.__setattr__(self, "_changed", False)
+ object.__setattr__(self, "_displayed", False)
self.reset()
+ isatty = hasattr(out, "isatty") and out.isatty()
+ object.__setattr__(self, "_isatty", isatty)
+ if isatty:
+ self._init_term()
+ else:
+ term_codes = {}
+ for k, capname in self._termcap_name_map.iteritems():
+ term_codes[k] = self._default_term_codes[capname]
+ object.__setattr__(self, "_term_codes", term_codes)
+
+ def _init_term(self):
+ """
+ Initialize term control codes.
+ """
+
+ term_type = os.environ.get("TERM", "vt100")
+ tigetstr = None
+
+ try:
+ import curses
+ try:
+ curses.setupterm(term_type, self.out.fileno())
+ tigetstr = curses.tigetstr
+ except curses.error:
+ pass
+ except ImportError:
+ pass
+
+ if tigetstr is None:
+ def tigetstr(capname):
+ return self._default_term_codes[capname]
+
+ term_codes = {}
+ for k, capname in self._termcap_name_map.iteritems():
+ term_codes[k] = tigetstr(capname)
+ object.__setattr__(self, "_term_codes", term_codes)
+
+ def _format_msg(self, msg):
+ return ">>> %s" % msg
+
+ def _erase(self):
+ self.out.write(
+ self._term_codes['carriage_return'] + \
+ self._term_codes['clr_eol'])
+ self._displayed = False
+
+ def _display(self, line):
+ self.out.write(line)
+ self._displayed = True
+
+ def _update(self, msg):
+
+ out = self.out
+ if not self._isatty:
+ out.write(self._format_msg(msg) + self._term_codes['newline'])
+ return
+
+ if self._displayed:
+ self._erase()
+
+ self._display(self._format_msg(msg))
+
+ def displayMessage(self, msg):
+
+ if self._isatty and self._displayed:
+ self._erase()
+
+ self.out.write(self._format_msg(msg) + self._term_codes['newline'])
+ self._displayed = False
+
def reset(self):
self.maxval = 0
self.merges = 0
for name in self._bound_properties:
object.__setattr__(self, name, 0)
+ if self._displayed:
+ self.out.write(self._term_codes['newline'])
+ self._displayed = False
+
def __setattr__(self, name, value):
old_value = getattr(self, name)
if value == old_value:
@@ -8482,8 +8570,7 @@ class JobStatusDisplay(object):
f.add_literal_data("Load average: ")
f.add_literal_data(load_avg_str)
- portage.writemsg_stdout(">>> %s\n" % \
- (color_output.getvalue(),), noiselevel=-1)
+ self._update(color_output.getvalue())
xtermTitle(plain_output.getvalue())
class Scheduler(PollScheduler):
@@ -9374,8 +9461,7 @@ class Scheduler(PollScheduler):
@param msg: a brief status message (no newlines allowed)
"""
- # TODO: Let self._status_display handle this.
- portage.util.writemsg_level(">>> %s\n" % msg, noiselevel=-1)
+ self._status_display.displayMessage(msg)
def _save_resume_list(self):
"""