| 41 | 41 |
flushedCh chan struct{}
|
| 42 | 42 |
stopCh chan struct{}
|
| 43 | 43 |
done chan struct{}
|
| 44 | |
|
| 45 | |
timePerItemEstimate time.Duration
|
| 46 | 44 |
}
|
| 47 | 45 |
|
| 48 | 46 |
type Statistics struct {
|
| 49 | |
Total, Completed int
|
| 50 | |
TimePerItemEstimate time.Duration
|
|
47 |
Total, Current int
|
|
48 |
TimeElapsed, TimePerItemEstimate time.Duration
|
| 51 | 49 |
}
|
| 52 | 50 |
|
| 53 | 51 |
func (s *Statistics) eta() time.Duration {
|
| 54 | |
return time.Duration(s.Total-s.Completed) * s.TimePerItemEstimate
|
|
52 |
return time.Duration(s.Total-s.Current) * s.TimePerItemEstimate
|
| 55 | 53 |
}
|
| 56 | 54 |
|
| 57 | 55 |
func newBar(total, width int, wg *sync.WaitGroup) *Bar {
|
|
| 190 | 188 |
return b
|
| 191 | 189 |
}
|
| 192 | 190 |
|
|
191 |
func (b *Bar) PrependElapsed(padding int) *Bar {
|
|
192 |
layout := "%" + strconv.Itoa(padding) + "s"
|
|
193 |
b.PrependFunc(func(s *Statistics) string {
|
|
194 |
return fmt.Sprintf(layout, time.Duration(s.TimeElapsed.Seconds())*time.Second)
|
|
195 |
})
|
|
196 |
return b
|
|
197 |
}
|
|
198 |
|
|
199 |
func (b *Bar) AppendElapsed() *Bar {
|
|
200 |
b.AppendFunc(func(s *Statistics) string {
|
|
201 |
return fmt.Sprint(time.Duration(s.TimeElapsed.Seconds()) * time.Second)
|
|
202 |
})
|
|
203 |
return b
|
|
204 |
}
|
|
205 |
|
| 193 | 206 |
func (b *Bar) AppendPercentage() *Bar {
|
| 194 | 207 |
b.AppendFunc(func(s *Statistics) string {
|
| 195 | |
completed := int(100 * float64(s.Completed) / float64(s.Total))
|
|
208 |
completed := int(100 * float64(s.Current) / float64(s.Total))
|
| 196 | 209 |
return fmt.Sprintf("%3d %%", completed)
|
| 197 | 210 |
})
|
| 198 | 211 |
return b
|
|
| 201 | 214 |
func (b *Bar) PrependPercentage(padding int) *Bar {
|
| 202 | 215 |
layout := "%" + strconv.Itoa(padding) + "d %%"
|
| 203 | 216 |
b.PrependFunc(func(s *Statistics) string {
|
| 204 | |
completed := int(100 * float64(s.Completed) / float64(s.Total))
|
|
217 |
completed := int(100 * float64(s.Current) / float64(s.Total))
|
| 205 | 218 |
return fmt.Sprintf(layout, completed)
|
| 206 | 219 |
})
|
| 207 | 220 |
return b
|
| 208 | 221 |
}
|
| 209 | 222 |
|
| 210 | 223 |
func (b *Bar) server(wg *sync.WaitGroup) {
|
| 211 | |
var completed int
|
| 212 | |
blockStartTime := time.Now()
|
|
224 |
timeStarted := time.Now()
|
|
225 |
blockStartTime := timeStarted
|
| 213 | 226 |
buf := make([]byte, b.width, b.width+24)
|
|
227 |
var tpie time.Duration
|
|
228 |
var timeElapsed time.Duration
|
| 214 | 229 |
var appendFuncs []DecoratorFunc
|
| 215 | 230 |
var prependFuncs []DecoratorFunc
|
| 216 | 231 |
var done bool
|
|
232 |
var current int
|
| 217 | 233 |
for {
|
| 218 | 234 |
select {
|
| 219 | 235 |
case i := <-b.incrCh:
|
| 220 | |
n := completed + i
|
|
236 |
n := current + i
|
| 221 | 237 |
// fmt.Fprintf(os.Stderr, "n = %+v\n", n)
|
| 222 | 238 |
if n > b.total {
|
| 223 | |
completed = b.total
|
|
239 |
current = b.total
|
| 224 | 240 |
done = true
|
| 225 | 241 |
break
|
| 226 | 242 |
}
|
| 227 | |
b.updateTimePerItemEstimate(i, blockStartTime)
|
| 228 | |
completed = n
|
| 229 | |
if completed == b.total && !done {
|
|
243 |
timeElapsed = time.Since(timeStarted)
|
|
244 |
tpie = calcTimePerItemEstimate(tpie, blockStartTime, b.alpha, i)
|
|
245 |
blockStartTime = time.Now()
|
|
246 |
current = n
|
|
247 |
if current == b.total && !done {
|
| 230 | 248 |
done = true
|
| 231 | 249 |
}
|
| 232 | |
blockStartTime = time.Now()
|
| 233 | 250 |
case d := <-b.decoratorCh:
|
| 234 | 251 |
switch d.kind {
|
| 235 | 252 |
case decoratorAppend:
|
|
| 238 | 255 |
prependFuncs = append(prependFuncs, d.f)
|
| 239 | 256 |
}
|
| 240 | 257 |
case respCh := <-b.redrawReqCh:
|
| 241 | |
respCh <- b.draw(buf, completed, appendFuncs, prependFuncs)
|
|
258 |
stat := &Statistics{b.total, current, timeElapsed, tpie}
|
|
259 |
respCh <- b.draw(stat, buf, appendFuncs, prependFuncs)
|
| 242 | 260 |
case respCh := <-b.progressReqCh:
|
| 243 | |
respCh <- int(100 * float64(completed) / float64(b.total))
|
|
261 |
respCh <- int(100 * float64(current) / float64(b.total))
|
| 244 | 262 |
case <-b.flushedCh:
|
| 245 | 263 |
if done && !b.IsCompleted() {
|
| 246 | 264 |
// fmt.Fprintln(os.Stderr, "flushedCh: wg.Done")
|
|
| 259 | 277 |
}
|
| 260 | 278 |
}
|
| 261 | 279 |
|
| 262 | |
func (b *Bar) draw(buf []byte, current int, appendFuncs, prependFuncs []DecoratorFunc) []byte {
|
| 263 | |
completedWidth := current * b.width / b.total
|
|
280 |
func (b *Bar) draw(stat *Statistics, buf []byte, appendFuncs, prependFuncs []DecoratorFunc) []byte {
|
|
281 |
completedWidth := stat.Current * b.width / b.total
|
| 264 | 282 |
|
| 265 | 283 |
for i := 0; i < completedWidth; i++ {
|
| 266 | 284 |
buf[i] = b.fill
|
|
| 276 | 294 |
// set left and right ends bits
|
| 277 | 295 |
buf[0], buf[len(buf)-1] = b.leftEnd, b.rightEnd
|
| 278 | 296 |
|
| 279 | |
s := &Statistics{b.total, current, b.timePerItemEstimate}
|
| 280 | |
|
| 281 | 297 |
// render append functions to the right of the bar
|
| 282 | 298 |
for _, f := range appendFuncs {
|
| 283 | 299 |
buf = append(buf, ' ')
|
| 284 | |
buf = append(buf, []byte(f(s))...)
|
|
300 |
buf = append(buf, []byte(f(stat))...)
|
| 285 | 301 |
}
|
| 286 | 302 |
|
| 287 | 303 |
// render prepend functions to the left of the bar
|
| 288 | 304 |
for _, f := range prependFuncs {
|
| 289 | |
args := []byte(f(s))
|
|
305 |
args := []byte(f(stat))
|
| 290 | 306 |
args = append(args, ' ')
|
| 291 | 307 |
buf = append(args, buf...)
|
| 292 | 308 |
}
|
| 293 | 309 |
return buf
|
| 294 | 310 |
}
|
| 295 | 311 |
|
| 296 | |
func (b *Bar) updateTimePerItemEstimate(items int, blockStartTime time.Time) {
|
|
312 |
func calcTimePerItemEstimate(tpie time.Duration, blockStartTime time.Time, alpha float64, items int) time.Duration {
|
| 297 | 313 |
lastBlockTime := time.Since(blockStartTime)
|
| 298 | 314 |
lastItemEstimate := float64(lastBlockTime) / float64(items)
|
| 299 | |
b.timePerItemEstimate = time.Duration((b.alpha * lastItemEstimate) + (1-b.alpha)*float64(b.timePerItemEstimate))
|
|
315 |
return time.Duration((alpha * lastItemEstimate) + (1-alpha)*float64(tpie))
|
| 300 | 316 |
}
|
| 301 | 317 |
|
| 302 | 318 |
func (b *Bar) progress() int {
|