diff options
-rwxr-xr-x | bin/emaint | 37 | ||||
-rw-r--r-- | pym/portage/output.py | 128 |
2 files changed, 160 insertions, 5 deletions
diff --git a/bin/emaint b/bin/emaint index 0e9ba853d..c44bbe85a 100755 --- a/bin/emaint +++ b/bin/emaint @@ -1,6 +1,6 @@ #!/usr/bin/python -O -import sys, os +import sys, os, time from optparse import OptionParser, OptionValueError if not hasattr(__builtins__, "set"): from sets import Set as set @@ -12,7 +12,7 @@ except ImportError: sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) import portage -import portage.const, portage.exception +import portage.const, portage.exception, portage.output class WorldHandler(object): def name(): @@ -132,6 +132,24 @@ class VdbKeyHandler(object): return errors +class ProgressHandler(object): + def __init__(self): + self.curval = 0 + self.maxval = 0 + self.last_update = 0 + self.min_display_latency = 0.2 + + def onProgress(self, maxval, curval): + self.maxval = maxval + self.curval = curval + cur_time = time.time() + if cur_time - self.last_update >= self.min_display_latency: + self.last_update = cur_time + self.display() + + def display(self): + raise NotImplementedError(self) + def emaint_main(myargv): # TODO: Create a system that allows external modules to be added without @@ -191,11 +209,22 @@ def emaint_main(myargv): status = "Attempting to fix %s" func = "fix" - + isatty = sys.stdout.isatty() for task in tasks: print status % task.name() inst = task() - result = getattr(inst, func)() + onProgress = None + if isatty: + progressBar = portage.output.TermProgressBar() + progressHandler = ProgressHandler() + def display(): + progressBar.set(progressHandler.maxval, progressHandler.curval) + progressHandler.display = display + result = getattr(inst, func)(onProgress=progressHandler.onProgress) + if isatty: + # make sure the final progress is displayed + progressHandler.display() + print if result: print print "\n".join(result) diff --git a/pym/portage/output.py b/pym/portage/output.py index 01595e5b1..d2122e0b5 100644 --- a/pym/portage/output.py +++ b/pym/portage/output.py @@ -4,7 +4,7 @@ __docformat__ = "epytext" -import commands,errno,os,re,shlex,sys +import commands, errno, os, re, shlex, sys, time from portage.const import COLOR_MAP_FILE from portage.util import writemsg from portage.exception import PortageException, ParseError, PermissionDenied, FileNotFound @@ -407,3 +407,129 @@ class EOutput: if not self.quiet: self.__eend("ewend", errno, msg) self.__last_e_cmd = "ewend" + +class ProgressBar(object): + """The interface is copied from the ProgressBar class from the EasyDialogs + module (which is Mac only).""" + def __init__(self, title=None, maxval=0, label=None): + self._title = title + self._maxval = maxval + self._label = maxval + self._curval = 0 + + @property + def curval(self): + """ + The current value (of type integer or long integer) of the progress + bar. The normal access methods coerce curval between 0 and maxval. This + attribute should not be altered directly. + """ + return self._curval + + @property + def maxval(self): + """ + The maximum value (of type integer or long integer) of the progress + bar; the progress bar (thermometer style) is full when curval equals + maxval. If maxval is 0, the bar will be indeterminate (barber-pole). + This attribute should not be altered directly. + """ + return self._maxval + + def title(self, newstr): + """Sets the text in the title bar of the progress dialog to newstr.""" + self._title = newstr + + def label(self, newstr): + """Sets the text in the progress box of the progress dialog to newstr.""" + self._label = newstr + + def set(self, value, maxval=None): + """ + Sets the progress bar's curval to value, and also maxval to max if the + latter is provided. value is first coerced between 0 and maxval. The + thermometer bar is updated to reflect the changes, including a change + from indeterminate to determinate or vice versa. + """ + if maxval is not None: + self._maxval = maxval + if value < 0: + value = 0 + elif value > maxval: + value = maxval + self._curval = value + + def inc(self, n=1): + """Increments the progress bar's curval by n, or by 1 if n is not + provided. (Note that n may be negative, in which case the effect is a + decrement.) The progress bar is updated to reflect the change. If the + bar is indeterminate, this causes one ``spin'' of the barber pole. The + resulting curval is coerced between 0 and maxval if incrementing causes + it to fall outside this range. + """ + self.set(self._curval+n) + +class TermProgressBar(ProgressBar): + """A tty progress bar similar to wget's.""" + def __init__(self, **kwargs): + ProgressBar.__init__(self, **kwargs) + lines, self.term_columns = get_term_size() + self.file = sys.stdout + self._min_columns = 11 + # for indeterminate mode, ranges from 0.0 to 1.0 + self._position = 0.0 + + def set(self, value, maxval=None): + ProgressBar.set(self, value, maxval=maxval) + self._display_image(self._create_image()) + + def _display_image(self, image): + self.file.write('\r') + self.file.write(image) + self.file.flush() + + def _create_image(self): + cols = self.term_columns + min_columns = self._min_columns + curval = self._curval + maxval = self._maxval + position = self._position + if cols < 3: + return "" + bar_space = cols - 6 + if maxval == 0: + max_bar_width = bar_space-3 + image = " " + if cols < min_columns: + return image + if position <= 0.5: + offset = 2 * position + else: + offset = 2 * (1 - position) + delta = 0.5 / max_bar_width + position += delta + if position >= 1.0: + position = 0.0 + # make sure it touches the ends + if 1.0 - position < delta: + position = 1.0 + if position < 0.5 and 0.5 - position < delta: + position = 0.5 + self._position = position + bar_width = int(offset * max_bar_width) + image = image + "[" + (bar_width * " ") + \ + "<=>" + ((max_bar_width - bar_width) * " ") + "]" + return image + else: + max_bar_width = bar_space-1 + percentage = int(100 * float(curval) / maxval) + if percentage == 100: + percentage = 99 + image = ("%d%% " % percentage).rjust(4) + if cols < min_columns: + return image + offset = float(curval) / maxval + bar_width = int(offset * max_bar_width) + image = image + "[" + (bar_width * "=") + \ + ">" + ((max_bar_width - bar_width) * " ") + "]" + return image |