summaryrefslogtreecommitdiffstats
path: root/progress.py
diff options
context:
space:
mode:
Diffstat (limited to 'progress.py')
-rw-r--r--progress.py90
1 files changed, 64 insertions, 26 deletions
diff --git a/progress.py b/progress.py
index d2ed4bae..43c7ad21 100644
--- a/progress.py
+++ b/progress.py
@@ -1,5 +1,3 @@
1# -*- coding:utf-8 -*-
2#
3# Copyright (C) 2009 The Android Open Source Project 1# Copyright (C) 2009 The Android Open Source Project
4# 2#
5# Licensed under the Apache License, Version 2.0 (the "License"); 3# Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,18 +24,53 @@ _NOT_TTY = not os.isatty(2)
26# column 0. 24# column 0.
27CSI_ERASE_LINE = '\x1b[2K' 25CSI_ERASE_LINE = '\x1b[2K'
28 26
27
28def duration_str(total):
29 """A less noisy timedelta.__str__.
30
31 The default timedelta stringification contains a lot of leading zeros and
32 uses microsecond resolution. This makes for noisy output.
33 """
34 hours, rem = divmod(total, 3600)
35 mins, secs = divmod(rem, 60)
36 ret = '%.3fs' % (secs,)
37 if mins:
38 ret = '%im%s' % (mins, ret)
39 if hours:
40 ret = '%ih%s' % (hours, ret)
41 return ret
42
43
29class Progress(object): 44class Progress(object):
30 def __init__(self, title, total=0, units='', print_newline=False, 45 def __init__(self, title, total=0, units='', print_newline=False, delay=True,
31 always_print_percentage=False): 46 quiet=False):
32 self._title = title 47 self._title = title
33 self._total = total 48 self._total = total
34 self._done = 0 49 self._done = 0
35 self._lastp = -1
36 self._start = time() 50 self._start = time()
37 self._show = False 51 self._show = not delay
38 self._units = units 52 self._units = units
39 self._print_newline = print_newline 53 self._print_newline = print_newline
40 self._always_print_percentage = always_print_percentage 54 # Only show the active jobs section if we run more than one in parallel.
55 self._show_jobs = False
56 self._active = 0
57
58 # When quiet, never show any output. It's a bit hacky, but reusing the
59 # existing logic that delays initial output keeps the rest of the class
60 # clean. Basically we set the start time to years in the future.
61 if quiet:
62 self._show = False
63 self._start += 2**32
64
65 def start(self, name):
66 self._active += 1
67 if not self._show_jobs:
68 self._show_jobs = self._active > 1
69 self.update(inc=0, msg='started ' + name)
70
71 def finish(self, name):
72 self.update(msg='finished ' + name)
73 self._active -= 1
41 74
42 def update(self, inc=1, msg=''): 75 def update(self, inc=1, msg=''):
43 self._done += inc 76 self._done += inc
@@ -53,41 +86,46 @@ class Progress(object):
53 86
54 if self._total <= 0: 87 if self._total <= 0:
55 sys.stderr.write('%s\r%s: %d,' % ( 88 sys.stderr.write('%s\r%s: %d,' % (
56 CSI_ERASE_LINE, 89 CSI_ERASE_LINE,
57 self._title, 90 self._title,
58 self._done)) 91 self._done))
59 sys.stderr.flush() 92 sys.stderr.flush()
60 else: 93 else:
61 p = (100 * self._done) / self._total 94 p = (100 * self._done) / self._total
62 95 if self._show_jobs:
63 if self._lastp != p or self._always_print_percentage: 96 jobs = '[%d job%s] ' % (self._active, 's' if self._active > 1 else '')
64 self._lastp = p 97 else:
65 sys.stderr.write('%s\r%s: %3d%% (%d%s/%d%s)%s%s%s' % ( 98 jobs = ''
99 sys.stderr.write('%s\r%s: %2d%% %s(%d%s/%d%s)%s%s%s' % (
66 CSI_ERASE_LINE, 100 CSI_ERASE_LINE,
67 self._title, 101 self._title,
68 p, 102 p,
103 jobs,
69 self._done, self._units, 104 self._done, self._units,
70 self._total, self._units, 105 self._total, self._units,
71 ' ' if msg else '', msg, 106 ' ' if msg else '', msg,
72 "\n" if self._print_newline else "")) 107 '\n' if self._print_newline else ''))
73 sys.stderr.flush() 108 sys.stderr.flush()
74 109
75 def end(self): 110 def end(self):
76 if _NOT_TTY or IsTrace() or not self._show: 111 if _NOT_TTY or IsTrace() or not self._show:
77 return 112 return
78 113
114 duration = duration_str(time() - self._start)
79 if self._total <= 0: 115 if self._total <= 0:
80 sys.stderr.write('%s\r%s: %d, done.\n' % ( 116 sys.stderr.write('%s\r%s: %d, done in %s\n' % (
81 CSI_ERASE_LINE, 117 CSI_ERASE_LINE,
82 self._title, 118 self._title,
83 self._done)) 119 self._done,
120 duration))
84 sys.stderr.flush() 121 sys.stderr.flush()
85 else: 122 else:
86 p = (100 * self._done) / self._total 123 p = (100 * self._done) / self._total
87 sys.stderr.write('%s\r%s: %3d%% (%d%s/%d%s), done.\n' % ( 124 sys.stderr.write('%s\r%s: %3d%% (%d%s/%d%s), done in %s\n' % (
88 CSI_ERASE_LINE, 125 CSI_ERASE_LINE,
89 self._title, 126 self._title,
90 p, 127 p,
91 self._done, self._units, 128 self._done, self._units,
92 self._total, self._units)) 129 self._total, self._units,
130 duration))
93 sys.stderr.flush() 131 sys.stderr.flush()