From c15cd9de5815864acae55870a951991604b5beb8 Mon Sep 17 00:00:00 2001 From: Vladimir Bauer Date: Sun, 14 Jul 2019 10:53:50 +0500 Subject: [PATCH] AdjustAverageDecorators for resume-able tasks --- bar.go | 35 ++++++++++++++++++++++++++++++++++- bar_option.go | 25 +++++-------------------- decor/decorator.go | 3 +++ decor/eta.go | 17 ++++++++++++++++- decor/speed.go | 24 +++++++++++++++++++++++- progress.go | 18 +++++++++++++++++- 6 files changed, 98 insertions(+), 24 deletions(-) diff --git a/bar.go b/bar.go index 7cea8abe..f364b464 100644 --- a/bar.go +++ b/bar.go @@ -75,6 +75,7 @@ type bState struct { noPop bool aDecorators []decor.Decorator pDecorators []decor.Decorator + mDecorators []decor.Decorator amountReceivers []decor.AmountReceiver shutdownListeners []decor.ShutdownListener bufP, bufB, bufA *bytes.Buffer @@ -170,14 +171,46 @@ func (b *Bar) Current() int64 { } // SetRefill sets refill, if supported by underlying Filler. +// Useful for resume-able tasks. func (b *Bar) SetRefill(amount int64) { + type refiller interface { + SetRefill(int64) + } b.operateState <- func(s *bState) { - if f, ok := s.filler.(interface{ SetRefill(int64) }); ok { + if f, ok := s.filler.(refiller); ok { f.SetRefill(amount) } } } +// AdjustAverageDecorators updates start time of all average decorators. +// Useful for resume-able tasks. +func (b *Bar) AdjustAverageDecorators(startTime time.Time) { + type adjustable interface { + AverageAdjust(time.Time) + } + b.UpdateDecorators(func(d decor.Decorator) { + if d, ok := d.(adjustable); ok { + d.AverageAdjust(startTime) + } + }) +} + +// UpdateDecorators general helper func. +func (b *Bar) UpdateDecorators(cb decor.UpdateFunc) { + b.operateState <- func(s *bState) { + for _, decorators := range [...][]decor.Decorator{ + s.pDecorators, + s.aDecorators, + s.mDecorators, + } { + for _, d := range decorators { + cb(d) + } + } + } +} + // SetTotal sets total dynamically. // Set complete to true, to trigger bar complete event now. func (b *Bar) SetTotal(total int64, complete bool) { diff --git a/bar_option.go b/bar_option.go index 5a1e11a3..3887648b 100644 --- a/bar_option.go +++ b/bar_option.go @@ -7,30 +7,15 @@ import ( // BarOption is a function option which changes the default behavior of a bar. type BarOption func(*bState) -type merger interface { - CompoundDecorators() []decor.Decorator -} - -func (s *bState) appendAmountReceiver(d decor.Decorator) { - if ar, ok := d.(decor.AmountReceiver); ok { - s.amountReceivers = append(s.amountReceivers, ar) - } -} - -func (s *bState) appendShutdownListener(d decor.Decorator) { - if sl, ok := d.(decor.ShutdownListener); ok { - s.shutdownListeners = append(s.shutdownListeners, sl) - } +type mergeWrapper interface { + MergeUnwrap() []decor.Decorator } func (s *bState) addDecorators(dest *[]decor.Decorator, decorators ...decor.Decorator) { for _, decorator := range decorators { - s.appendAmountReceiver(decorator) - s.appendShutdownListener(decorator) - if m, ok := decorator.(merger); ok { - dd := m.CompoundDecorators() - s.appendAmountReceiver(dd[0]) - s.appendShutdownListener(dd[0]) + if mw, ok := decorator.(mergeWrapper); ok { + dd := mw.MergeUnwrap() + s.mDecorators = append(s.mDecorators, dd[0]) *dest = append(*dest, dd[1:]...) } *dest = append(*dest, decorator) diff --git a/decor/decorator.go b/decor/decorator.go index 877de533..92c8e498 100644 --- a/decor/decorator.go +++ b/decor/decorator.go @@ -93,6 +93,9 @@ type ShutdownListener interface { Shutdown() } +// UpdateFunc convenience func type +type UpdateFunc func(Decorator) + // Global convenience shortcuts var ( WCSyncWidth = WC{C: DSyncWidth} diff --git a/decor/eta.go b/decor/eta.go index 898a2c1f..ff911d82 100644 --- a/decor/eta.go +++ b/decor/eta.go @@ -120,6 +120,17 @@ func (d *movingAverageETA) OnCompleteMessage(msg string) { // // `wcc` optional WC config func AverageETA(style TimeStyle, wcc ...WC) Decorator { + return NewAverageETA(style, time.Now(), wcc...) +} + +// NewAverageETA decorator with user provided start time. +// +// `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS] +// +// `startTime` start time +// +// `wcc` optional WC config +func NewAverageETA(style TimeStyle, startTime time.Time, wcc ...WC) Decorator { var wc WC for _, widthConf := range wcc { wc = widthConf @@ -128,7 +139,7 @@ func AverageETA(style TimeStyle, wcc ...WC) Decorator { d := &averageETA{ WC: wc, style: style, - startTime: time.Now(), + startTime: startTime, } return d } @@ -178,6 +189,10 @@ func (d *averageETA) OnCompleteMessage(msg string) { d.completeMsg = &msg } +func (d *averageETA) AverageAdjust(startTime time.Time) { + d.startTime = startTime +} + func MaxTolerateTimeNormalizer(maxTolerate time.Duration) TimeNormalizer { var normalized time.Duration var lastCall time.Time diff --git a/decor/speed.go b/decor/speed.go index 17ada80b..e8839bd1 100644 --- a/decor/speed.go +++ b/decor/speed.go @@ -220,6 +220,24 @@ func (d *movingAverageSpeed) OnCompleteMessage(msg string) { // // "%.1f" = "1.0MiB/s" or "% .1f" = "1.0 MiB/s" func AverageSpeed(unit int, unitFormat string, wcc ...WC) Decorator { + return NewAverageSpeed(unit, unitFormat, time.Now(), wcc...) +} + +// NewAverageSpeed decorator with dynamic unit measure adjustment and +// user provided start time. +// +// `unit` one of [0|UnitKiB|UnitKB] zero for no unit +// +// `unitFormat` printf compatible verb for value, like "%f" or "%d" +// +// `startTime` start time +// +// `wcc` optional WC config +// +// unitFormat example if UnitKiB is chosen: +// +// "%.1f" = "1.0MiB/s" or "% .1f" = "1.0 MiB/s" +func NewAverageSpeed(unit int, unitFormat string, startTime time.Time, wcc ...WC) Decorator { var wc WC for _, widthConf := range wcc { wc = widthConf @@ -229,7 +247,7 @@ func AverageSpeed(unit int, unitFormat string, wcc ...WC) Decorator { WC: wc, unit: unit, unitFormat: unitFormat, - startTime: time.Now(), + startTime: startTime, } return d } @@ -269,3 +287,7 @@ func (d *averageSpeed) Decor(st *Statistics) string { func (d *averageSpeed) OnCompleteMessage(msg string) { d.completeMsg = &msg } + +func (d *averageSpeed) AverageAdjust(startTime time.Time) { + d.startTime = startTime +} diff --git a/progress.go b/progress.go index ee537a51..6bd49e12 100644 --- a/progress.go +++ b/progress.go @@ -11,6 +11,7 @@ import ( "time" "github.com/vbauerster/mpb/v4/cwriter" + "github.com/vbauerster/mpb/v4/decor" ) const ( @@ -143,7 +144,22 @@ func (p *Progress) Add(total int64, filler Filler, options ...BarOption) *Bar { ps.idCount++ result <- bar }: - return <-result + var amountReceivers []decor.AmountReceiver + var shutdownListeners []decor.ShutdownListener + bar := <-result + bar.UpdateDecorators(func(d decor.Decorator) { + if d, ok := d.(decor.AmountReceiver); ok { + amountReceivers = append(amountReceivers, d) + } + if d, ok := d.(decor.ShutdownListener); ok { + shutdownListeners = append(shutdownListeners, d) + } + }) + bar.operateState <- func(s *bState) { + s.amountReceivers = amountReceivers + s.shutdownListeners = shutdownListeners + } + return bar case <-p.done: p.bwg.Done() return nil