diff options
Diffstat (limited to 'lib/bb/progress.py')
-rw-r--r-- | lib/bb/progress.py | 69 |
1 files changed, 50 insertions, 19 deletions
diff --git a/lib/bb/progress.py b/lib/bb/progress.py index 9c755b7f7..9518be77f 100644 --- a/lib/bb/progress.py +++ b/lib/bb/progress.py @@ -14,7 +14,27 @@ import bb.event import bb.build from bb.build import StdoutNoopContextManager -class ProgressHandler(object): + +# from https://stackoverflow.com/a/14693789/221061 +ANSI_ESCAPE_REGEX = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]') + + +def filter_color(string): + """ + Filter ANSI escape codes out of |string|, return new string + """ + return ANSI_ESCAPE_REGEX.sub('', string) + + +def filter_color_n(string): + """ + Filter ANSI escape codes out of |string|, returns tuple of + (new string, # of ANSI codes removed) + """ + return ANSI_ESCAPE_REGEX.subn('', string) + + +class ProgressHandler: """ Base class that can pretend to be a file object well enough to be used to build objects to intercept console output and determine the @@ -55,6 +75,7 @@ class ProgressHandler(object): self._lastevent = ts self._progress = progress + class LineFilterProgressHandler(ProgressHandler): """ A ProgressHandler variant that provides the ability to filter out @@ -66,62 +87,68 @@ class LineFilterProgressHandler(ProgressHandler): """ def __init__(self, d, outfile=None): self._linebuffer = '' - super(LineFilterProgressHandler, self).__init__(d, outfile) + super().__init__(d, outfile) def write(self, string): self._linebuffer += string while True: breakpos = self._linebuffer.find('\n') + 1 if breakpos == 0: - break + # for the case when the line with progress ends with only '\r' + breakpos = self._linebuffer.find('\r') + 1 + if breakpos == 0: + break line = self._linebuffer[:breakpos] self._linebuffer = self._linebuffer[breakpos:] # Drop any line feeds and anything that precedes them lbreakpos = line.rfind('\r') + 1 - if lbreakpos: + if lbreakpos and lbreakpos != breakpos: line = line[lbreakpos:] - if self.writeline(line): - super(LineFilterProgressHandler, self).write(line) + if self.writeline(filter_color(line)): + super().write(line) def writeline(self, line): return True + class BasicProgressHandler(ProgressHandler): def __init__(self, d, regex=r'(\d+)%', outfile=None): - super(BasicProgressHandler, self).__init__(d, outfile) + super().__init__(d, outfile) self._regex = re.compile(regex) # Send an initial progress event so the bar gets shown self._fire_progress(0) def write(self, string): - percs = self._regex.findall(string) + percs = self._regex.findall(filter_color(string)) if percs: progress = int(percs[-1]) self.update(progress) - super(BasicProgressHandler, self).write(string) + super().write(string) + class OutOfProgressHandler(ProgressHandler): def __init__(self, d, regex, outfile=None): - super(OutOfProgressHandler, self).__init__(d, outfile) + super().__init__(d, outfile) self._regex = re.compile(regex) # Send an initial progress event so the bar gets shown self._fire_progress(0) def write(self, string): - nums = self._regex.findall(string) + nums = self._regex.findall(filter_color(string)) if nums: progress = (float(nums[-1][0]) / float(nums[-1][1])) * 100 self.update(progress) - super(OutOfProgressHandler, self).write(string) + super().write(string) + -class MultiStageProgressReporter(object): +class MultiStageProgressReporter: """ Class which allows reporting progress without the caller having to know where they are in the overall sequence. Useful for tasks made up of python code spread across multiple classes / functions - the progress reporter object can be passed around or stored at the object level and calls - to next_stage() and update() made whereever needed. + to next_stage() and update() made wherever needed. """ def __init__(self, d, stage_weights, debug=False): """ @@ -199,6 +226,7 @@ class MultiStageProgressReporter(object): value is considered to be out of stage_total, otherwise it should be a percentage value from 0 to 100. """ + progress = None if self._stage_total: stage_progress = (float(stage_progress) / self._stage_total) * 100 if self._stage < 0: @@ -207,9 +235,10 @@ class MultiStageProgressReporter(object): progress = self._base_progress + (stage_progress * self._stage_weights[self._stage]) else: progress = self._base_progress - if progress > 100: - progress = 100 - self._fire_progress(progress) + if progress: + if progress > 100: + progress = 100 + self._fire_progress(progress) def finish(self): if self._finished: @@ -230,6 +259,7 @@ class MultiStageProgressReporter(object): out.append('Up to finish: %d' % stage_weight) bb.warn('Stage times:\n %s' % '\n '.join(out)) + class MultiStageProcessProgressReporter(MultiStageProgressReporter): """ Version of MultiStageProgressReporter intended for use with @@ -238,7 +268,7 @@ class MultiStageProcessProgressReporter(MultiStageProgressReporter): def __init__(self, d, processname, stage_weights, debug=False): self._processname = processname self._started = False - MultiStageProgressReporter.__init__(self, d, stage_weights, debug) + super().__init__(d, stage_weights, debug) def start(self): if not self._started: @@ -255,13 +285,14 @@ class MultiStageProcessProgressReporter(MultiStageProgressReporter): MultiStageProgressReporter.finish(self) bb.event.fire(bb.event.ProcessFinished(self._processname), self._data) + class DummyMultiStageProcessProgressReporter(MultiStageProgressReporter): """ MultiStageProcessProgressReporter that takes the calls and does nothing with them (to avoid a bunch of "if progress_reporter:" checks) """ def __init__(self): - MultiStageProcessProgressReporter.__init__(self, "", None, []) + super().__init__(None, []) def _fire_progress(self, taskprogress, rate=None): pass |