| 10 | 10 |
"time"
|
| 11 | 11 |
"unicode/utf8"
|
| 12 | 12 |
|
| 13 | |
"github.com/vbauerster/mpb/v4/decor"
|
|
13 |
"github.com/vbauerster/mpb/v5/decor"
|
| 14 | 14 |
)
|
| 15 | 15 |
|
| 16 | |
// Filler interface.
|
| 17 | |
// Bar renders by calling Filler's Fill method. You can literally have
|
| 18 | |
// any bar kind, by implementing this interface and passing it to the
|
| 19 | |
// *Progress.Add method.
|
| 20 | |
type Filler interface {
|
|
16 |
// BarFiller interface.
|
|
17 |
// Bar renders itself by calling BarFiller's Fill method. You can
|
|
18 |
// literally have any bar kind, by implementing this interface and
|
|
19 |
// passing it to the *Progress.Add method.
|
|
20 |
type BarFiller interface {
|
| 21 | 21 |
Fill(w io.Writer, width int, stat *decor.Statistics)
|
| 22 | 22 |
}
|
| 23 | 23 |
|
| 24 | |
// FillerFunc is function type adapter to convert function into Filler.
|
| 25 | |
type FillerFunc func(w io.Writer, width int, stat *decor.Statistics)
|
| 26 | |
|
| 27 | |
func (f FillerFunc) Fill(w io.Writer, width int, stat *decor.Statistics) {
|
|
24 |
// BarFillerFunc is function type adapter to convert function into Filler.
|
|
25 |
type BarFillerFunc func(w io.Writer, width int, stat *decor.Statistics)
|
|
26 |
|
|
27 |
func (f BarFillerFunc) Fill(w io.Writer, width int, stat *decor.Statistics) {
|
| 28 | 28 |
f(w, width, stat)
|
| 29 | |
}
|
| 30 | |
|
| 31 | |
// WrapFiller interface.
|
| 32 | |
// If you're implementing custom Filler by wrapping a built-in one,
|
| 33 | |
// it is necessary to implement this interface to retain functionality
|
| 34 | |
// of built-in Filler.
|
| 35 | |
type WrapFiller interface {
|
| 36 | |
Base() Filler
|
| 37 | 29 |
}
|
| 38 | 30 |
|
| 39 | 31 |
// Bar represents a progress Bar.
|
|
| 65 | 57 |
type extFunc func(in io.Reader, tw int, st *decor.Statistics) (out io.Reader, lines int)
|
| 66 | 58 |
|
| 67 | 59 |
type bState struct {
|
| 68 | |
baseF Filler
|
| 69 | |
filler Filler
|
|
60 |
baseF BarFiller
|
|
61 |
filler BarFiller
|
| 70 | 62 |
id int
|
| 71 | 63 |
width int
|
| 72 | 64 |
total int64
|
| 73 | 65 |
current int64
|
|
66 |
lastN int64
|
|
67 |
iterated bool
|
| 74 | 68 |
trimSpace bool
|
| 75 | 69 |
toComplete bool
|
| 76 | 70 |
completeFlushed bool
|
| 77 | 71 |
noPop bool
|
| 78 | 72 |
aDecorators []decor.Decorator
|
| 79 | 73 |
pDecorators []decor.Decorator
|
| 80 | |
amountReceivers []decor.AmountReceiver
|
|
74 |
averageDecorators []decor.AverageDecorator
|
|
75 |
ewmaDecorators []decor.EwmaDecorator
|
| 81 | 76 |
shutdownListeners []decor.ShutdownListener
|
| 82 | |
averageAdjusters []decor.AverageAdjuster
|
| 83 | 77 |
bufP, bufB, bufA *bytes.Buffer
|
| 84 | 78 |
extender extFunc
|
| 85 | 79 |
|
|
| 182 | 176 |
}
|
| 183 | 177 |
}
|
| 184 | 178 |
|
| 185 | |
// AdjustAverageDecorators updates start time of all average decorators.
|
| 186 | |
// Useful for resume-able tasks.
|
| 187 | |
func (b *Bar) AdjustAverageDecorators(startTime time.Time) {
|
| 188 | |
b.operateState <- func(s *bState) {
|
| 189 | |
for _, adjuster := range s.averageAdjusters {
|
| 190 | |
adjuster.AverageAdjust(startTime)
|
| 191 | |
}
|
| 192 | |
}
|
| 193 | |
}
|
| 194 | |
|
| 195 | 179 |
// TraverseDecorators traverses all available decorators and calls cb func on each.
|
| 196 | |
func (b *Bar) TraverseDecorators(cb decor.CBFunc) {
|
|
180 |
func (b *Bar) TraverseDecorators(cb func(decor.Decorator)) {
|
| 197 | 181 |
b.operateState <- func(s *bState) {
|
| 198 | 182 |
for _, decorators := range [...][]decor.Decorator{
|
| 199 | 183 |
s.pDecorators,
|
|
| 207 | 191 |
}
|
| 208 | 192 |
|
| 209 | 193 |
// SetTotal sets total dynamically.
|
| 210 | |
// Set complete to true, to trigger bar complete event now.
|
|
194 |
// If total is less or equal to zero it takes progress' current value.
|
|
195 |
// If complete is true, complete event will be triggered.
|
| 211 | 196 |
func (b *Bar) SetTotal(total int64, complete bool) {
|
| 212 | 197 |
select {
|
| 213 | 198 |
case b.operateState <- func(s *bState) {
|
|
| 226 | 211 |
}
|
| 227 | 212 |
}
|
| 228 | 213 |
|
| 229 | |
// SetCurrent sets progress' current to arbitrary amount.
|
| 230 | |
func (b *Bar) SetCurrent(current int64, wdd ...time.Duration) {
|
| 231 | |
select {
|
| 232 | |
case b.operateState <- func(s *bState) {
|
| 233 | |
for _, ar := range s.amountReceivers {
|
| 234 | |
ar.NextAmount(current-s.current, wdd...)
|
| 235 | |
}
|
|
214 |
// SetCurrent sets progress' current to an arbitrary value.
|
|
215 |
func (b *Bar) SetCurrent(current int64) {
|
|
216 |
select {
|
|
217 |
case b.operateState <- func(s *bState) {
|
|
218 |
s.iterated = true
|
|
219 |
s.lastN = current - s.current
|
| 236 | 220 |
s.current = current
|
| 237 | 221 |
if s.total > 0 && s.current >= s.total {
|
| 238 | 222 |
s.current = s.total
|
|
| 244 | 228 |
}
|
| 245 | 229 |
}
|
| 246 | 230 |
|
| 247 | |
// Increment is a shorthand for b.IncrInt64(1, wdd...).
|
| 248 | |
func (b *Bar) Increment(wdd ...time.Duration) {
|
| 249 | |
b.IncrInt64(1, wdd...)
|
| 250 | |
}
|
| 251 | |
|
| 252 | |
// IncrBy is a shorthand for b.IncrInt64(int64(n), wdd...).
|
| 253 | |
func (b *Bar) IncrBy(n int, wdd ...time.Duration) {
|
| 254 | |
b.IncrInt64(int64(n), wdd...)
|
| 255 | |
}
|
| 256 | |
|
| 257 | |
// IncrInt64 increments progress bar by amount of n. wdd is an optional
|
| 258 | |
// work duration i.e. time.Since(start), which expected to be passed,
|
| 259 | |
// if any ewma based decorator is used.
|
| 260 | |
func (b *Bar) IncrInt64(n int64, wdd ...time.Duration) {
|
| 261 | |
select {
|
| 262 | |
case b.operateState <- func(s *bState) {
|
| 263 | |
for _, ar := range s.amountReceivers {
|
| 264 | |
ar.NextAmount(n, wdd...)
|
| 265 | |
}
|
|
231 |
// Increment is a shorthand for b.IncrInt64(1).
|
|
232 |
func (b *Bar) Increment() {
|
|
233 |
b.IncrInt64(1)
|
|
234 |
}
|
|
235 |
|
|
236 |
// IncrBy is a shorthand for b.IncrInt64(int64(n)).
|
|
237 |
func (b *Bar) IncrBy(n int) {
|
|
238 |
b.IncrInt64(int64(n))
|
|
239 |
}
|
|
240 |
|
|
241 |
// IncrInt64 increments progress by amount of n.
|
|
242 |
func (b *Bar) IncrInt64(n int64) {
|
|
243 |
select {
|
|
244 |
case b.operateState <- func(s *bState) {
|
|
245 |
s.iterated = true
|
|
246 |
s.lastN = n
|
| 266 | 247 |
s.current += n
|
| 267 | 248 |
if s.total > 0 && s.current >= s.total {
|
| 268 | 249 |
s.current = s.total
|
| 269 | 250 |
s.toComplete = true
|
| 270 | 251 |
go b.refreshTillShutdown()
|
|
252 |
}
|
|
253 |
}:
|
|
254 |
case <-b.done:
|
|
255 |
}
|
|
256 |
}
|
|
257 |
|
|
258 |
// DecoratorEwmaUpdate updates all EWMA based decorators. Should be
|
|
259 |
// called on each iteration, because EWMA's unit of measure is an
|
|
260 |
// iteration's taken time. Panics if called before *Bar.Incr... family
|
|
261 |
// methods.
|
|
262 |
func (b *Bar) DecoratorEwmaUpdate(dur time.Duration) {
|
|
263 |
select {
|
|
264 |
case b.operateState <- func(s *bState) {
|
|
265 |
ewmaIterationUpdate(false, s, dur)
|
|
266 |
}:
|
|
267 |
case <-b.done:
|
|
268 |
ewmaIterationUpdate(true, b.cacheState, dur)
|
|
269 |
}
|
|
270 |
}
|
|
271 |
|
|
272 |
// DecoratorAverageAdjust adjusts all average based decorators. Call
|
|
273 |
// if you need to adjust start time of all average based decorators
|
|
274 |
// or after progress resume.
|
|
275 |
func (b *Bar) DecoratorAverageAdjust(start time.Time) {
|
|
276 |
select {
|
|
277 |
case b.operateState <- func(s *bState) {
|
|
278 |
for _, d := range s.averageDecorators {
|
|
279 |
d.AverageAdjust(start)
|
| 271 | 280 |
}
|
| 272 | 281 |
}:
|
| 273 | 282 |
case <-b.done:
|
|
| 367 | 376 |
}
|
| 368 | 377 |
|
| 369 | 378 |
func (b *Bar) subscribeDecorators() {
|
| 370 | |
var amountReceivers []decor.AmountReceiver
|
|
379 |
var averageDecorators []decor.AverageDecorator
|
|
380 |
var ewmaDecorators []decor.EwmaDecorator
|
| 371 | 381 |
var shutdownListeners []decor.ShutdownListener
|
| 372 | |
var averageAdjusters []decor.AverageAdjuster
|
| 373 | 382 |
b.TraverseDecorators(func(d decor.Decorator) {
|
| 374 | |
if d, ok := d.(decor.AmountReceiver); ok {
|
| 375 | |
amountReceivers = append(amountReceivers, d)
|
|
383 |
if d, ok := d.(decor.AverageDecorator); ok {
|
|
384 |
averageDecorators = append(averageDecorators, d)
|
|
385 |
}
|
|
386 |
if d, ok := d.(decor.EwmaDecorator); ok {
|
|
387 |
ewmaDecorators = append(ewmaDecorators, d)
|
| 376 | 388 |
}
|
| 377 | 389 |
if d, ok := d.(decor.ShutdownListener); ok {
|
| 378 | 390 |
shutdownListeners = append(shutdownListeners, d)
|
| 379 | 391 |
}
|
| 380 | |
if d, ok := d.(decor.AverageAdjuster); ok {
|
| 381 | |
averageAdjusters = append(averageAdjusters, d)
|
| 382 | |
}
|
| 383 | 392 |
})
|
| 384 | 393 |
b.operateState <- func(s *bState) {
|
| 385 | |
s.amountReceivers = amountReceivers
|
|
394 |
s.averageDecorators = averageDecorators
|
|
395 |
s.ewmaDecorators = ewmaDecorators
|
| 386 | 396 |
s.shutdownListeners = shutdownListeners
|
| 387 | |
s.averageAdjusters = averageAdjusters
|
| 388 | 397 |
}
|
| 389 | 398 |
}
|
| 390 | 399 |
|
|
| 474 | 483 |
}
|
| 475 | 484 |
return d
|
| 476 | 485 |
}
|
|
486 |
|
|
487 |
func ewmaIterationUpdate(done bool, s *bState, dur time.Duration) {
|
|
488 |
if !done && !s.iterated {
|
|
489 |
panic("increment required before ewma iteration update")
|
|
490 |
} else {
|
|
491 |
s.iterated = false
|
|
492 |
}
|
|
493 |
for _, d := range s.ewmaDecorators {
|
|
494 |
d.EwmaUpdate(s.lastN, dur)
|
|
495 |
}
|
|
496 |
}
|