js/src/tests/lib/progressbar.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/tests/lib/progressbar.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,109 @@
     1.4 +# Text progress bar library, like curl or scp.
     1.5 +
     1.6 +from datetime import datetime, timedelta
     1.7 +import math
     1.8 +import sys
     1.9 +
    1.10 +if sys.platform.startswith('win'):
    1.11 +    from terminal_win import Terminal
    1.12 +else:
    1.13 +    from terminal_unix import Terminal
    1.14 +
    1.15 +class NullProgressBar(object):
    1.16 +    def update(self, current, data): pass
    1.17 +    def poke(self): pass
    1.18 +    def finish(self, complete=True): pass
    1.19 +    def beginline(self): pass
    1.20 +    def message(self, msg): sys.stdout.write(msg + '\n')
    1.21 +    def update_granularity(self): return timedelta.max
    1.22 +
    1.23 +class ProgressBar(object):
    1.24 +    def __init__(self, limit, fmt):
    1.25 +        assert self.conservative_isatty()
    1.26 +
    1.27 +        self.prior = None
    1.28 +        self.atLineStart = True
    1.29 +        self.counters_fmt = fmt # [{str:str}] Describtion of how to lay out each
    1.30 +                                #             field in the counters map.
    1.31 +        self.limit = limit # int: The value of 'current' equal to 100%.
    1.32 +        self.limit_digits = int(math.ceil(math.log10(self.limit))) # int: max digits in limit
    1.33 +        self.t0 = datetime.now() # datetime: The start time.
    1.34 +
    1.35 +        # Compute the width of the counters and build the format string.
    1.36 +        self.counters_width = 1 # [
    1.37 +        for layout in self.counters_fmt:
    1.38 +            self.counters_width += self.limit_digits
    1.39 +            self.counters_width += 1 # | (or ']' for the last one)
    1.40 +
    1.41 +        self.barlen = 64 - self.counters_width
    1.42 +
    1.43 +    def update_granularity(self):
    1.44 +        return timedelta(seconds=0.1)
    1.45 +
    1.46 +    def update(self, current, data):
    1.47 +        # Record prior for poke.
    1.48 +        self.prior = (current, data)
    1.49 +        self.atLineStart = False
    1.50 +
    1.51 +        # Build counters string.
    1.52 +        sys.stdout.write('\r[')
    1.53 +        for layout in self.counters_fmt:
    1.54 +            Terminal.set_color(layout['color'])
    1.55 +            sys.stdout.write(('%' + str(self.limit_digits) + 'd') % data[layout['value']])
    1.56 +            Terminal.reset_color()
    1.57 +            if layout != self.counters_fmt[-1]:
    1.58 +                sys.stdout.write('|')
    1.59 +            else:
    1.60 +                sys.stdout.write('] ')
    1.61 +
    1.62 +        # Build the bar.
    1.63 +        pct = int(100.0 * current / self.limit)
    1.64 +        sys.stdout.write('%3d%% ' % pct)
    1.65 +
    1.66 +        barlen = int(1.0 * self.barlen * current / self.limit) - 1
    1.67 +        bar = '=' * barlen + '>' + ' ' * (self.barlen - barlen - 1)
    1.68 +        sys.stdout.write(bar + '|')
    1.69 +
    1.70 +        # Update the bar.
    1.71 +        dt = datetime.now() - self.t0
    1.72 +        dt = dt.seconds + dt.microseconds * 1e-6
    1.73 +        sys.stdout.write('%6.1fs' % dt)
    1.74 +        Terminal.clear_right()
    1.75 +
    1.76 +        # Force redisplay, since we didn't write a \n.
    1.77 +        sys.stdout.flush()
    1.78 +
    1.79 +    def poke(self):
    1.80 +        if not self.prior:
    1.81 +            return
    1.82 +        self.update(*self.prior)
    1.83 +
    1.84 +    def finish(self, complete=True):
    1.85 +        final_count = self.limit if complete else self.prior[0]
    1.86 +        self.update(final_count, self.prior[1])
    1.87 +        sys.stdout.write('\n')
    1.88 +
    1.89 +    def beginline(self):
    1.90 +        if not self.atLineStart:
    1.91 +            sys.stdout.write('\n')
    1.92 +            self.atLineStart = True
    1.93 +
    1.94 +    def message(self, msg):
    1.95 +        self.beginline()
    1.96 +        sys.stdout.write(msg)
    1.97 +        sys.stdout.write('\n')
    1.98 +
    1.99 +    @staticmethod
   1.100 +    def conservative_isatty():
   1.101 +        """
   1.102 +        Prefer erring on the side of caution and not using terminal commands if
   1.103 +        the current output stream may be a file.  We explicitly check for the
   1.104 +        Android platform because terminal commands work poorly over ADB's
   1.105 +        redirection.
   1.106 +        """
   1.107 +        try:
   1.108 +            import android
   1.109 +            return False
   1.110 +        except ImportError:
   1.111 +            return sys.stdout.isatty()
   1.112 +        return False

mercurial