Codebase list golang-github-vbauerster-mpb / 69188da
wait for flush Vladimir Bauer 9 years ago
2 changed file(s) with 90 addition(s) and 42 deletion(s). Raw diff Collapse all Expand all
11
22 import (
33 "fmt"
4 "sync"
45 "time"
56 )
67
6465
6566 Alpha float64
6667
67 currentIncrCh chan int
68 incrRequestCh chan *incrRequest
6869
6970 redrawRequestCh chan *redrawRequest
7071
7172 decoratorCh chan *decorator
7273
7374 timePerItemEstimate time.Duration
75
76 flushedCh chan *sync.WaitGroup
7477 }
7578
7679 type Statistics struct {
7982 }
8083
8184 type redrawRequest struct {
82 bufch chan []byte
85 bufCh chan []byte
86 }
87
88 type incrRequest struct {
89 amount int
90 result chan bool
8391 }
8492
8593 // NewBar returns a new progress bar
86 func NewBar(total int) *Bar {
94 func newBar(total int) *Bar {
8795 b := &Bar{
8896 Alpha: 0.25,
8997 total: total,
93101 Head: Head,
94102 Fill: Fill,
95103 Empty: Empty,
96 currentIncrCh: make(chan int),
104 incrRequestCh: make(chan *incrRequest),
97105 redrawRequestCh: make(chan *redrawRequest),
98106 decoratorCh: make(chan *decorator),
107 flushedCh: make(chan *sync.WaitGroup),
99108 }
100109 go b.server()
101110 return b
102 }
103
104 func (b *Bar) Incr(n int) {
105 b.currentIncrCh <- n
106111 }
107112
108113 func (b *Bar) PrependFunc(f DecoratorFunc) *Bar {
131136 return b
132137 }
133138
139 func (b *Bar) PrependPercentage() *Bar {
140 b.PrependFunc(func(s *Statistics) string {
141 completed := int(100 * float64(s.Completed) / float64(s.Total))
142 return fmt.Sprintf("%3d %%", completed)
143 })
144 return b
145 }
146
134147 // String returns the string representation of the bar
135148 func (b *Bar) String() string {
136 bufch := make(chan []byte)
137 b.redrawRequestCh <- &redrawRequest{bufch}
138 return string(<-bufch)
149 bufCh := make(chan []byte)
150 b.redrawRequestCh <- &redrawRequest{bufCh}
151 return string(<-bufCh)
152 }
153
154 // func (b *Bar) bytes() []byte {
155 // bufch := make(chan []byte)
156 // b.redrawRequestCh <- &redrawRequest{bufch}
157 // return <-bufch
158 // }
159
160 func (b *Bar) flushed(wg *sync.WaitGroup) {
161 b.flushedCh <- wg
162 }
163
164 func (b *Bar) Incr(n int) bool {
165 result := make(chan bool)
166 b.incrRequestCh <- &incrRequest{n, result}
167 return <-result
139168 }
140169
141170 func (b *Bar) server() {
142 var current int
171 var completed int
143172 blockStartTime := time.Now()
144173 buf := make([]byte, b.Width, b.Width+24)
145174 var appendFuncs []DecoratorFunc
146175 var prependFuncs []DecoratorFunc
147176 for {
148177 select {
149 case i := <-b.currentIncrCh:
150 n := current + i
178 case r := <-b.incrRequestCh:
179 n := completed + r.amount
151180 if n > b.total {
152 return
181 completed = b.total
182 r.result <- false
183 break // breaks out of select, not for
153184 }
154 b.updateTimePerItemEstimate(i, blockStartTime)
155 current = n
185 b.updateTimePerItemEstimate(r.amount, blockStartTime)
186 completed = n
156187 blockStartTime = time.Now()
188 r.result <- true
157189 case d := <-b.decoratorCh:
158190 switch d.kind {
159191 case decoratorAppend:
162194 prependFuncs = append(prependFuncs, d.f)
163195 }
164196 case r := <-b.redrawRequestCh:
165 r.bufch <- b.draw(buf, current, appendFuncs, prependFuncs)
197 r.bufCh <- b.draw(buf, completed, appendFuncs, prependFuncs)
198 case wg := <-b.flushedCh:
199 if completed == b.total {
200 close(b.incrRequestCh)
201 wg.Done()
202 return
203 }
166204 }
167205 }
168206 }
33 "fmt"
44 "io"
55 "os"
6 "sync"
67 "time"
78
8 "github.com/gosuri/uilive"
9 "github.com/vbauerster/uilive"
910 )
1011
1112 type opType uint
1213
1314 const (
14 add opType = iota
15 remove
15 barAdd opType = iota
16 barRemove
1617 )
1718
18 const refreshRate = 100
19 const refreshRate = 50
1920
2021 // progress represents the container that renders progress bars
2122 type progress struct {
3132
3233 // new refresh interval to be send over this channel
3334 interval chan time.Duration
35
36 wg *sync.WaitGroup
3437 }
3538
3639 type operation struct {
37 kind opType
38 bar *Bar
39 ok chan bool
40 kind opType
41 bar *Bar
42 result chan bool
4043 }
4144
4245 // New returns a new progress bar with defaults
4649 lw: uilive.New(),
4750 op: make(chan *operation),
4851 interval: make(chan time.Duration),
52 wg: new(sync.WaitGroup),
4953 }
5054 go p.server()
5155 return p
56 }
57
58 // AddBar creates a new progress bar and adds to the container
59 func (p *progress) AddBar(total int) *Bar {
60 p.wg.Add(1)
61 bar := newBar(total)
62 // bar.Width = p.Width
63 p.op <- &operation{barAdd, bar, nil}
64 return bar
65 }
66
67 func (p *progress) RemoveBar(b *Bar) bool {
68 result := make(chan bool)
69 p.op <- &operation{barRemove, b, result}
70 return <-result
5271 }
5372
5473 // RefreshRate overrides default (30ms) refreshRate value
6483 return p
6584 }
6685
67 // AddBar creates a new progress bar and adds to the container
68 func (p *progress) AddBar(total int) *Bar {
69 bar := NewBar(total)
70 // bar.Width = p.Width
71 p.op <- &operation{add, bar, nil}
72 return bar
73 }
74
75 func (p *progress) RemoveBar(b *Bar) bool {
76 result := make(chan bool)
77 p.op <- &operation{remove, b, result}
78 return <-result
79 }
80
8186 // Bypass returns a writer which allows non-buffered data to be written to the underlying output
8287 func (p *progress) Bypass() io.Writer {
8388 return p.lw.Bypass()
8590
8691 // Stop stops listening
8792 func (p *progress) Stop() {
93 p.wg.Wait()
8894 close(p.op)
8995 }
9096
99105 if !ok {
100106 t.Stop()
101107 close(p.interval)
108 p.lw.Stop()
102109 return
103110 }
104111 switch op.kind {
105 case add:
112 case barAdd:
106113 bars = append(bars, op.bar)
107 case remove:
114 case barRemove:
108115 var ok bool
109116 for i, b := range bars {
110117 if b == op.bar {
113120 break
114121 }
115122 }
116 op.ok <- ok
123 op.result <- ok
117124 }
118125 case <-t.C:
119126 for _, b := range bars {
120127 fmt.Fprintln(p.lw, b.String())
121128 }
122129 p.lw.Flush()
130 for _, b := range bars {
131 b.flushed(p.wg)
132 }
123133 case d := <-p.interval:
124134 t.Stop()
125135 t = time.NewTicker(d)