| 1 | 1 |
|
| 2 | 2 |
import (
|
| 3 | 3 |
"fmt"
|
|
4 |
"os"
|
| 4 | 5 |
"sync"
|
| 5 | 6 |
"time"
|
| 6 | 7 |
)
|
|
| 73 | 74 |
|
| 74 | 75 |
timePerItemEstimate time.Duration
|
| 75 | 76 |
|
| 76 | |
flushedCh chan *sync.WaitGroup
|
|
77 |
flushedCh chan struct{}
|
|
78 |
|
|
79 |
stopCh chan struct{}
|
|
80 |
done chan struct{}
|
|
81 |
|
|
82 |
// wg *sync.WaitGroup
|
| 77 | 83 |
}
|
| 78 | 84 |
|
| 79 | 85 |
type Statistics struct {
|
|
| 91 | 97 |
}
|
| 92 | 98 |
|
| 93 | 99 |
// NewBar returns a new progress bar
|
| 94 | |
func newBar(total int) *Bar {
|
|
100 |
func newBar(total int, wg *sync.WaitGroup) *Bar {
|
| 95 | 101 |
b := &Bar{
|
| 96 | 102 |
Alpha: 0.25,
|
| 97 | 103 |
total: total,
|
|
| 104 | 110 |
incrRequestCh: make(chan *incrRequest),
|
| 105 | 111 |
redrawRequestCh: make(chan *redrawRequest),
|
| 106 | 112 |
decoratorCh: make(chan *decorator),
|
| 107 | |
flushedCh: make(chan *sync.WaitGroup),
|
| 108 | |
}
|
| 109 | |
go b.server()
|
|
113 |
flushedCh: make(chan struct{}),
|
|
114 |
stopCh: make(chan struct{}),
|
|
115 |
done: make(chan struct{}),
|
|
116 |
}
|
|
117 |
go b.server(wg)
|
| 110 | 118 |
return b
|
| 111 | 119 |
}
|
| 112 | 120 |
|
|
| 146 | 154 |
|
| 147 | 155 |
// String returns the string representation of the bar
|
| 148 | 156 |
func (b *Bar) String() string {
|
|
157 |
if b.IsStopped() {
|
|
158 |
return "bar stopped"
|
|
159 |
}
|
| 149 | 160 |
bufCh := make(chan []byte)
|
| 150 | 161 |
b.redrawRequestCh <- &redrawRequest{bufCh}
|
| 151 | 162 |
return string(<-bufCh)
|
| 152 | 163 |
}
|
| 153 | 164 |
|
| 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
|
|
165 |
func (b *Bar) flushed() {
|
|
166 |
if !b.IsStopped() {
|
|
167 |
b.flushedCh <- struct{}{}
|
|
168 |
}
|
| 162 | 169 |
}
|
| 163 | 170 |
|
| 164 | 171 |
func (b *Bar) Incr(n int) bool {
|
|
172 |
if b.IsStopped() {
|
|
173 |
return false
|
|
174 |
}
|
| 165 | 175 |
result := make(chan bool)
|
| 166 | 176 |
b.incrRequestCh <- &incrRequest{n, result}
|
| 167 | 177 |
return <-result
|
| 168 | 178 |
}
|
| 169 | 179 |
|
| 170 | |
func (b *Bar) server() {
|
|
180 |
func (b *Bar) server(wg *sync.WaitGroup) {
|
| 171 | 181 |
var completed int
|
| 172 | 182 |
blockStartTime := time.Now()
|
| 173 | 183 |
buf := make([]byte, b.Width, b.Width+24)
|
| 174 | 184 |
var appendFuncs []DecoratorFunc
|
| 175 | 185 |
var prependFuncs []DecoratorFunc
|
|
186 |
var done bool
|
| 176 | 187 |
for {
|
| 177 | 188 |
select {
|
| 178 | 189 |
case r := <-b.incrRequestCh:
|
| 179 | 190 |
n := completed + r.amount
|
|
191 |
fmt.Fprintf(os.Stderr, "n = %+v\n", n)
|
| 180 | 192 |
if n > b.total {
|
|
193 |
r.result <- false
|
| 181 | 194 |
completed = b.total
|
| 182 | |
r.result <- false
|
| 183 | |
break // breaks out of select, not for
|
| 184 | |
}
|
|
195 |
fmt.Fprintln(os.Stderr, "n > b.total = return false")
|
|
196 |
break // breaks out of select
|
|
197 |
}
|
|
198 |
// r.result <- true
|
| 185 | 199 |
b.updateTimePerItemEstimate(r.amount, blockStartTime)
|
| 186 | 200 |
completed = n
|
| 187 | 201 |
blockStartTime = time.Now()
|
|
202 |
if completed == b.total && !done {
|
|
203 |
fmt.Fprintln(os.Stderr, "completed == b.total")
|
|
204 |
done = true
|
|
205 |
wg.Done()
|
|
206 |
}
|
| 188 | 207 |
r.result <- true
|
| 189 | 208 |
case d := <-b.decoratorCh:
|
| 190 | 209 |
switch d.kind {
|
|
| 194 | 213 |
prependFuncs = append(prependFuncs, d.f)
|
| 195 | 214 |
}
|
| 196 | 215 |
case r := <-b.redrawRequestCh:
|
|
216 |
// fmt.Fprintln(os.Stderr, "redraw")
|
| 197 | 217 |
r.bufCh <- b.draw(buf, completed, appendFuncs, prependFuncs)
|
| 198 | |
case wg := <-b.flushedCh:
|
| 199 | |
if completed == b.total {
|
| 200 | |
close(b.incrRequestCh)
|
|
218 |
// case <-b.flushedCh:
|
|
219 |
// if completed == b.total && !done {
|
|
220 |
// fmt.Fprintln(os.Stderr, "wg.Done")
|
|
221 |
// done = true
|
|
222 |
// wg.Done()
|
|
223 |
// } else {
|
|
224 |
// fmt.Fprintln(os.Stderr, "wg.Done not done")
|
|
225 |
// }
|
|
226 |
case <-b.stopCh:
|
|
227 |
fmt.Fprintln(os.Stderr, "received stop signal")
|
|
228 |
// close(b.incrRequestCh)
|
|
229 |
close(b.done)
|
|
230 |
if !done {
|
|
231 |
done = true
|
| 201 | 232 |
wg.Done()
|
| 202 | |
return
|
| 203 | |
}
|
|
233 |
}
|
|
234 |
// close(b.redrawRequestCh)
|
|
235 |
// close(b.flushedCh)
|
|
236 |
return
|
| 204 | 237 |
}
|
|
238 |
}
|
|
239 |
}
|
|
240 |
|
|
241 |
func (b *Bar) Stop() {
|
|
242 |
if !b.IsStopped() {
|
|
243 |
fmt.Fprintln(os.Stderr, "sending to stopCh")
|
|
244 |
b.stopCh <- struct{}{}
|
|
245 |
} else {
|
|
246 |
fmt.Fprintln(os.Stderr, "Stop: already stopped")
|
|
247 |
}
|
|
248 |
}
|
|
249 |
|
|
250 |
func (b *Bar) IsStopped() bool {
|
|
251 |
select {
|
|
252 |
case <-b.done:
|
|
253 |
return true
|
|
254 |
default:
|
|
255 |
return false
|
| 205 | 256 |
}
|
| 206 | 257 |
}
|
| 207 | 258 |
|