summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2007-05-27 12:12:51 +0000
committerZac Medico <zmedico@gentoo.org>2007-05-27 12:12:51 +0000
commit7d093f0cb5f87696f627af664ce47edb67169125 (patch)
tree0d8f85f519474393f046666070411f39748e92d1
parent26722a60c214295187372ab1a319cdd5283f2a1f (diff)
downloadportage-7d093f0cb5f87696f627af664ce47edb67169125.tar.gz
portage-7d093f0cb5f87696f627af664ce47edb67169125.tar.bz2
portage-7d093f0cb5f87696f627af664ce47edb67169125.zip
Add progress support to emaint (similar to wget's progress bar).
svn path=/main/trunk/; revision=6639
-rwxr-xr-xbin/emaint37
-rw-r--r--pym/portage/output.py128
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