diff options
Diffstat (limited to 'progress.py')
-rw-r--r-- | progress.py | 90 |
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. |
27 | CSI_ERASE_LINE = '\x1b[2K' | 25 | CSI_ERASE_LINE = '\x1b[2K' |
28 | 26 | ||
27 | |||
28 | def 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 | |||
29 | class Progress(object): | 44 | class 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() |