1#!/usr/bin/env python
2
3from __future__ import print_function
4
5import use_lldb_suite
6import six
7
8import sys
9import time
10
11
12class ProgressBar(object):
13    """ProgressBar class holds the options of the progress bar.
14    The options are:
15        start   State from which start the progress. For example, if start is
16                5 and the end is 10, the progress of this state is 50%
17        end     State in which the progress has terminated.
18        width   --
19        fill    String to use for "filled" used to represent the progress
20        blank   String to use for "filled" used to represent remaining space.
21        format  Format
22        incremental
23    """
24    light_block = six.unichr(0x2591).encode("utf-8")
25    solid_block = six.unichr(0x2588).encode("utf-8")
26    solid_right_arrow = six.unichr(0x25BA).encode("utf-8")
27
28    def __init__(self,
29                 start=0,
30                 end=10,
31                 width=12,
32                 fill=six.unichr(0x25C9).encode("utf-8"),
33                 blank=six.unichr(0x25CC).encode("utf-8"),
34                 marker=six.unichr(0x25CE).encode("utf-8"),
35                 format='[%(fill)s%(marker)s%(blank)s] %(progress)s%%',
36                 incremental=True):
37        super(ProgressBar, self).__init__()
38
39        self.start = start
40        self.end = end
41        self.width = width
42        self.fill = fill
43        self.blank = blank
44        self.marker = marker
45        self.format = format
46        self.incremental = incremental
47        self.step = 100 / float(width)  # fix
48        self.reset()
49
50    def __add__(self, increment):
51        increment = self._get_progress(increment)
52        if 100 > self.progress + increment:
53            self.progress += increment
54        else:
55            self.progress = 100
56        return self
57
58    def complete(self):
59        self.progress = 100
60        return self
61
62    def __str__(self):
63        progressed = int(self.progress / self.step)  # fix
64        fill = progressed * self.fill
65        blank = (self.width - progressed) * self.blank
66        return self.format % {
67            'fill': fill,
68            'blank': blank,
69            'marker': self.marker,
70            'progress': int(
71                self.progress)}
72
73    __repr__ = __str__
74
75    def _get_progress(self, increment):
76        return float(increment * 100) / self.end
77
78    def reset(self):
79        """Resets the current progress to the start point"""
80        self.progress = self._get_progress(self.start)
81        return self
82
83
84class AnimatedProgressBar(ProgressBar):
85    """Extends ProgressBar to allow you to use it straighforward on a script.
86    Accepts an extra keyword argument named `stdout` (by default use sys.stdout)
87    and may be any file-object to which send the progress status.
88    """
89
90    def __init__(self,
91                 start=0,
92                 end=10,
93                 width=12,
94                 fill=six.unichr(0x25C9).encode("utf-8"),
95                 blank=six.unichr(0x25CC).encode("utf-8"),
96                 marker=six.unichr(0x25CE).encode("utf-8"),
97                 format='[%(fill)s%(marker)s%(blank)s] %(progress)s%%',
98                 incremental=True,
99                 stdout=sys.stdout):
100        super(
101            AnimatedProgressBar,
102            self).__init__(
103            start,
104            end,
105            width,
106            fill,
107            blank,
108            marker,
109            format,
110            incremental)
111        self.stdout = stdout
112
113    def show_progress(self):
114        if hasattr(self.stdout, 'isatty') and self.stdout.isatty():
115            self.stdout.write('\r')
116        else:
117            self.stdout.write('\n')
118        self.stdout.write(str(self))
119        self.stdout.flush()
120
121
122class ProgressWithEvents(AnimatedProgressBar):
123    """Extends AnimatedProgressBar to allow you to track a set of events that
124       cause the progress to move. For instance, in a deletion progress bar, you
125       can track files that were nuked and files that the user doesn't have access to
126    """
127
128    def __init__(self,
129                 start=0,
130                 end=10,
131                 width=12,
132                 fill=six.unichr(0x25C9).encode("utf-8"),
133                 blank=six.unichr(0x25CC).encode("utf-8"),
134                 marker=six.unichr(0x25CE).encode("utf-8"),
135                 format='[%(fill)s%(marker)s%(blank)s] %(progress)s%%',
136                 incremental=True,
137                 stdout=sys.stdout):
138        super(
139            ProgressWithEvents,
140            self).__init__(
141            start,
142            end,
143            width,
144            fill,
145            blank,
146            marker,
147            format,
148            incremental,
149            stdout)
150        self.events = {}
151
152    def add_event(self, event):
153        if event in self.events:
154            self.events[event] += 1
155        else:
156            self.events[event] = 1
157
158    def show_progress(self):
159        isatty = hasattr(self.stdout, 'isatty') and self.stdout.isatty()
160        if isatty:
161            self.stdout.write('\r')
162        else:
163            self.stdout.write('\n')
164        self.stdout.write(str(self))
165        if len(self.events) == 0:
166            return
167        self.stdout.write('\n')
168        for key in list(self.events.keys()):
169            self.stdout.write(str(key) + ' = ' + str(self.events[key]) + ' ')
170        if isatty:
171            self.stdout.write('\033[1A')
172        self.stdout.flush()
173
174
175if __name__ == '__main__':
176    p = AnimatedProgressBar(end=200, width=200)
177
178    while True:
179        p + 5
180        p.show_progress()
181        time.sleep(0.3)
182        if p.progress == 100:
183            break
184    print()  # new line
185