diff options
author | Zac Medico <zmedico@gentoo.org> | 2008-07-19 03:18:21 +0000 |
---|---|---|
committer | Zac Medico <zmedico@gentoo.org> | 2008-07-19 03:18:21 +0000 |
commit | 23ab040fa6adb92b45ff35dc170adb8264124e48 (patch) | |
tree | b8e06947fe772cca4115eb39b03da2ea77bee74d | |
parent | cb95ea298f10add8e27404e7cc25db0a60782c07 (diff) | |
download | portage-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__.py | 96 |
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): """ |