summaryrefslogtreecommitdiff
path: root/vendor/github.com/vbauerster/mpb/decor/eta.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/vbauerster/mpb/decor/eta.go')
-rw-r--r--vendor/github.com/vbauerster/mpb/decor/eta.go207
1 files changed, 207 insertions, 0 deletions
diff --git a/vendor/github.com/vbauerster/mpb/decor/eta.go b/vendor/github.com/vbauerster/mpb/decor/eta.go
new file mode 100644
index 000000000..44a1f03ea
--- /dev/null
+++ b/vendor/github.com/vbauerster/mpb/decor/eta.go
@@ -0,0 +1,207 @@
+package decor
+
+import (
+ "fmt"
+ "math"
+ "time"
+
+ "github.com/VividCortex/ewma"
+ "github.com/vbauerster/mpb/internal"
+)
+
+type TimeNormalizer func(time.Duration) time.Duration
+
+// EwmaETA exponential-weighted-moving-average based ETA decorator.
+//
+// `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS]
+//
+// `age` is the previous N samples to average over.
+//
+// `wcc` optional WC config
+func EwmaETA(style int, age float64, wcc ...WC) Decorator {
+ return MovingAverageETA(style, ewma.NewMovingAverage(age), NopNormalizer(), wcc...)
+}
+
+// MovingAverageETA decorator relies on MovingAverage implementation to calculate its average.
+//
+// `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS]
+//
+// `average` available implementations of MovingAverage [ewma.MovingAverage|NewMedian|NewMedianEwma]
+//
+// `normalizer` available implementations are [NopNormalizer|FixedIntervalTimeNormalizer|MaxTolerateTimeNormalizer]
+//
+// `wcc` optional WC config
+func MovingAverageETA(style int, average MovingAverage, normalizer TimeNormalizer, wcc ...WC) Decorator {
+ var wc WC
+ for _, widthConf := range wcc {
+ wc = widthConf
+ }
+ wc.Init()
+ d := &movingAverageETA{
+ WC: wc,
+ style: style,
+ average: average,
+ normalizer: normalizer,
+ }
+ return d
+}
+
+type movingAverageETA struct {
+ WC
+ style int
+ average ewma.MovingAverage
+ completeMsg *string
+ normalizer TimeNormalizer
+}
+
+func (d *movingAverageETA) Decor(st *Statistics) string {
+ if st.Completed && d.completeMsg != nil {
+ return d.FormatMsg(*d.completeMsg)
+ }
+
+ v := internal.Round(d.average.Value())
+ remaining := d.normalizer(time.Duration((st.Total - st.Current) * int64(v)))
+ hours := int64((remaining / time.Hour) % 60)
+ minutes := int64((remaining / time.Minute) % 60)
+ seconds := int64((remaining / time.Second) % 60)
+
+ var str string
+ switch d.style {
+ case ET_STYLE_GO:
+ str = fmt.Sprint(time.Duration(remaining.Seconds()) * time.Second)
+ case ET_STYLE_HHMMSS:
+ str = fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
+ case ET_STYLE_HHMM:
+ str = fmt.Sprintf("%02d:%02d", hours, minutes)
+ case ET_STYLE_MMSS:
+ if hours > 0 {
+ str = fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
+ } else {
+ str = fmt.Sprintf("%02d:%02d", minutes, seconds)
+ }
+ }
+
+ return d.FormatMsg(str)
+}
+
+func (d *movingAverageETA) NextAmount(n int, wdd ...time.Duration) {
+ var workDuration time.Duration
+ for _, wd := range wdd {
+ workDuration = wd
+ }
+ lastItemEstimate := float64(workDuration) / float64(n)
+ if math.IsInf(lastItemEstimate, 0) || math.IsNaN(lastItemEstimate) {
+ return
+ }
+ d.average.Add(lastItemEstimate)
+}
+
+func (d *movingAverageETA) OnCompleteMessage(msg string) {
+ d.completeMsg = &msg
+}
+
+// AverageETA decorator.
+//
+// `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS]
+//
+// `wcc` optional WC config
+func AverageETA(style int, wcc ...WC) Decorator {
+ var wc WC
+ for _, widthConf := range wcc {
+ wc = widthConf
+ }
+ wc.Init()
+ d := &averageETA{
+ WC: wc,
+ style: style,
+ startTime: time.Now(),
+ }
+ return d
+}
+
+type averageETA struct {
+ WC
+ style int
+ startTime time.Time
+ completeMsg *string
+}
+
+func (d *averageETA) Decor(st *Statistics) string {
+ if st.Completed && d.completeMsg != nil {
+ return d.FormatMsg(*d.completeMsg)
+ }
+
+ var str string
+ timeElapsed := time.Since(d.startTime)
+ v := internal.Round(float64(timeElapsed) / float64(st.Current))
+ if math.IsInf(v, 0) || math.IsNaN(v) {
+ v = 0
+ }
+ remaining := time.Duration((st.Total - st.Current) * int64(v))
+ hours := int64((remaining / time.Hour) % 60)
+ minutes := int64((remaining / time.Minute) % 60)
+ seconds := int64((remaining / time.Second) % 60)
+
+ switch d.style {
+ case ET_STYLE_GO:
+ str = fmt.Sprint(time.Duration(remaining.Seconds()) * time.Second)
+ case ET_STYLE_HHMMSS:
+ str = fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
+ case ET_STYLE_HHMM:
+ str = fmt.Sprintf("%02d:%02d", hours, minutes)
+ case ET_STYLE_MMSS:
+ if hours > 0 {
+ str = fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
+ } else {
+ str = fmt.Sprintf("%02d:%02d", minutes, seconds)
+ }
+ }
+
+ return d.FormatMsg(str)
+}
+
+func (d *averageETA) OnCompleteMessage(msg string) {
+ d.completeMsg = &msg
+}
+
+func MaxTolerateTimeNormalizer(maxTolerate time.Duration) TimeNormalizer {
+ var normalized time.Duration
+ var lastCall time.Time
+ return func(remaining time.Duration) time.Duration {
+ if diff := normalized - remaining; diff <= 0 || diff > maxTolerate || remaining < maxTolerate/2 {
+ normalized = remaining
+ lastCall = time.Now()
+ return remaining
+ }
+ normalized -= time.Since(lastCall)
+ lastCall = time.Now()
+ return normalized
+ }
+}
+
+func FixedIntervalTimeNormalizer(updInterval int) TimeNormalizer {
+ var normalized time.Duration
+ var lastCall time.Time
+ var count int
+ return func(remaining time.Duration) time.Duration {
+ if count == 0 || remaining <= time.Duration(15*time.Second) {
+ count = updInterval
+ normalized = remaining
+ lastCall = time.Now()
+ return remaining
+ }
+ count--
+ normalized -= time.Since(lastCall)
+ lastCall = time.Now()
+ if normalized > 0 {
+ return normalized
+ }
+ return remaining
+ }
+}
+
+func NopNormalizer() TimeNormalizer {
+ return func(remaining time.Duration) time.Duration {
+ return remaining
+ }
+}