Codebase list golang-github-vbauerster-mpb / 8fab02a
Hide internals, provide public setters Vladimir Bauer 9 years ago
2 changed file(s) with 157 addition(s) and 148 deletion(s). Raw diff Collapse all Expand all
+127
-121
bar.go less more
55 "time"
66 )
77
8 var (
9 // Fill is the default character representing completed progress
10 Fill byte = '='
11
12 // Head is the default character that moves when progress is updated
13 Head byte = '>'
14
15 // Empty is the default character that represents the empty progress
16 Empty byte = '-'
17
18 // LeftEnd is the default character in the left most part of the progress indicator
19 LeftEnd byte = '['
20
21 // RightEnd is the default character in the right most part of the progress indicator
22 RightEnd byte = ']'
23
24 // Width is the default width of the progress bar
25 Width = 70
26 )
27
28 // DecoratorFunc is a function that can be prepended and appended to the progress bar
29 type DecoratorFunc func(s *Statistics) string
30
318 type decoratorFuncType uint
329
3310 const (
3512 decoratorPrepend
3613 )
3714
15 // DecoratorFunc is a function that can be prepended and appended to the progress bar
16 type DecoratorFunc func(s *Statistics) string
17
3818 type decorator struct {
3919 kind decoratorFuncType
4020 f DecoratorFunc
4121 }
4222
43 // Bar represents a progress bar
23 // Bar represents a progress Bar
4424 type Bar struct {
45 // total of the total for the progress bar
46 total int
47
48 // LeftEnd is character in the left most part of the progress indicator. Defaults to '['
49 LeftEnd byte
50
51 // RightEnd is character in the right most part of the progress indicator. Defaults to ']'
52 RightEnd byte
53
54 // Fill is the character representing completed progress. Defaults to '='
55 Fill byte
56
57 // Head is the character that moves when progress is updated. Defaults to '>'
58 Head byte
59
60 // Empty is the character that represents the empty progress. Default is '-'
61 Empty byte
62
63 // Width is the width of the progress bar
64 Width int
65
66 Alpha float64
67
68 incrRequestCh chan *incrRequest
69 incrCh chan int
70
25 total int
26 width int
27 alpha float64
28 stopped bool
29
30 fill byte
31 empty byte
32 tip byte
33 leftEnd byte
34 rightEnd byte
35
36 incrCh chan int
7137 redrawRequestCh chan *redrawRequest
72
73 decoratorCh chan *decorator
38 decoratorCh chan *decorator
39 flushedCh chan struct{}
40 stopCh chan struct{}
41 done chan struct{}
7442
7543 timePerItemEstimate time.Duration
76
77 flushedCh chan struct{}
78
79 stopCh chan struct{}
80 done chan struct{}
81
82 stopped bool
8344 }
8445
8546 type Statistics struct {
9152 bufCh chan []byte
9253 }
9354
94 type incrRequest struct {
95 amount int
96 result chan bool
97 }
98
99 // NewBar returns a new progress bar
100 func newBar(total int, wg *sync.WaitGroup) *Bar {
55 func newBar(total, width int, wg *sync.WaitGroup) *Bar {
10156 b := &Bar{
102 Alpha: 0.25,
57 fill: '=',
58 empty: '-',
59 tip: '>',
60 leftEnd: '[',
61 rightEnd: ']',
62 alpha: 0.25,
10363 total: total,
104 Width: Width,
105 LeftEnd: LeftEnd,
106 RightEnd: RightEnd,
107 Head: Head,
108 Fill: Fill,
109 Empty: Empty,
110 incrRequestCh: make(chan *incrRequest),
64 width: width,
65 incrCh: make(chan int),
11166 redrawRequestCh: make(chan *redrawRequest),
11267 decoratorCh: make(chan *decorator),
11368 flushedCh: make(chan struct{}),
11469 stopCh: make(chan struct{}),
11570 done: make(chan struct{}),
116 incrCh: make(chan int),
11771 }
11872 go b.server(wg)
11973 return b
74 }
75
76 // SetWidth sets width of the bar
77 func (b *Bar) SetWidth(n int) *Bar {
78 if n <= 0 {
79 return b
80 }
81 b.width = n
82 return b
83 }
84
85 // SetFill sets character representing completed progress.
86 // Defaults to '='
87 func (b *Bar) SetFill(c byte) *Bar {
88 b.fill = c
89 return b
90 }
91
92 // SetTip sets character representing tip of progress.
93 // Defaults to '>'
94 func (b *Bar) SetTip(c byte) *Bar {
95 b.tip = c
96 return b
97 }
98
99 // SetEmpty sets character representing the empty progress
100 // Defaults to '-'
101 func (b *Bar) SetEmpty(c byte) *Bar {
102 b.empty = c
103 return b
104 }
105
106 // SetLeftEnd sets character representing the left most border
107 // Defaults to '['
108 func (b *Bar) SetLeftEnd(c byte) *Bar {
109 b.leftEnd = c
110 return b
111 }
112
113 // SetRightEnd sets character representing the right most border
114 // Defaults to ']'
115 func (b *Bar) SetRightEnd(c byte) *Bar {
116 b.rightEnd = c
117 return b
118 }
119
120 // SetEtaAlpha sets alfa for exponential-weighted-moving-average ETA estimator
121 // Defaults to 0.25
122 // Normally you shouldn't touch this
123 func (b *Bar) SetEtaAlpha(a float64) *Bar {
124 b.alpha = a
125 return b
126 }
127
128 // String returns the string representation of the bar
129 func (b *Bar) String() string {
130 bufCh := make(chan []byte)
131 b.redrawRequestCh <- &redrawRequest{bufCh}
132 return string(<-bufCh)
133 }
134
135 func (b *Bar) Incr(n int) {
136 if !b.IsCompleted() {
137 b.incrCh <- n
138 }
139 }
140
141 func (b *Bar) Stop() {
142 if !b.stopped {
143 b.stopCh <- struct{}{}
144 b.stopped = true
145 }
146 }
147
148 func (b *Bar) IsCompleted() bool {
149 select {
150 case <-b.done:
151 return true
152 default:
153 return false
154 }
120155 }
121156
122157 func (b *Bar) PrependFunc(f DecoratorFunc) *Bar {
153188 return b
154189 }
155190
156 // String returns the string representation of the bar
157 func (b *Bar) String() string {
158 bufCh := make(chan []byte)
159 b.redrawRequestCh <- &redrawRequest{bufCh}
160 return string(<-bufCh)
161 }
162
163 func (b *Bar) flushed() {
164 b.flushedCh <- struct{}{}
165 }
166
167 func (b *Bar) Incr(n int) {
168 if !b.IsCompleted() {
169 b.incrCh <- n
170 }
171 }
172
173191 func (b *Bar) server(wg *sync.WaitGroup) {
174192 var completed int
175193 blockStartTime := time.Now()
176 buf := make([]byte, b.Width, b.Width+24)
194 buf := make([]byte, b.width, b.width+24)
177195 var appendFuncs []DecoratorFunc
178196 var prependFuncs []DecoratorFunc
179197 var done bool
220238 }
221239 }
222240
223 func (b *Bar) Stop() {
224 if !b.stopped {
225 b.stopCh <- struct{}{}
226 b.stopped = true
227 }
228 }
229
230 func (b *Bar) IsCompleted() bool {
231 select {
232 case <-b.done:
233 return true
234 default:
235 return false
236 }
237 }
238
239241 func (b *Bar) draw(buf []byte, current int, appendFuncs, prependFuncs []DecoratorFunc) []byte {
240 completedWidth := current * b.Width / b.total
242 completedWidth := current * b.width / b.total
241243
242244 for i := 0; i < completedWidth; i++ {
243 buf[i] = b.Fill
244 }
245 for i := completedWidth; i < b.Width; i++ {
246 buf[i] = b.Empty
247 }
248 // set head bit
249 if completedWidth > 0 && completedWidth < b.Width {
250 buf[completedWidth-1] = b.Head
245 buf[i] = b.fill
246 }
247 for i := completedWidth; i < b.width; i++ {
248 buf[i] = b.empty
249 }
250 // set tip bit
251 if completedWidth > 0 && completedWidth < b.width {
252 buf[completedWidth-1] = b.tip
251253 }
252254
253255 // set left and right ends bits
254 buf[0], buf[len(buf)-1] = b.LeftEnd, b.RightEnd
256 buf[0], buf[len(buf)-1] = b.leftEnd, b.rightEnd
255257
256258 s := &Statistics{b.total, current, b.timePerItemEstimate}
257259
270272 return buf
271273 }
272274
275 func (b *Bar) flushed() {
276 b.flushedCh <- struct{}{}
277 }
278
273279 func (b *Bar) updateTimePerItemEstimate(items int, blockStartTime time.Time) {
274280 lastBlockTime := time.Since(blockStartTime)
275281 lastItemEstimate := float64(lastBlockTime) / float64(items)
276 b.timePerItemEstimate = time.Duration((b.Alpha * lastItemEstimate) + (1-b.Alpha)*float64(b.timePerItemEstimate))
277 }
282 b.timePerItemEstimate = time.Duration((b.alpha * lastItemEstimate) + (1-b.alpha)*float64(b.timePerItemEstimate))
283 }
1818
1919 const refreshRate = 60
2020
21 // progress represents the container that renders progress bars
22 type progress struct {
23 // out is the writer to render progress bars to
24 out io.Writer
25
26 // Width is the width of the progress bars
27 // Width int
21 // Progress represents the container that renders Progress bars
22 type Progress struct {
23 out io.Writer
24 width int
25 stopped bool
2826
2927 op chan *operation
3028
31 // new refresh interval to be send over this channel
32 interval chan time.Duration
29 rrChangeReqCh chan time.Duration
3330
3431 wg *sync.WaitGroup
35
36 stopped bool
3732 }
3833
3934 type operation struct {
4338 }
4439
4540 // New returns a new progress bar with defaults
46 func New() *progress {
47 p := &progress{
48 out: os.Stdout,
49 op: make(chan *operation),
50 interval: make(chan time.Duration),
51 wg: new(sync.WaitGroup),
41 func New() *Progress {
42 p := &Progress{
43 out: os.Stdout,
44 width: 70,
45 op: make(chan *operation),
46 rrChangeReqCh: make(chan time.Duration),
47 wg: new(sync.WaitGroup),
5248 }
5349 go p.server()
5450 return p
5551 }
5652
53 func (p *Progress) SetWidth(n int) *Progress {
54 if n <= 0 {
55 return p
56 }
57 p.width = n
58 return p
59 }
60
5761 // SetOut sets underlying writer of progress
5862 // default is os.Stdout
59 func (p *progress) SetOut(w io.Writer) *progress {
63 func (p *Progress) SetOut(w io.Writer) *Progress {
6064 if w == nil {
6165 return p
6266 }
6569 }
6670
6771 // RefreshRate overrides default (30ms) refreshRate value
68 func (p *progress) RefreshRate(d time.Duration) *progress {
69 p.interval <- d
72 func (p *Progress) RefreshRate(d time.Duration) *Progress {
73 p.rrChangeReqCh <- d
7074 return p
7175 }
7276
7377 // AddBar creates a new progress bar and adds to the container
74 func (p *progress) AddBar(total int) *Bar {
78 func (p *Progress) AddBar(total int) *Bar {
7579 p.wg.Add(1)
76 bar := newBar(total, p.wg)
77 // bar.Width = p.Width
80 bar := newBar(total, p.width, p.wg)
7881 p.op <- &operation{barAdd, bar, nil}
7982 return bar
8083 }
8184
82 func (p *progress) RemoveBar(b *Bar) bool {
85 func (p *Progress) RemoveBar(b *Bar) bool {
8386 result := make(chan bool)
8487 p.op <- &operation{barRemove, b, result}
8588 return <-result
8689 }
8790
8891 // WaitAndStop stops listening
89 func (p *progress) WaitAndStop() {
92 func (p *Progress) WaitAndStop() {
9093 if !p.stopped {
9194 // fmt.Fprintln(os.Stderr, "p.WaitAndStop")
9295 p.stopped = true
9699 }
97100
98101 // server monitors underlying channels and renders any progress bars
99 func (p *progress) server() {
102 func (p *Progress) server() {
100103 t := time.NewTicker(refreshRate * time.Millisecond)
101104 bars := make([]*Bar, 0, 4)
102105 lw := uilive.New(p.out)
137140 b.flushed()
138141 }(b)
139142 }
140 case d := <-p.interval:
143 case d := <-p.rrChangeReqCh:
141144 t.Stop()
142145 t = time.NewTicker(d)
143146 }