pax_global_header00006660000000000000000000000064141727220050014512gustar00rootroot0000000000000052 comment=fbeaf867830cc088065f0014763f0c3cc974287c mpb-7.3.2/000077500000000000000000000000001417272200500123015ustar00rootroot00000000000000mpb-7.3.2/.github/000077500000000000000000000000001417272200500136415ustar00rootroot00000000000000mpb-7.3.2/.github/workflows/000077500000000000000000000000001417272200500156765ustar00rootroot00000000000000mpb-7.3.2/.github/workflows/test.yml000066400000000000000000000015521417272200500174030ustar00rootroot00000000000000name: Test on: [push, pull_request] jobs: test: strategy: matrix: go-version: [1.16, 1.17] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - name: Setup Go uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@v2 - uses: actions/cache@v2 with: # In order: # * Module download cache # * Build cache (Linux) # * Build cache (Mac) # * Build cache (Windows) path: | ~/go/pkg/mod ~/.cache/go-build ~/Library/Caches/go-build %LocalAppData%\go-build key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - name: Test run: go test -race ./... mpb-7.3.2/.gitignore000066400000000000000000000001731417272200500142720ustar00rootroot00000000000000# Test binary, build with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out mpb-7.3.2/README.md000066400000000000000000000101411417272200500135550ustar00rootroot00000000000000# Multi Progress Bar [![GoDoc](https://pkg.go.dev/badge/github.com/vbauerster/mpb)](https://pkg.go.dev/github.com/vbauerster/mpb/v7) [![Test status](https://github.com/vbauerster/mpb/actions/workflows/test.yml/badge.svg)](https://github.com/vbauerster/mpb/actions/workflows/test.yml) [![Donate with PayPal](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/vbauerster) **mpb** is a Go lib for rendering progress bars in terminal applications. ## Features - **Multiple Bars**: Multiple progress bars are supported - **Dynamic Total**: Set total while bar is running - **Dynamic Add/Remove**: Dynamically add or remove bars - **Cancellation**: Cancel whole rendering process - **Predefined Decorators**: Elapsed time, [ewma](https://github.com/VividCortex/ewma) based ETA, Percentage, Bytes counter - **Decorator's width sync**: Synchronized decorator's width among multiple bars ## Usage #### [Rendering single bar](_examples/singleBar/main.go) ```go package main import ( "math/rand" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { // initialize progress container, with custom width p := mpb.New(mpb.WithWidth(64)) total := 100 name := "Single Bar:" // create a single bar, which will inherit container's width bar := p.New(int64(total), // BarFillerBuilder with custom style mpb.BarStyle().Lbound("╢").Filler("▌").Tip("▌").Padding("░").Rbound("╟"), mpb.PrependDecorators( // display our name with one space on the right decor.Name(name, decor.WC{W: len(name) + 1, C: decor.DidentRight}), // replace ETA decorator with "done" message, OnComplete event decor.OnComplete( decor.AverageETA(decor.ET_STYLE_GO, decor.WC{W: 4}), "done", ), ), mpb.AppendDecorators(decor.Percentage()), ) // simulating some work max := 100 * time.Millisecond for i := 0; i < total; i++ { time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) bar.Increment() } // wait for our bar to complete and flush p.Wait() } ``` #### [Rendering multiple bars](_examples/multiBars/main.go) ```go var wg sync.WaitGroup // passed wg will be accounted at p.Wait() call p := mpb.New(mpb.WithWaitGroup(&wg)) total, numBars := 100, 3 wg.Add(numBars) for i := 0; i < numBars; i++ { name := fmt.Sprintf("Bar#%d:", i) bar := p.AddBar(int64(total), mpb.PrependDecorators( // simple name decorator decor.Name(name), // decor.DSyncWidth bit enables column width synchronization decor.Percentage(decor.WCSyncSpace), ), mpb.AppendDecorators( // replace ETA decorator with "done" message, OnComplete event decor.OnComplete( // ETA decorator with ewma age of 60 decor.EwmaETA(decor.ET_STYLE_GO, 60, decor.WCSyncWidth), "done", ), ), ) // simulating some work go func() { defer wg.Done() rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 100 * time.Millisecond for i := 0; i < total; i++ { // start variable is solely for EWMA calculation // EWMA's unit of measure is an iteration's duration start := time.Now() time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() // we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract bar.DecoratorEwmaUpdate(time.Since(start)) } }() } // wait for passed wg and for all bars to complete and flush p.Wait() ``` #### [Dynamic total](_examples/dynTotal/main.go) ![dynamic total](_svg/godEMrCZmJkHYH1X9dN4Nm0U7.svg) #### [Complex example](_examples/complex/main.go) ![complex](_svg/wHzf1M7sd7B3zVa2scBMnjqRf.svg) #### [Bytes counters](_examples/io/main.go) ![byte counters](_svg/hIpTa3A5rQz65ssiVuRJu87X6.svg) mpb-7.3.2/UNLICENSE000066400000000000000000000022731417272200500135550ustar00rootroot00000000000000This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to mpb-7.3.2/_examples/000077500000000000000000000000001417272200500142565ustar00rootroot00000000000000mpb-7.3.2/_examples/.gitignore000066400000000000000000000000071417272200500162430ustar00rootroot00000000000000go.sum mpb-7.3.2/_examples/barExtender/000077500000000000000000000000001417272200500165215ustar00rootroot00000000000000mpb-7.3.2/_examples/barExtender/go.mod000066400000000000000000000001551417272200500176300ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/barExtender go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/barExtender/main.go000066400000000000000000000031161417272200500177750ustar00rootroot00000000000000package main import ( "fmt" "io" "math/rand" "sync" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { var wg sync.WaitGroup // passed wg will be accounted at p.Wait() call p := mpb.New(mpb.WithWaitGroup(&wg)) total, numBars := 100, 3 wg.Add(numBars) for i := 0; i < numBars; i++ { name := fmt.Sprintf("Bar#%d:", i) efn := func(w io.Writer, _ int, s decor.Statistics) { if s.Completed { fmt.Fprintf(w, "Bar id: %d has been completed\n", s.ID) } } bar := p.AddBar(int64(total), mpb.BarExtender(mpb.BarFillerFunc(efn)), mpb.PrependDecorators( // simple name decorator decor.Name(name), // decor.DSyncWidth bit enables column width synchronization decor.Percentage(decor.WCSyncSpace), ), mpb.AppendDecorators( // replace ETA decorator with "done" message, OnComplete event decor.OnComplete( // ETA decorator with ewma age of 60 decor.EwmaETA(decor.ET_STYLE_GO, 60), "done", ), ), ) // simulating some work go func() { defer wg.Done() rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 100 * time.Millisecond for i := 0; i < total; i++ { // start variable is solely for EWMA calculation // EWMA's unit of measure is an iteration's duration start := time.Now() time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() // since EWMA based decorator is used, DecoratorEwmaUpdate should be called bar.DecoratorEwmaUpdate(time.Since(start)) } }() } // wait for passed wg and for all bars to complete and flush p.Wait() } mpb-7.3.2/_examples/cancel/000077500000000000000000000000001417272200500155035ustar00rootroot00000000000000mpb-7.3.2/_examples/cancel/go.mod000066400000000000000000000001501417272200500166050ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/cancel go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/cancel/main.go000066400000000000000000000025401417272200500167570ustar00rootroot00000000000000package main import ( "context" "fmt" "math/rand" "sync" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() var wg sync.WaitGroup // passed wg will be accounted at p.Wait() call p := mpb.NewWithContext(ctx, mpb.WithWaitGroup(&wg)) total := 300 numBars := 3 wg.Add(numBars) for i := 0; i < numBars; i++ { name := fmt.Sprintf("Bar#%d:", i) bar := p.AddBar(int64(total), mpb.PrependDecorators( decor.Name(name), decor.EwmaETA(decor.ET_STYLE_GO, 60, decor.WCSyncSpace), ), mpb.AppendDecorators( // note that OnComplete will not be fired, because of cancel decor.OnComplete(decor.Percentage(decor.WC{W: 5}), "done"), ), ) go func() { defer wg.Done() rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 100 * time.Millisecond for !bar.Completed() { // start variable is solely for EWMA calculation // EWMA's unit of measure is an iteration's duration start := time.Now() time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() // since EWMA based decorator is used, DecoratorEwmaUpdate should be called bar.DecoratorEwmaUpdate(time.Since(start)) } }() } // wait for passed wg and for all bars to complete and flush p.Wait() } mpb-7.3.2/_examples/complex/000077500000000000000000000000001417272200500157255ustar00rootroot00000000000000mpb-7.3.2/_examples/complex/go.mod000066400000000000000000000001511417272200500170300ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/complex go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/complex/main.go000066400000000000000000000044221417272200500172020ustar00rootroot00000000000000package main import ( "fmt" "math/rand" "sync" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func init() { rand.Seed(time.Now().UnixNano()) } func main() { doneWg := new(sync.WaitGroup) // passed doneWg will be accounted at p.Wait() call p := mpb.New(mpb.WithWaitGroup(doneWg)) numBars := 4 var bars []*mpb.Bar var downloadWgg []*sync.WaitGroup for i := 0; i < numBars; i++ { wg := new(sync.WaitGroup) wg.Add(1) downloadWgg = append(downloadWgg, wg) task := fmt.Sprintf("Task#%02d:", i) job := "downloading" b := p.AddBar(rand.Int63n(201)+100, mpb.PrependDecorators( decor.Name(task, decor.WC{W: len(task) + 1, C: decor.DidentRight}), decor.Name(job, decor.WCSyncSpaceR), decor.CountersNoUnit("%d / %d", decor.WCSyncWidth), ), mpb.AppendDecorators(decor.Percentage(decor.WC{W: 5})), ) go newTask(wg, b, i+1) bars = append(bars, b) } for i := 0; i < numBars; i++ { doneWg.Add(1) i := i go func() { task := fmt.Sprintf("Task#%02d:", i) // ANSI escape sequences are not supported on Windows OS job := "\x1b[31;1;4mつのだ☆HIRO\x1b[0m" // preparing delayed bars b := p.AddBar(rand.Int63n(101)+100, mpb.BarQueueAfter(bars[i]), mpb.BarFillerClearOnComplete(), mpb.PrependDecorators( decor.Name(task, decor.WC{W: len(task) + 1, C: decor.DidentRight}), decor.OnComplete(decor.Name(job, decor.WCSyncSpaceR), "done!"), decor.OnComplete(decor.EwmaETA(decor.ET_STYLE_MMSS, 0, decor.WCSyncWidth), ""), ), mpb.AppendDecorators( decor.OnComplete(decor.Percentage(decor.WC{W: 5}), ""), ), ) // waiting for download to complete, before starting install job downloadWgg[i].Wait() go newTask(doneWg, b, numBars-i) }() } // wait for passed doneWg and for all bars to complete and flush p.Wait() } func newTask(wg *sync.WaitGroup, bar *mpb.Bar, incrBy int) { defer wg.Done() max := 100 * time.Millisecond for !bar.Completed() { // start variable is solely for EWMA calculation // EWMA's unit of measure is an iteration's duration start := time.Now() time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) bar.IncrBy(incrBy) // we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract bar.DecoratorEwmaUpdate(time.Since(start)) } } mpb-7.3.2/_examples/decoratorsOnTop/000077500000000000000000000000001417272200500174035ustar00rootroot00000000000000mpb-7.3.2/_examples/decoratorsOnTop/go.mod000066400000000000000000000001611417272200500205070ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/decoratorsOnTop go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/decoratorsOnTop/main.go000066400000000000000000000020071417272200500206550ustar00rootroot00000000000000package main import ( "io" "math/rand" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { p := mpb.New() total := 100 bar := p.New(int64(total), mpb.NopStyle(), // make main bar style nop, so there are just decorators mpb.BarExtender(extended(mpb.BarStyle())), // extend wtih normal bar on the next line mpb.PrependDecorators( decor.Name("Percentage: "), decor.NewPercentage("%d"), ), mpb.AppendDecorators( decor.Name("ETA: "), decor.OnComplete( decor.AverageETA(decor.ET_STYLE_GO), "done", ), ), ) // simulating some work max := 100 * time.Millisecond for i := 0; i < total; i++ { time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) bar.Increment() } // wait for our bar to complete and flush p.Wait() } func extended(builder mpb.BarFillerBuilder) mpb.BarFiller { filler := builder.Build() return mpb.BarFillerFunc(func(w io.Writer, reqWidth int, st decor.Statistics) { filler.Fill(w, reqWidth, st) w.Write([]byte("\n")) }) } mpb-7.3.2/_examples/differentWidth/000077500000000000000000000000001417272200500172245ustar00rootroot00000000000000mpb-7.3.2/_examples/differentWidth/go.mod000066400000000000000000000001601417272200500203270ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/differentWidth go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/differentWidth/main.go000066400000000000000000000027741417272200500205110ustar00rootroot00000000000000package main import ( "fmt" "math/rand" "sync" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { var wg sync.WaitGroup // passed wg will be accounted at p.Wait() call p := mpb.New( mpb.WithWaitGroup(&wg), mpb.WithWidth(60), ) total, numBars := 100, 3 wg.Add(numBars) for i := 0; i < numBars; i++ { name := fmt.Sprintf("Bar#%d:", i) bar := p.AddBar(int64(total), // set BarWidth 40 for bar 1 and 2 mpb.BarOptional(mpb.BarWidth(40), i > 0), mpb.PrependDecorators( // simple name decorator decor.Name(name), // decor.DSyncWidth bit enables column width synchronization decor.Percentage(decor.WCSyncSpace), ), mpb.AppendDecorators( // replace ETA decorator with "done" message, OnComplete event decor.OnComplete( // ETA decorator with ewma age of 60 decor.EwmaETA(decor.ET_STYLE_GO, 60), "done", ), ), ) // simulating some work go func() { defer wg.Done() rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 100 * time.Millisecond for i := 0; i < total; i++ { // start variable is solely for EWMA calculation // EWMA's unit of measure is an iteration's duration start := time.Now() time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() // we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract bar.DecoratorEwmaUpdate(time.Since(start)) } }() } // wait for passed wg and for all bars to complete and flush p.Wait() } mpb-7.3.2/_examples/dynTotal/000077500000000000000000000000001417272200500160545ustar00rootroot00000000000000mpb-7.3.2/_examples/dynTotal/go.mod000066400000000000000000000001521417272200500171600ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/dynTotal go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/dynTotal/main.go000066400000000000000000000021641417272200500173320ustar00rootroot00000000000000package main import ( "io" "math/rand" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func init() { rand.Seed(time.Now().UnixNano()) } func main() { p := mpb.New(mpb.WithWidth(64)) var total int64 // new bar with 'trigger complete event' disabled, because total is zero bar := p.AddBar(total, mpb.PrependDecorators(decor.Counters(decor.UnitKiB, "% .1f / % .1f")), mpb.AppendDecorators(decor.Percentage()), ) maxSleep := 100 * time.Millisecond read := makeStream(200) for { n, err := read() total += int64(n) if err == io.EOF { break } // while total is unknown, // set it to a positive number which is greater than current total, // to make sure no complete event is triggered by next IncrBy call. bar.SetTotal(total+2048, false) bar.IncrBy(n) time.Sleep(time.Duration(rand.Intn(10)+1) * maxSleep / 10) } // force bar complete event, note true flag bar.SetTotal(total, true) p.Wait() } func makeStream(limit int) func() (int, error) { return func() (int, error) { if limit <= 0 { return 0, io.EOF } limit-- return rand.Intn(1024) + 1, nil } } mpb-7.3.2/_examples/io/000077500000000000000000000000001417272200500146655ustar00rootroot00000000000000mpb-7.3.2/_examples/io/go.mod000066400000000000000000000001441417272200500157720ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/io go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/io/main.go000066400000000000000000000014111417272200500161350ustar00rootroot00000000000000package main import ( "crypto/rand" "io" "io/ioutil" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { var total int64 = 1024 * 1024 * 500 reader := io.LimitReader(rand.Reader, total) p := mpb.New( mpb.WithWidth(60), mpb.WithRefreshRate(180*time.Millisecond), ) bar := p.New(total, mpb.BarStyle().Rbound("|"), mpb.PrependDecorators( decor.CountersKibiByte("% .2f / % .2f"), ), mpb.AppendDecorators( decor.EwmaETA(decor.ET_STYLE_GO, 90), decor.Name(" ] "), decor.EwmaSpeed(decor.UnitKiB, "% .2f", 60), ), ) // create proxy reader proxyReader := bar.ProxyReader(reader) defer proxyReader.Close() // copy from proxyReader, ignoring errors io.Copy(ioutil.Discard, proxyReader) p.Wait() } mpb-7.3.2/_examples/merge/000077500000000000000000000000001417272200500153555ustar00rootroot00000000000000mpb-7.3.2/_examples/merge/go.mod000066400000000000000000000001471417272200500164650ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/merge go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/merge/main.go000066400000000000000000000035251417272200500166350ustar00rootroot00000000000000package main import ( "math/rand" "strings" "sync" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { var wg sync.WaitGroup // passed wg will be accounted at p.Wait() call p := mpb.New(mpb.WithWaitGroup(&wg), mpb.WithWidth(60)) total, numBars := 100, 3 wg.Add(numBars) for i := 0; i < numBars; i++ { var pdecorators mpb.BarOption if i == 0 { pdecorators = mpb.PrependDecorators( decor.Merge( decor.OnComplete( newVariadicSpinner(decor.WCSyncSpace), "done", ), decor.WCSyncSpace, // Placeholder decor.WCSyncSpace, // Placeholder ), ) } else { pdecorators = mpb.PrependDecorators( decor.CountersNoUnit("% .1d / % .1d", decor.WCSyncSpace), decor.OnComplete(decor.Spinner(nil, decor.WCSyncSpace), "done"), decor.OnComplete(decor.Spinner(nil, decor.WCSyncSpace), "done"), ) } bar := p.AddBar(int64(total), pdecorators, mpb.AppendDecorators( decor.OnComplete(decor.EwmaETA(decor.ET_STYLE_GO, 60), "done"), ), ) // simulating some work go func() { defer wg.Done() rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 100 * time.Millisecond for i := 0; i < total; i++ { // start variable is solely for EWMA calculation // EWMA's unit of measure is an iteration's duration start := time.Now() time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() // we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract bar.DecoratorEwmaUpdate(time.Since(start)) } }() } // wait for passed wg and for all bars to complete and flush p.Wait() } func newVariadicSpinner(wc decor.WC) decor.Decorator { spinner := decor.Spinner(nil) fn := func(s decor.Statistics) string { return strings.Repeat(spinner.Decor(s), int(s.Current/3)) } return decor.Any(fn, wc) } mpb-7.3.2/_examples/mexicanBar/000077500000000000000000000000001417272200500163275ustar00rootroot00000000000000mpb-7.3.2/_examples/mexicanBar/go.mod000066400000000000000000000001541417272200500174350ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/mexicanBar go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/mexicanBar/main.go000066400000000000000000000013361417272200500176050ustar00rootroot00000000000000package main import ( "math/rand" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { // initialize progress container, with custom width p := mpb.New(mpb.WithWidth(80)) total := 100 name := "Complex Filler:" bs := mpb.BarStyle() bs.Lbound("[\u001b[36;1m") bs.Filler("_") bs.Tip("\u001b[0m⛵\u001b[36;1m") bs.Padding("_") bs.Rbound("\u001b[0m]") bar := p.New(int64(total), bs, mpb.PrependDecorators(decor.Name(name)), mpb.AppendDecorators(decor.Percentage()), ) // simulating some work max := 100 * time.Millisecond for i := 0; i < total; i++ { time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) bar.Increment() } // wait for our bar to complete p.Wait() } mpb-7.3.2/_examples/multiBars/000077500000000000000000000000001417272200500162205ustar00rootroot00000000000000mpb-7.3.2/_examples/multiBars/go.mod000066400000000000000000000001531417272200500173250ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/multiBars go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/multiBars/main.go000066400000000000000000000026411417272200500174760ustar00rootroot00000000000000package main import ( "fmt" "math/rand" "sync" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { var wg sync.WaitGroup // passed wg will be accounted at p.Wait() call p := mpb.New(mpb.WithWaitGroup(&wg)) total, numBars := 100, 3 wg.Add(numBars) for i := 0; i < numBars; i++ { name := fmt.Sprintf("Bar#%d:", i) bar := p.AddBar(int64(total), mpb.PrependDecorators( // simple name decorator decor.Name(name), // decor.DSyncWidth bit enables column width synchronization decor.Percentage(decor.WCSyncSpace), ), mpb.AppendDecorators( // replace ETA decorator with "done" message, OnComplete event decor.OnComplete( // ETA decorator with ewma age of 60 decor.EwmaETA(decor.ET_STYLE_GO, 60, decor.WCSyncWidth), "done", ), ), ) // simulating some work go func() { defer wg.Done() rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 100 * time.Millisecond for i := 0; i < total; i++ { // start variable is solely for EWMA calculation // EWMA's unit of measure is an iteration's duration start := time.Now() time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() // we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract bar.DecoratorEwmaUpdate(time.Since(start)) } }() } // wait for passed wg and for all bars to complete and flush p.Wait() } mpb-7.3.2/_examples/panic/000077500000000000000000000000001417272200500153505ustar00rootroot00000000000000mpb-7.3.2/_examples/panic/go.mod000066400000000000000000000001471417272200500164600ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/panic go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/panic/main.go000066400000000000000000000016601417272200500166260ustar00rootroot00000000000000package main import ( "fmt" "os" "strings" "sync" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { var wg sync.WaitGroup // passed wg will be accounted at p.Wait() call p := mpb.New( mpb.WithWaitGroup(&wg), mpb.WithDebugOutput(os.Stderr), ) wantPanic := strings.Repeat("Panic ", 64) numBars := 3 wg.Add(numBars) for i := 0; i < numBars; i++ { name := fmt.Sprintf("b#%02d:", i) bar := p.AddBar(100, mpb.BarID(i), mpb.PrependDecorators(panicDecorator(name, wantPanic))) go func() { defer wg.Done() for i := 0; i < 100; i++ { time.Sleep(50 * time.Millisecond) bar.Increment() } }() } // wait for passed wg and for all bars to complete and flush p.Wait() } func panicDecorator(name, panicMsg string) decor.Decorator { return decor.Any(func(st decor.Statistics) string { if st.ID == 1 && st.Current >= 42 { panic(panicMsg) } return name }) } mpb-7.3.2/_examples/poplog/000077500000000000000000000000001417272200500155565ustar00rootroot00000000000000mpb-7.3.2/_examples/poplog/go.mod000066400000000000000000000001501417272200500166600ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/poplog go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/poplog/main.go000066400000000000000000000022231417272200500170300ustar00rootroot00000000000000package main import ( "fmt" "math/rand" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { p := mpb.New(mpb.PopCompletedMode()) total, numBars := 100, 4 for i := 0; i < numBars; i++ { name := fmt.Sprintf("Bar#%d:", i) bar := p.AddBar(int64(total), mpb.BarFillerOnComplete(fmt.Sprintf("%s has been completed", name)), mpb.BarFillerTrim(), mpb.PrependDecorators( decor.OnComplete(decor.Name(name), ""), decor.OnComplete(decor.NewPercentage(" % d "), ""), ), mpb.AppendDecorators( decor.OnComplete(decor.Name(" "), ""), decor.OnComplete(decor.EwmaETA(decor.ET_STYLE_GO, 60), ""), ), ) // simulating some work rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 100 * time.Millisecond for i := 0; i < total; i++ { // start variable is solely for EWMA calculation // EWMA's unit of measure is an iteration's duration start := time.Now() time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() // we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract bar.DecoratorEwmaUpdate(time.Since(start)) } } p.Wait() } mpb-7.3.2/_examples/quietMode/000077500000000000000000000000001417272200500162125ustar00rootroot00000000000000mpb-7.3.2/_examples/quietMode/go.mod000066400000000000000000000001531417272200500173170ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/quietMode go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/quietMode/main.go000066400000000000000000000034761417272200500174770ustar00rootroot00000000000000package main import ( "flag" "fmt" "math/rand" "sync" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) var quietMode bool func init() { flag.BoolVar(&quietMode, "q", false, "quiet mode") } func main() { flag.Parse() var wg sync.WaitGroup // passed wg will be accounted at p.Wait() call p := mpb.New( mpb.WithWaitGroup(&wg), mpb.ContainerOptional( // setting to nil will: // set output to ioutil.Discard and disable refresh rate cycle, in // order not to consume much CPU. Hovewer a single refresh still will // be triggered on bar complete event, per each bar. mpb.WithOutput(nil), quietMode, ), ) total, numBars := 100, 3 wg.Add(numBars) for i := 0; i < numBars; i++ { name := fmt.Sprintf("Bar#%d:", i) bar := p.AddBar(int64(total), mpb.PrependDecorators( // simple name decorator decor.Name(name), // decor.DSyncWidth bit enables column width synchronization decor.Percentage(decor.WCSyncSpace), ), mpb.AppendDecorators( // replace ETA decorator with "done" message, OnComplete event decor.OnComplete( // ETA decorator with ewma age of 60 decor.EwmaETA(decor.ET_STYLE_GO, 60), "done", ), ), ) // simulating some work go func() { defer wg.Done() rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 100 * time.Millisecond for i := 0; i < total; i++ { // start variable is solely for EWMA calculation // EWMA's unit of measure is an iteration's duration start := time.Now() time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() // we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract bar.DecoratorEwmaUpdate(time.Since(start)) } }() } // wait for passed wg and for all bars to complete and flush p.Wait() fmt.Println("done") } mpb-7.3.2/_examples/remove/000077500000000000000000000000001417272200500155535ustar00rootroot00000000000000mpb-7.3.2/_examples/remove/go.mod000066400000000000000000000001501417272200500166550ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/remove go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/remove/main.go000066400000000000000000000025171417272200500170330ustar00rootroot00000000000000package main import ( "fmt" "math/rand" "sync" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { var wg sync.WaitGroup // passed wg will be accounted at p.Wait() call p := mpb.New(mpb.WithWaitGroup(&wg)) total := 100 numBars := 3 wg.Add(numBars) for i := 0; i < numBars; i++ { name := fmt.Sprintf("Bar#%d:", i) bar := p.AddBar(int64(total), mpb.BarID(i), mpb.BarOptional(mpb.BarRemoveOnComplete(), i == 0), mpb.PrependDecorators( decor.Name(name), ), mpb.AppendDecorators( decor.Any(func(s decor.Statistics) string { return fmt.Sprintf("completed: %v", s.Completed) }, decor.WCSyncSpaceR), decor.Any(func(s decor.Statistics) string { return fmt.Sprintf("aborted: %v", s.Aborted) }, decor.WCSyncSpaceR), decor.OnComplete(decor.NewPercentage("%d", decor.WCSyncSpace), "done"), decor.OnAbort(decor.NewPercentage("%d", decor.WCSyncSpace), "ohno"), ), ) go func() { defer wg.Done() rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 100 * time.Millisecond for i := 0; !bar.Completed(); i++ { if bar.ID() == 2 && i >= 42 { bar.Abort(false) } time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() } }() } // wait for passed wg and for all bars to complete and flush p.Wait() } mpb-7.3.2/_examples/reverseBar/000077500000000000000000000000001417272200500163565ustar00rootroot00000000000000mpb-7.3.2/_examples/reverseBar/go.mod000066400000000000000000000001541417272200500174640ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/reverseBar go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/reverseBar/main.go000066400000000000000000000032051417272200500176310ustar00rootroot00000000000000package main import ( "fmt" "math/rand" "sync" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { var wg sync.WaitGroup // passed wg will be accounted at p.Wait() call p := mpb.New(mpb.WithWaitGroup(&wg)) total, numBars := 100, 3 wg.Add(numBars) for i := 0; i < numBars; i++ { name := fmt.Sprintf("Bar#%d:", i) bar := p.New(int64(total), condBuilder(i == 1), mpb.PrependDecorators( // simple name decorator decor.Name(name), // decor.DSyncWidth bit enables column width synchronization decor.Percentage(decor.WCSyncSpace), ), mpb.AppendDecorators( // replace ETA decorator with "done" message, OnComplete event decor.OnComplete( // ETA decorator with ewma age of 60 decor.EwmaETA(decor.ET_STYLE_GO, 60), "done", ), ), ) // simulating some work go func() { defer wg.Done() rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 100 * time.Millisecond for i := 0; i < total; i++ { // start variable is solely for EWMA calculation // EWMA's unit of measure is an iteration's duration start := time.Now() time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() // we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract bar.DecoratorEwmaUpdate(time.Since(start)) } }() } // wait for passed wg and for all bars to complete and flush p.Wait() } func condBuilder(cond bool) mpb.BarFillerBuilder { return mpb.BarFillerBuilderFunc(func() mpb.BarFiller { bs := mpb.BarStyle() if cond { // reverse Bar on cond bs = bs.Tip("<").Reverse() } return bs.Build() }) } mpb-7.3.2/_examples/singleBar/000077500000000000000000000000001417272200500161645ustar00rootroot00000000000000mpb-7.3.2/_examples/singleBar/go.mod000066400000000000000000000001531417272200500172710ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/singleBar go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/singleBar/main.go000066400000000000000000000020271417272200500174400ustar00rootroot00000000000000package main import ( "math/rand" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { // initialize progress container, with custom width p := mpb.New(mpb.WithWidth(64)) total := 100 name := "Single Bar:" // create a single bar, which will inherit container's width bar := p.New(int64(total), // BarFillerBuilder with custom style mpb.BarStyle().Lbound("╢").Filler("▌").Tip("▌").Padding("░").Rbound("╟"), mpb.PrependDecorators( // display our name with one space on the right decor.Name(name, decor.WC{W: len(name) + 1, C: decor.DidentRight}), // replace ETA decorator with "done" message, OnComplete event decor.OnComplete( decor.AverageETA(decor.ET_STYLE_GO, decor.WC{W: 4}), "done", ), ), mpb.AppendDecorators(decor.Percentage()), ) // simulating some work max := 100 * time.Millisecond for i := 0; i < total; i++ { time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) bar.Increment() } // wait for our bar to complete and flush p.Wait() } mpb-7.3.2/_examples/spinTipBar/000077500000000000000000000000001417272200500163315ustar00rootroot00000000000000mpb-7.3.2/_examples/spinTipBar/go.mod000066400000000000000000000001541417272200500174370ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/spinTipBar go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/spinTipBar/main.go000066400000000000000000000011721417272200500176050ustar00rootroot00000000000000package main import ( "math/rand" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { // initialize progress container, with custom width p := mpb.New(mpb.WithWidth(80)) total := 100 name := "Single Bar:" bar := p.New(int64(total), mpb.BarStyle().Tip(`-`, `\`, `|`, `/`), mpb.PrependDecorators(decor.Name(name)), mpb.AppendDecorators(decor.Percentage()), ) // simulating some work max := 100 * time.Millisecond for i := 0; i < total; i++ { time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) bar.Increment() } // wait for our bar to complete and flush p.Wait() } mpb-7.3.2/_examples/spinnerBar/000077500000000000000000000000001417272200500163615ustar00rootroot00000000000000mpb-7.3.2/_examples/spinnerBar/go.mod000066400000000000000000000001541417272200500174670ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/spinnerBar go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/spinnerBar/main.go000066400000000000000000000033261417272200500176400ustar00rootroot00000000000000package main import ( "fmt" "math/rand" "sync" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { var wg sync.WaitGroup // passed wg will be accounted at p.Wait() call p := mpb.New( mpb.WithWaitGroup(&wg), mpb.WithWidth(16), ) total, numBars := 101, 3 wg.Add(numBars) for i := 0; i < numBars; i++ { name := fmt.Sprintf("Bar#%d:", i) bar := p.New(int64(total), condBuilder(i != 0), mpb.PrependDecorators( // simple name decorator decor.Name(name), ), mpb.AppendDecorators( // replace ETA decorator with "done" message, OnComplete event decor.OnComplete( // ETA decorator with ewma age of 60 decor.EwmaETA(decor.ET_STYLE_GO, 60), "done", ), ), ) // simulating some work go func() { defer wg.Done() rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 100 * time.Millisecond for i := 0; i < total; i++ { // start variable is solely for EWMA calculation // EWMA's unit of measure is an iteration's duration start := time.Now() time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() // we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract bar.DecoratorEwmaUpdate(time.Since(start)) } }() } // wait for passed wg and for all bars to complete and flush p.Wait() } func condBuilder(cond bool) mpb.BarFillerBuilder { return mpb.BarFillerBuilderFunc(func() mpb.BarFiller { if cond { // spinner Bar on cond frames := []string{"∙∙∙", "●∙∙", "∙●∙", "∙∙●", "∙∙∙"} return mpb.SpinnerStyle(frames...).Build() } return mpb.BarStyle().Lbound("╢").Filler("▌").Tip("▌").Padding("░").Rbound("╟").Build() }) } mpb-7.3.2/_examples/spinnerDecorator/000077500000000000000000000000001417272200500175775ustar00rootroot00000000000000mpb-7.3.2/_examples/spinnerDecorator/go.mod000066400000000000000000000001621417272200500207040ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/spinnerDecorator go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/spinnerDecorator/main.go000066400000000000000000000021351417272200500210530ustar00rootroot00000000000000package main import ( "fmt" "math/rand" "sync" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { var wg sync.WaitGroup // passed wg will be accounted at p.Wait() call p := mpb.New(mpb.WithWaitGroup(&wg), mpb.WithWidth(64)) total, numBars := 100, 3 wg.Add(numBars) for i := 0; i < numBars; i++ { name := fmt.Sprintf("Bar#%d:", i) bar := p.AddBar(int64(total), mpb.PrependDecorators( // simple name decorator decor.Name(name), decor.OnComplete( // spinner decorator with default style decor.Spinner(nil, decor.WCSyncSpace), "done", ), ), mpb.AppendDecorators( // decor.DSyncWidth bit enables column width synchronization decor.Percentage(decor.WCSyncWidth), ), ) // simulating some work go func() { defer wg.Done() rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 100 * time.Millisecond for i := 0; i < total; i++ { time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() } }() } // wait for passed wg and for all bars to complete and flush p.Wait() } mpb-7.3.2/_examples/stress/000077500000000000000000000000001417272200500156015ustar00rootroot00000000000000mpb-7.3.2/_examples/stress/go.mod000066400000000000000000000001501417272200500167030ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/stress go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/stress/main.go000066400000000000000000000017221417272200500170560ustar00rootroot00000000000000package main import ( "fmt" "math/rand" "sync" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) const ( totalBars = 32 ) func main() { var wg sync.WaitGroup // passed wg will be accounted at p.Wait() call p := mpb.New(mpb.WithWaitGroup(&wg)) wg.Add(totalBars) for i := 0; i < totalBars; i++ { name := fmt.Sprintf("Bar#%02d: ", i) total := rand.Intn(320) + 10 bar := p.AddBar(int64(total), mpb.PrependDecorators( decor.Name(name), decor.Elapsed(decor.ET_STYLE_GO, decor.WCSyncSpace), ), mpb.AppendDecorators( decor.OnComplete( decor.Percentage(decor.WC{W: 5}), "done", ), ), ) go func() { defer wg.Done() rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 100 * time.Millisecond for !bar.Completed() { time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() } }() } // wait for passed wg and for all bars to complete and flush p.Wait() } mpb-7.3.2/_examples/suppressBar/000077500000000000000000000000001417272200500165675ustar00rootroot00000000000000mpb-7.3.2/_examples/suppressBar/go.mod000066400000000000000000000002311417272200500176710ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/suppressBar go 1.14 require ( github.com/mattn/go-runewidth v0.0.13 github.com/vbauerster/mpb/v7 v7.3.2 ) mpb-7.3.2/_examples/suppressBar/main.go000066400000000000000000000041131417272200500200410ustar00rootroot00000000000000package main import ( "errors" "fmt" "io" "math/rand" "sync" "time" "github.com/mattn/go-runewidth" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { p := mpb.New() total := 100 msgCh := make(chan string) resumeCh := make(chan struct{}) nextCh := make(chan struct{}, 1) bar := p.AddBar(int64(total), mpb.BarFillerMiddleware(func(base mpb.BarFiller) mpb.BarFiller { var msg *string return mpb.BarFillerFunc(func(w io.Writer, reqWidth int, st decor.Statistics) { select { case m := <-msgCh: defer func() { msg = &m }() nextCh <- struct{}{} case <-resumeCh: msg = nil default: } if msg != nil { io.WriteString(w, runewidth.Truncate(*msg, st.AvailableWidth, "…")) nextCh <- struct{}{} } else { base.Fill(w, reqWidth, st) } }) }), mpb.PrependDecorators(decor.Name("my bar:")), mpb.AppendDecorators(newCustomPercentage(nextCh)), ) ew := &errorWrapper{} time.AfterFunc(2*time.Second, func() { ew.reset(errors.New("timeout")) }) // simulating some work go func() { rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 100 * time.Millisecond for i := 0; i < total; i++ { time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) if ew.isErr() { msgCh <- fmt.Sprintf("%s at %d, retrying...", ew.Error(), i) go ew.reset(nil) i-- bar.SetRefill(int64(i)) time.Sleep(3 * time.Second) resumeCh <- struct{}{} continue } bar.Increment() } }() p.Wait() } type errorWrapper struct { sync.RWMutex err error } func (ew *errorWrapper) Error() string { ew.RLock() defer ew.RUnlock() return ew.err.Error() } func (ew *errorWrapper) isErr() bool { ew.RLock() defer ew.RUnlock() return ew.err != nil } func (ew *errorWrapper) reset(err error) { ew.Lock() ew.err = err ew.Unlock() } func newCustomPercentage(nextCh <-chan struct{}) decor.Decorator { base := decor.Percentage() fn := func(s decor.Statistics) string { select { case <-nextCh: return "" default: return base.Decor(s) } } return decor.Any(fn) } mpb-7.3.2/_examples/tipOnComplete/000077500000000000000000000000001417272200500170405ustar00rootroot00000000000000mpb-7.3.2/_examples/tipOnComplete/go.mod000066400000000000000000000001571417272200500201510ustar00rootroot00000000000000module github.com/vbauerster/mpb/_examples/tipOnComplete go 1.14 require github.com/vbauerster/mpb/v7 v7.3.2 mpb-7.3.2/_examples/tipOnComplete/main.go000066400000000000000000000011651417272200500203160ustar00rootroot00000000000000package main import ( "math/rand" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func main() { // initialize progress container, with custom width p := mpb.New(mpb.WithWidth(80)) total := 100 name := "Single Bar:" bar := p.New(int64(total), mpb.BarStyle().TipOnComplete(">"), mpb.PrependDecorators(decor.Name(name)), mpb.AppendDecorators(decor.Percentage()), ) // simulating some work max := 100 * time.Millisecond for i := 0; i < total; i++ { time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) bar.Increment() } // wait for our bar to complete and flush p.Wait() } mpb-7.3.2/_svg/000077500000000000000000000000001417272200500132375ustar00rootroot00000000000000mpb-7.3.2/_svg/godEMrCZmJkHYH1X9dN4Nm0U7.svg000066400000000000000000002025171417272200500200530ustar00rootroot00000000000000~/go/src/github.com/vbauerster/mpb/examples/dynTotal~/go/src/github.com/vbauerster/mpb/examples/dynTotalmaster*gorun-racemain.gogorun-racemain.gogorun-racemain.go55.7KiB/56.7KiB[============================================================>-]98%100.7KiB/100.7KiB[==============================================================]100%~/go/src/github.com/vbauerster/mpb/examples/dynTotalmaster*13s~/go/src/github.com/vbauerster/mpb/examples/dynTotalmaster~/go/src/github.com/vbauerster/mpb/examples/dynTotalmastergorun-racemain.gogorun-racemain.gogorun-racemain.gogorun-racemain.go519b/1.5KiB[====================>-----------------------------------------]34%2.2KiB/3.2KiB[==========================================>-------------------]69%2.5KiB/3.5KiB[===========================================>------------------]72%3.2KiB/4.2KiB[==============================================>---------------]76%3.6KiB/4.6KiB[================================================>-------------]78%6.5KiB/7.5KiB[=====================================================>--------]87%8.0KiB/9.0KiB[======================================================>-------]89%10.6KiB/11.6KiB[========================================================>-----]91%12.1KiB/13.1KiB[========================================================>-----]92%13.1KiB/14.1KiB[=========================================================>----]93%13.2KiB/14.2KiB[=========================================================>----]93%13.9KiB/14.9KiB[=========================================================>----]93%15.5KiB/16.5KiB[=========================================================>----]94%15.8KiB/16.8KiB[=========================================================>----]94%17.6KiB/18.6KiB[==========================================================>---]95%18.9KiB/19.9KiB[==========================================================>---]95%20.0KiB/21.0KiB[==========================================================>---]95%21.0KiB/22.0KiB[==========================================================>---]95%21.3KiB/22.3KiB[==========================================================>---]96%22.6KiB/23.6KiB[==========================================================>---]96%23.9KiB/24.9KiB[===========================================================>--]96%25.7KiB/26.7KiB[===========================================================>--]96%26.1KiB/27.1KiB[===========================================================>--]96%26.8KiB/27.8KiB[===========================================================>--]96%28.0KiB/29.0KiB[===========================================================>--]97%28.4KiB/29.4KiB[===========================================================>--]97%29.6KiB/30.6KiB[===========================================================>--]97%30.0KiB/31.0KiB[===========================================================>--]97%30.4KiB/31.4KiB[===========================================================>--]97%31.8KiB/32.8KiB[===========================================================>--]97%34.4KiB/35.4KiB[===========================================================>--]97%34.5KiB/35.5KiB[===========================================================>--]97%37.0KiB/38.0KiB[===========================================================>--]97%38.5KiB/39.5KiB[===========================================================>--]97%40.4KiB/41.4KiB[============================================================>-]98%41.1KiB/42.1KiB[============================================================>-]98%42.2KiB/43.2KiB[============================================================>-]98%43.9KiB/44.9KiB[============================================================>-]98%44.9KiB/45.9KiB[============================================================>-]98%46.2KiB/47.2KiB[============================================================>-]98%46.9KiB/47.9KiB[============================================================>-]98%48.4KiB/49.4KiB[============================================================>-]98%48.7KiB/49.7KiB[============================================================>-]98%49.3KiB/50.3KiB[============================================================>-]98%50.1KiB/51.1KiB[============================================================>-]98%50.5KiB/51.5KiB[============================================================>-]98%50.6KiB/51.6KiB[============================================================>-]98%50.8KiB/51.8KiB[============================================================>-]98%51.7KiB/52.7KiB[============================================================>-]98%52.7KiB/53.7KiB[============================================================>-]98%53.6KiB/54.6KiB[============================================================>-]98%57.5KiB/58.5KiB[============================================================>-]98%58.3KiB/59.3KiB[============================================================>-]98%58.7KiB/59.7KiB[============================================================>-]98%60.1KiB/61.1KiB[============================================================>-]98%62.0KiB/63.0KiB[============================================================>-]98%63.7KiB/64.7KiB[============================================================>-]98%64.7KiB/65.7KiB[============================================================>-]98%65.2KiB/66.2KiB[============================================================>-]98%65.8KiB/66.8KiB[============================================================>-]99%66.4KiB/67.4KiB[============================================================>-]99%67.6KiB/68.6KiB[============================================================>-]99%68.5KiB/69.5KiB[============================================================>-]99%70.0KiB/71.0KiB[============================================================>-]99%70.4KiB/71.4KiB[============================================================>-]99%70.8KiB/71.8KiB[============================================================>-]99%72.3KiB/73.3KiB[============================================================>-]99%73.1KiB/74.1KiB[============================================================>-]99%74.4KiB/75.4KiB[============================================================>-]99%75.7KiB/76.7KiB[============================================================>-]99%78.2KiB/79.2KiB[============================================================>-]99%79.3KiB/80.3KiB[============================================================>-]99%80.1KiB/81.1KiB[============================================================>-]99%81.3KiB/82.3KiB[============================================================>-]99%82.3KiB/83.3KiB[============================================================>-]99%82.6KiB/83.6KiB[============================================================>-]99%84.0KiB/85.0KiB[============================================================>-]99%84.7KiB/85.7KiB[============================================================>-]99%85.9KiB/86.9KiB[============================================================>-]99%87.7KiB/88.7KiB[============================================================>-]99%88.8KiB/89.8KiB[============================================================>-]99%90.3KiB/91.3KiB[============================================================>-]99%91.6KiB/92.6KiB[============================================================>-]99%92.8KiB/93.8KiB[============================================================>-]99%93.5KiB/94.5KiB[============================================================>-]99%93.6KiB/94.6KiB[============================================================>-]99%95.1KiB/96.1KiB[============================================================>-]99%96.4KiB/97.4KiB[============================================================>-]99%97.6KiB/98.6KiB[============================================================>-]99%98.8KiB/99.8KiB[============================================================>-]99%99.7KiB/100.7KiB[============================================================>-]99%100.6KiB/101.6KiB[============================================================>-]99%100.7KiB/101.7KiB[============================================================>-]99%mpb-7.3.2/_svg/hIpTa3A5rQz65ssiVuRJu87X6.svg000066400000000000000000005242741417272200500201740ustar00rootroot00000000000000~/go/src/github.com/vbauerster/mpb/examples/io/single~/go/src/github.com/vbauerster/mpb/examples/io/singlemaster*gorun-racemain.gogorun-racemain.gogorun-racemain.go40.6MiB/40.6MiB[==========================================================|00:00]7.54MiB/s~/go/src/github.com/vbauerster/mpb/examples/io/singlemaster*46s~/go/src/github.com/vbauerster/mpb/examples/io/singlemastergitclean-fdxgorun-racemain.gogorun-racemain.gogorun-racemain.go16.6KiB/40.6MiB[----------------------------------------------------------|00:00]0b/s66.5KiB/40.6MiB[----------------------------------------------------------|00:00]0b/s134.5KiB/40.6MiB[----------------------------------------------------------|09:01]6.18MiB/s339.6KiB/40.6MiB[----------------------------------------------------------|08:18]6.41MiB/s577.6KiB/40.6MiB[>---------------------------------------------------------|07:32]7.05MiB/s866.6KiB/40.6MiB[>---------------------------------------------------------|06:43]7.36MiB/s1.5MiB/40.6MiB[=>--------------------------------------------------------|05:12]8.12MiB/s1.8MiB/40.6MiB[==>-------------------------------------------------------|04:28]8.48MiB/s2.4MiB/40.6MiB[==>-------------------------------------------------------|03:29]16.62MiB/s2.9MiB/40.6MiB[===>------------------------------------------------------|02:52]15.37MiB/s3.5MiB/40.6MiB[====>-----------------------------------------------------|02:17]14.22MiB/s3.9MiB/40.6MiB[=====>----------------------------------------------------|01:59]13.18MiB/s4.3MiB/40.6MiB[=====>----------------------------------------------------|01:40]12.42MiB/s4.9MiB/40.6MiB[======>---------------------------------------------------|01:19]18.55MiB/s5.2MiB/40.6MiB[======>---------------------------------------------------|01:11]17.39MiB/s5.5MiB/40.6MiB[=======>--------------------------------------------------|01:03]16.23MiB/s5.6MiB/40.6MiB[=======>--------------------------------------------------|01:02]16.04MiB/s6.2MiB/40.6MiB[========>-------------------------------------------------|00:50]17.91MiB/s6.5MiB/40.6MiB[========>-------------------------------------------------|00:47]16.80MiB/s6.7MiB/40.6MiB[=========>------------------------------------------------|00:45]15.85MiB/s7.0MiB/40.6MiB[=========>------------------------------------------------|00:41]14.66MiB/s7.3MiB/40.6MiB[=========>------------------------------------------------|00:38]17.03MiB/s7.5MiB/40.6MiB[==========>-----------------------------------------------|00:39]16.26MiB/s7.7MiB/40.6MiB[==========>-----------------------------------------------|00:38]15.16MiB/s8.0MiB/40.6MiB[==========>-----------------------------------------------|00:36]14.16MiB/s8.1MiB/40.6MiB[===========>----------------------------------------------|00:35]13.56MiB/s8.4MiB/40.6MiB[===========>----------------------------------------------|00:36]13.08MiB/s8.6MiB/40.6MiB[===========>----------------------------------------------|00:34]12.51MiB/s8.8MiB/40.6MiB[============>---------------------------------------------|00:34]12.05MiB/s9.0MiB/40.6MiB[============>---------------------------------------------|00:35]11.56MiB/s9.3MiB/40.6MiB[============>---------------------------------------------|00:32]11.12MiB/s9.5MiB/40.6MiB[=============>--------------------------------------------|00:31]10.75MiB/s9.7MiB/40.6MiB[=============>--------------------------------------------|00:30]10.23MiB/s10.0MiB/40.6MiB[=============>--------------------------------------------|00:29]9.89MiB/s10.2MiB/40.6MiB[==============>-------------------------------------------|00:30]9.54MiB/s10.4MiB/40.6MiB[==============>-------------------------------------------|00:28]9.34MiB/s10.7MiB/40.6MiB[==============>-------------------------------------------|00:27]9.04MiB/s10.9MiB/40.6MiB[===============>------------------------------------------|00:26]8.79MiB/s11.0MiB/40.6MiB[===============>------------------------------------------|00:26]8.75MiB/s11.3MiB/40.6MiB[===============>------------------------------------------|00:25]11.13MiB/s11.5MiB/40.6MiB[===============>------------------------------------------|00:24]10.81MiB/s11.7MiB/40.6MiB[================>-----------------------------------------|00:24]10.45MiB/s11.9MiB/40.6MiB[================>-----------------------------------------|00:25]10.00MiB/s12.1MiB/40.6MiB[================>-----------------------------------------|00:25]9.63MiB/s12.3MiB/40.6MiB[=================>----------------------------------------|00:24]9.26MiB/s12.4MiB/40.6MiB[=================>----------------------------------------|00:24]9.14MiB/s12.6MiB/40.6MiB[=================>----------------------------------------|00:23]8.79MiB/s12.8MiB/40.6MiB[=================>----------------------------------------|00:23]10.07MiB/s12.9MiB/40.6MiB[=================>----------------------------------------|00:23]9.96MiB/s13.1MiB/40.6MiB[==================>---------------------------------------|00:22]9.80MiB/s13.2MiB/40.6MiB[==================>---------------------------------------|00:22]9.71MiB/s13.4MiB/40.6MiB[==================>---------------------------------------|00:22]9.61MiB/s13.6MiB/40.6MiB[==================>---------------------------------------|00:25]9.36MiB/s13.7MiB/40.6MiB[===================>--------------------------------------|00:24]9.19MiB/s13.9MiB/40.6MiB[===================>--------------------------------------|00:24]8.93MiB/s14.0MiB/40.6MiB[===================>--------------------------------------|00:24]8.65MiB/s14.2MiB/40.6MiB[===================>--------------------------------------|00:24]8.48MiB/s14.4MiB/40.6MiB[====================>-------------------------------------|00:23]8.32MiB/s14.5MiB/40.6MiB[====================>-------------------------------------|00:23]8.20MiB/s14.7MiB/40.6MiB[====================>-------------------------------------|00:22]8.12MiB/s14.8MiB/40.6MiB[====================>-------------------------------------|00:22]7.97MiB/s15.0MiB/40.6MiB[====================>-------------------------------------|00:22]7.88MiB/s15.2MiB/40.6MiB[=====================>------------------------------------|00:21]7.74MiB/s15.3MiB/40.6MiB[=====================>------------------------------------|00:21]7.73MiB/s15.4MiB/40.6MiB[=====================>------------------------------------|00:20]9.07MiB/s15.6MiB/40.6MiB[=====================>------------------------------------|00:20]8.84MiB/s15.7MiB/40.6MiB[=====================>------------------------------------|00:20]8.72MiB/s15.9MiB/40.6MiB[======================>-----------------------------------|00:20]8.45MiB/s16.0MiB/40.6MiB[======================>-----------------------------------|00:20]8.27MiB/s16.1MiB/40.6MiB[======================>-----------------------------------|00:22]8.05MiB/s16.3MiB/40.6MiB[======================>-----------------------------------|00:21]7.88MiB/s16.4MiB/40.6MiB[======================>-----------------------------------|00:21]7.69MiB/s16.6MiB/40.6MiB[=======================>----------------------------------|00:21]7.60MiB/s16.7MiB/40.6MiB[=======================>----------------------------------|00:22]7.49MiB/s16.9MiB/40.6MiB[=======================>----------------------------------|00:22]7.41MiB/s17.0MiB/40.6MiB[=======================>----------------------------------|00:21]7.43MiB/s17.2MiB/40.6MiB[========================>---------------------------------|00:21]7.38MiB/s17.4MiB/40.6MiB[========================>---------------------------------|00:23]7.23MiB/s17.5MiB/40.6MiB[========================>---------------------------------|00:23]7.15MiB/s17.7MiB/40.6MiB[========================>---------------------------------|00:24]6.99MiB/s17.9MiB/40.6MiB[=========================>--------------------------------|00:25]6.90MiB/s18.0MiB/40.6MiB[=========================>--------------------------------|00:24]6.83MiB/s18.2MiB/40.6MiB[=========================>--------------------------------|00:23]8.15MiB/s18.3MiB/40.6MiB[=========================>--------------------------------|00:24]7.99MiB/s18.4MiB/40.6MiB[=========================>--------------------------------|00:24]7.88MiB/s18.6MiB/40.6MiB[==========================>-------------------------------|00:24]7.62MiB/s18.7MiB/40.6MiB[==========================>-------------------------------|00:23]7.58MiB/s18.8MiB/40.6MiB[==========================>-------------------------------|00:23]7.47MiB/s19.0MiB/40.6MiB[==========================>-------------------------------|00:22]7.39MiB/s19.1MiB/40.6MiB[==========================>-------------------------------|00:22]7.33MiB/s19.2MiB/40.6MiB[===========================>------------------------------|00:22]8.48MiB/s19.4MiB/40.6MiB[===========================>------------------------------|00:25]8.27MiB/s19.5MiB/40.6MiB[===========================>------------------------------|00:25]8.13MiB/s19.6MiB/40.6MiB[===========================>------------------------------|00:25]7.89MiB/s19.7MiB/40.6MiB[===========================>------------------------------|00:25]7.67MiB/s19.8MiB/40.6MiB[===========================>------------------------------|00:24]7.52MiB/s20.0MiB/40.6MiB[============================>-----------------------------|00:24]7.42MiB/s20.1MiB/40.6MiB[============================>-----------------------------|00:24]7.25MiB/s20.2MiB/40.6MiB[============================>-----------------------------|00:23]7.12MiB/s20.3MiB/40.6MiB[============================>-----------------------------|00:23]6.94MiB/s20.5MiB/40.6MiB[============================>-----------------------------|00:24]6.75MiB/s20.6MiB/40.6MiB[============================>-----------------------------|00:24]6.59MiB/s20.7MiB/40.6MiB[=============================>----------------------------|00:27]6.57MiB/s20.8MiB/40.6MiB[=============================>----------------------------|00:27]6.45MiB/s21.0MiB/40.6MiB[=============================>----------------------------|00:28]6.40MiB/s21.1MiB/40.6MiB[=============================>----------------------------|00:30]6.36MiB/s21.2MiB/40.6MiB[=============================>----------------------------|00:29]6.28MiB/s21.3MiB/40.6MiB[=============================>----------------------------|00:28]6.22MiB/s21.4MiB/40.6MiB[==============================>---------------------------|00:27]6.19MiB/s21.5MiB/40.6MiB[==============================>---------------------------|00:29]6.10MiB/s21.7MiB/40.6MiB[==============================>---------------------------|00:28]6.09MiB/s21.8MiB/40.6MiB[==============================>---------------------------|00:27]6.04MiB/s21.9MiB/40.6MiB[==============================>---------------------------|00:27]5.88MiB/s22.0MiB/40.6MiB[===============================>--------------------------|00:27]5.83MiB/s22.2MiB/40.6MiB[===============================>--------------------------|00:26]5.78MiB/s22.3MiB/40.6MiB[===============================>--------------------------|00:25]5.80MiB/s22.4MiB/40.6MiB[===============================>--------------------------|00:24]5.76MiB/s22.5MiB/40.6MiB[===============================>--------------------------|00:24]5.72MiB/s22.7MiB/40.6MiB[===============================>--------------------------|00:23]5.70MiB/s22.8MiB/40.6MiB[================================>-------------------------|00:24]5.60MiB/s22.8MiB/40.6MiB[================================>-------------------------|00:24]5.58MiB/s23.0MiB/40.6MiB[================================>-------------------------|00:25]6.35MiB/s23.1MiB/40.6MiB[================================>-------------------------|00:25]6.33MiB/s23.2MiB/40.6MiB[================================>-------------------------|00:24]6.33MiB/s23.4MiB/40.6MiB[================================>-------------------------|00:24]6.31MiB/s23.5MiB/40.6MiB[=================================>------------------------|00:23]6.28MiB/s23.6MiB/40.6MiB[=================================>------------------------|00:23]6.20MiB/s23.7MiB/40.6MiB[=================================>------------------------|00:22]6.26MiB/s23.8MiB/40.6MiB[=================================>------------------------|00:22]6.26MiB/s23.9MiB/40.6MiB[=================================>------------------------|00:21]6.31MiB/s24.0MiB/40.6MiB[=================================>------------------------|00:21]6.26MiB/s24.2MiB/40.6MiB[==================================>-----------------------|00:22]6.25MiB/s24.3MiB/40.6MiB[==================================>-----------------------|00:25]6.20MiB/s24.4MiB/40.6MiB[==================================>-----------------------|00:24]6.20MiB/s24.5MiB/40.6MiB[==================================>-----------------------|00:23]6.14MiB/s24.7MiB/40.6MiB[==================================>-----------------------|00:24]6.16MiB/s24.8MiB/40.6MiB[==================================>-----------------------|00:24]6.13MiB/s24.9MiB/40.6MiB[===================================>----------------------|00:23]6.14MiB/s25.0MiB/40.6MiB[===================================>----------------------|00:23]6.17MiB/s25.1MiB/40.6MiB[===================================>----------------------|00:23]6.16MiB/s25.3MiB/40.6MiB[===================================>----------------------|00:22]6.05MiB/s25.4MiB/40.6MiB[===================================>----------------------|00:22]6.14MiB/s25.5MiB/40.6MiB[===================================>----------------------|00:21]6.06MiB/s25.6MiB/40.6MiB[====================================>---------------------|00:22]6.04MiB/s25.8MiB/40.6MiB[====================================>---------------------|00:21]6.02MiB/s25.9MiB/40.6MiB[====================================>---------------------|00:22]5.96MiB/s26.0MiB/40.6MiB[====================================>---------------------|00:24]6.05MiB/s26.1MiB/40.6MiB[====================================>---------------------|00:23]6.03MiB/s26.2MiB/40.6MiB[=====================================>--------------------|00:22]7.18MiB/s26.3MiB/40.6MiB[=====================================>--------------------|00:22]7.10MiB/s26.4MiB/40.6MiB[=====================================>--------------------|00:21]7.09MiB/s26.5MiB/40.6MiB[=====================================>--------------------|00:21]7.09MiB/s26.7MiB/40.6MiB[=====================================>--------------------|00:21]7.07MiB/s26.8MiB/40.6MiB[=====================================>--------------------|00:20]7.02MiB/s26.8MiB/40.6MiB[=====================================>--------------------|00:20]6.92MiB/s27.0MiB/40.6MiB[======================================>-------------------|00:19]6.89MiB/s27.1MiB/40.6MiB[======================================>-------------------|00:19]6.99MiB/s27.2MiB/40.6MiB[======================================>-------------------|00:18]6.98MiB/s27.3MiB/40.6MiB[======================================>-------------------|00:18]6.99MiB/s27.5MiB/40.6MiB[======================================>-------------------|00:20]6.98MiB/s27.5MiB/40.6MiB[======================================>-------------------|00:20]6.94MiB/s27.7MiB/40.6MiB[=======================================>------------------|00:20]7.98MiB/s27.8MiB/40.6MiB[=======================================>------------------|00:19]7.88MiB/s27.8MiB/40.6MiB[=======================================>------------------|00:19]7.81MiB/s28.0MiB/40.6MiB[=======================================>------------------|00:18]7.71MiB/s28.0MiB/40.6MiB[=======================================>------------------|00:18]7.58MiB/s28.1MiB/40.6MiB[=======================================>------------------|00:18]7.44MiB/s28.2MiB/40.6MiB[=======================================>------------------|00:18]7.38MiB/s28.3MiB/40.6MiB[========================================>-----------------|00:17]7.33MiB/s28.4MiB/40.6MiB[========================================>-----------------|00:17]7.19MiB/s28.5MiB/40.6MiB[========================================>-----------------|00:18]7.17MiB/s28.6MiB/40.6MiB[========================================>-----------------|00:17]7.17MiB/s28.7MiB/40.6MiB[========================================>-----------------|00:20]7.11MiB/s28.8MiB/40.6MiB[========================================>-----------------|00:19]7.03MiB/s28.9MiB/40.6MiB[========================================>-----------------|00:20]6.89MiB/s29.0MiB/40.6MiB[=========================================>----------------|00:20]6.79MiB/s29.1MiB/40.6MiB[=========================================>----------------|00:19]6.72MiB/s29.2MiB/40.6MiB[=========================================>----------------|00:21]6.60MiB/s29.4MiB/40.6MiB[=========================================>----------------|00:20]6.50MiB/s29.4MiB/40.6MiB[=========================================>----------------|00:20]6.48MiB/s29.5MiB/40.6MiB[=========================================>----------------|00:20]6.44MiB/s29.7MiB/40.6MiB[=========================================>----------------|00:19]6.37MiB/s29.7MiB/40.6MiB[==========================================>---------------|00:19]6.31MiB/s29.8MiB/40.6MiB[==========================================>---------------|00:21]6.31MiB/s29.9MiB/40.6MiB[==========================================>---------------|00:20]6.34MiB/s30.0MiB/40.6MiB[==========================================>---------------|00:20]6.32MiB/s30.2MiB/40.6MiB[==========================================>---------------|00:19]6.22MiB/s30.2MiB/40.6MiB[==========================================>---------------|00:19]6.18MiB/s30.3MiB/40.6MiB[==========================================>---------------|00:19]6.16MiB/s30.5MiB/40.6MiB[===========================================>--------------|00:19]6.21MiB/s30.6MiB/40.6MiB[===========================================>--------------|00:18]6.19MiB/s30.7MiB/40.6MiB[===========================================>--------------|00:17]6.18MiB/s30.8MiB/40.6MiB[===========================================>--------------|00:17]6.19MiB/s30.9MiB/40.6MiB[===========================================>--------------|00:17]5.99MiB/s31.0MiB/40.6MiB[===========================================>--------------|00:17]5.89MiB/s31.1MiB/40.6MiB[============================================>-------------|00:16]5.92MiB/s31.3MiB/40.6MiB[============================================>-------------|00:15]5.80MiB/s31.4MiB/40.6MiB[============================================>-------------|00:15]5.85MiB/s31.5MiB/40.6MiB[============================================>-------------|00:14]5.87MiB/s31.7MiB/40.6MiB[============================================>-------------|00:13]5.93MiB/s31.9MiB/40.6MiB[=============================================>------------|00:13]5.95MiB/s32.0MiB/40.6MiB[=============================================>------------|00:12]5.98MiB/s32.2MiB/40.6MiB[=============================================>------------|00:11]5.99MiB/s32.4MiB/40.6MiB[=============================================>------------|00:11]6.04MiB/s32.5MiB/40.6MiB[=============================================>------------|00:10]6.08MiB/s32.7MiB/40.6MiB[==============================================>-----------|00:10]6.03MiB/s32.9MiB/40.6MiB[==============================================>-----------|00:09]6.05MiB/s33.1MiB/40.6MiB[==============================================>-----------|00:09]6.08MiB/s33.3MiB/40.6MiB[===============================================>----------|00:08]6.13MiB/s33.6MiB/40.6MiB[===============================================>----------|00:07]6.30MiB/s33.8MiB/40.6MiB[===============================================>----------|00:07]6.33MiB/s34.0MiB/40.6MiB[================================================>---------|00:07]6.44MiB/s34.3MiB/40.6MiB[================================================>---------|00:06]6.88MiB/s34.6MiB/40.6MiB[================================================>---------|00:05]6.88MiB/s34.8MiB/40.6MiB[=================================================>--------|00:05]6.88MiB/s35.2MiB/40.6MiB[=================================================>--------|00:04]10.50MiB/s35.4MiB/40.6MiB[==================================================>-------|00:04]10.17MiB/s35.6MiB/40.6MiB[==================================================>-------|00:03]9.88MiB/s35.9MiB/40.6MiB[==================================================>-------|00:03]9.36MiB/s36.2MiB/40.6MiB[===================================================>------|00:03]9.27MiB/s36.4MiB/40.6MiB[===================================================>------|00:02]9.08MiB/s36.7MiB/40.6MiB[===================================================>------|00:02]8.83MiB/s37.0MiB/40.6MiB[====================================================>-----|00:02]8.64MiB/s37.2MiB/40.6MiB[====================================================>-----|00:02]8.48MiB/s37.5MiB/40.6MiB[=====================================================>----|00:02]8.26MiB/s37.9MiB/40.6MiB[=====================================================>----|00:02]8.16MiB/s38.1MiB/40.6MiB[=====================================================>----|00:01]8.21MiB/s38.4MiB/40.6MiB[======================================================>---|00:01]8.38MiB/s38.7MiB/40.6MiB[======================================================>---|00:01]8.31MiB/s39.0MiB/40.6MiB[=======================================================>--|00:01]8.40MiB/s39.3MiB/40.6MiB[=======================================================>--|00:01]8.21MiB/s39.6MiB/40.6MiB[========================================================>-|00:00]8.14MiB/s40.0MiB/40.6MiB[========================================================>-|00:00]7.97MiB/s40.2MiB/40.6MiB[==========================================================|00:00]7.75MiB/smpb-7.3.2/_svg/wHzf1M7sd7B3zVa2scBMnjqRf.svg000066400000000000000000005756551417272200500203260ustar00rootroot00000000000000~/go/src/github.com/vbauerster/mpb/examples/complex~/go/src/github.com/vbauerster/mpb/examples/complexmaster*gorun-racemain.gogorun-racemain.gogorun-racemain.goTask#03:installing00:08[======>-------------------------------------------------------]11%Task#03:installing00:07[==============>-----------------------------------------------]24%Task#02:done!Task#03:done!Task#01:done!Task#00:done!~/go/src/github.com/vbauerster/mpb/examples/complexmaster*19s~/go/src/github.com/vbauerster/mpb/examples/complexmastergorun-racemain.gogorun-racemain.gogorun-racemain.gogorun-racemain.goTask#00:downloading4/268[>-------------------------------------------------------------]1%Task#01:downloading2/274[--------------------------------------------------------------]1%Task#02:downloading3/114[=>------------------------------------------------------------]3%Task#03:downloading4/114[=>------------------------------------------------------------]4%Task#00:downloading6/268[>-------------------------------------------------------------]2%Task#01:downloading8/274[=>------------------------------------------------------------]3%Task#02:downloading9/114[====>---------------------------------------------------------]8%Task#03:downloading12/114[======>-------------------------------------------------------]11%Task#00:downloading9/268[=>------------------------------------------------------------]3%Task#01:downloading12/274[==>-----------------------------------------------------------]4%Task#02:downloading12/114[======>-------------------------------------------------------]11%Task#03:downloading24/114[============>-------------------------------------------------]21%Task#00:downloading11/268[==>-----------------------------------------------------------]4%Task#01:downloading16/274[===>----------------------------------------------------------]6%Task#02:downloading18/114[=========>----------------------------------------------------]16%Task#03:downloading36/114[===================>------------------------------------------]32%Task#00:downloading13/268[==>-----------------------------------------------------------]5%Task#01:downloading22/274[====>---------------------------------------------------------]8%Task#02:downloading27/114[==============>-----------------------------------------------]24%Task#03:downloading40/114[=====================>----------------------------------------]35%Task#00:downloading15/268[==>-----------------------------------------------------------]6%Task#01:downloading24/274[====>---------------------------------------------------------]9%Task#02:downloading30/114[===============>----------------------------------------------]26%Task#03:downloading48/114[=========================>------------------------------------]42%Task#00:downloading16/268[===>----------------------------------------------------------]6%Task#01:downloading30/274[======>-------------------------------------------------------]11%Task#02:downloading39/114[====================>-----------------------------------------]34%Task#03:downloading56/114[=============================>--------------------------------]49%Task#00:downloading18/268[===>----------------------------------------------------------]7%Task#01:downloading34/274[=======>------------------------------------------------------]12%Task#02:downloading42/114[======================>---------------------------------------]37%Task#03:downloading64/114[==================================>---------------------------]56%Task#00:downloading19/268[===>----------------------------------------------------------]7%Task#01:downloading40/274[========>-----------------------------------------------------]15%Task#02:downloading45/114[=======================>--------------------------------------]39%Task#03:downloading68/114[====================================>-------------------------]60%Task#00:downloading21/268[====>---------------------------------------------------------]8%Task#01:downloading44/274[=========>----------------------------------------------------]16%Task#02:downloading54/114[============================>---------------------------------]47%Task#03:downloading76/114[========================================>---------------------]67%Task#00:downloading25/268[=====>--------------------------------------------------------]9%Task#01:downloading52/274[===========>--------------------------------------------------]19%Task#02:downloading60/114[================================>-----------------------------]53%Task#03:downloading80/114[===========================================>------------------]70%Task#00:downloading27/268[=====>--------------------------------------------------------]10%Task#01:downloading54/274[===========>--------------------------------------------------]20%Task#02:downloading63/114[=================================>----------------------------]55%Task#03:downloading88/114[===============================================>--------------]77%Task#00:downloading29/268[======>-------------------------------------------------------]11%Task#01:downloading58/274[============>-------------------------------------------------]21%Task#02:downloading69/114[=====================================>------------------------]61%Task#03:downloading92/114[=================================================>------------]81%Task#00:downloading30/268[======>-------------------------------------------------------]11%Task#01:downloading60/274[=============>------------------------------------------------]22%Task#02:downloading75/114[========================================>---------------------]66%Task#03:downloading100/114[=====================================================>--------]88%Task#00:downloading32/268[======>-------------------------------------------------------]12%Task#01:downloading66/274[==============>-----------------------------------------------]24%Task#02:downloading78/114[=========================================>--------------------]68%Task#03:downloading108/114[==========================================================>---]95%Task#00:downloading34/268[=======>------------------------------------------------------]13%Task#01:downloading70/274[===============>----------------------------------------------]26%Task#02:downloading84/114[=============================================>----------------]74%Task#03:downloading114/114[==============================================================]100%Task#00:downloading35/268[=======>------------------------------------------------------]13%Task#01:downloading74/274[================>---------------------------------------------]27%Task#02:downloading90/114[================================================>-------------]79%Task#03:installing00:00[--------------------------------------------------------------]1%Task#00:downloading37/268[========>-----------------------------------------------------]14%Task#01:downloading76/274[================>---------------------------------------------]28%Task#02:downloading96/114[===================================================>----------]84%Task#03:installing00:00[=>------------------------------------------------------------]2%Task#00:downloading40/268[========>-----------------------------------------------------]15%Task#01:downloading78/274[=================>--------------------------------------------]28%Task#02:downloading102/114[======================================================>-------]89%Task#03:installing00:00[=>------------------------------------------------------------]4%Task#00:downloading42/268[=========>----------------------------------------------------]16%Task#01:downloading82/274[==================>-------------------------------------------]30%Task#02:downloading108/114[==========================================================>---]95%Task#03:installing00:00[==>-----------------------------------------------------------]4%Task#00:downloading44/268[=========>----------------------------------------------------]16%Task#01:downloading86/274[==================>-------------------------------------------]31%Task#02:downloading114/114[==============================================================]100%Task#03:installing00:00[==>-----------------------------------------------------------]6%Task#00:downloading47/268[==========>---------------------------------------------------]18%Task#01:downloading88/274[===================>------------------------------------------]32%Task#02:installing00:00[=>------------------------------------------------------------]3%Task#03:installing00:09[====>---------------------------------------------------------]7%Task#00:downloading50/268[===========>--------------------------------------------------]19%Task#01:downloading92/274[====================>-----------------------------------------]34%Task#02:installing00:00[===>----------------------------------------------------------]6%Task#03:installing00:09[====>---------------------------------------------------------]9%Task#00:downloading52/268[===========>--------------------------------------------------]19%Task#01:downloading96/274[=====================>----------------------------------------]35%Task#02:installing00:00[=====>--------------------------------------------------------]9%Task#00:downloading54/268[===========>--------------------------------------------------]20%Task#01:downloading98/274[=====================>----------------------------------------]36%Task#02:installing00:03[========>-----------------------------------------------------]14%Task#00:downloading56/268[============>-------------------------------------------------]21%Task#01:downloading102/274[======================>---------------------------------------]37%Task#02:installing00:03[=========>----------------------------------------------------]17%Task#03:installing00:08[=======>------------------------------------------------------]12%Task#00:downloading57/268[============>-------------------------------------------------]21%Task#01:downloading106/274[=======================>--------------------------------------]39%Task#02:installing00:03[===========>--------------------------------------------------]19%Task#03:installing00:08[=======>------------------------------------------------------]14%Task#00:downloading59/268[=============>------------------------------------------------]22%Task#01:downloading114/274[=========================>------------------------------------]42%Task#02:installing00:03[=============>------------------------------------------------]23%Task#03:installing00:08[========>-----------------------------------------------------]14%Task#00:downloading61/268[=============>------------------------------------------------]23%Task#01:downloading120/274[==========================>-----------------------------------]44%Task#02:installing00:03[===============>----------------------------------------------]25%Task#03:installing00:08[=========>----------------------------------------------------]16%Task#00:downloading63/268[==============>-----------------------------------------------]24%Task#01:downloading126/274[============================>---------------------------------]46%Task#02:installing00:02[=================>--------------------------------------------]29%Task#03:installing00:08[=========>----------------------------------------------------]17%Task#00:downloading67/268[===============>----------------------------------------------]25%Task#01:downloading130/274[============================>---------------------------------]47%Task#02:installing00:02[==================>-------------------------------------------]31%Task#03:installing00:08[==========>---------------------------------------------------]17%Task#00:downloading68/268[===============>----------------------------------------------]25%Task#01:downloading132/274[=============================>--------------------------------]48%Task#02:installing00:02[=====================>----------------------------------------]36%Task#03:installing00:08[===========>--------------------------------------------------]19%Task#00:downloading69/268[===============>----------------------------------------------]26%Task#01:downloading136/274[==============================>-------------------------------]50%Task#02:installing00:02[======================>---------------------------------------]37%Task#03:installing00:08[============>-------------------------------------------------]20%Task#00:downloading71/268[===============>----------------------------------------------]26%Task#01:downloading140/274[===============================>------------------------------]51%Task#02:installing00:02[========================>-------------------------------------]41%Task#03:installing00:07[============>-------------------------------------------------]22%Task#00:downloading73/268[================>---------------------------------------------]27%Task#01:downloading144/274[================================>-----------------------------]53%Task#02:installing00:02[=========================>------------------------------------]42%Task#00:downloading75/268[================>---------------------------------------------]28%Task#01:downloading150/274[=================================>----------------------------]55%Task#02:installing00:02[===========================>----------------------------------]45%Task#00:downloading78/268[=================>--------------------------------------------]29%Task#01:downloading154/274[==================================>---------------------------]56%Task#02:installing00:02[============================>---------------------------------]47%Task#03:installing00:07[===============>----------------------------------------------]26%Task#00:downloading80/268[==================>-------------------------------------------]30%Task#01:downloading158/274[===================================>--------------------------]58%Task#02:installing00:02[==============================>-------------------------------]50%Task#03:installing00:07[================>---------------------------------------------]27%Task#00:downloading82/268[==================>-------------------------------------------]31%Task#01:downloading162/274[====================================>-------------------------]59%Task#02:installing00:02[===============================>------------------------------]51%Task#03:installing00:06[=================>--------------------------------------------]29%Task#00:downloading87/268[===================>------------------------------------------]32%Task#01:downloading164/274[====================================>-------------------------]60%Task#02:installing00:01[==================================>---------------------------]56%Task#03:installing00:06[==================>-------------------------------------------]31%Task#00:downloading90/268[====================>-----------------------------------------]34%Task#01:downloading166/274[=====================================>------------------------]61%Task#02:installing00:01[====================================>-------------------------]60%Task#03:installing00:06[===================>------------------------------------------]32%Task#00:downloading92/268[====================>-----------------------------------------]34%Task#01:downloading172/274[======================================>-----------------------]63%Task#02:installing00:01[======================================>-----------------------]62%Task#03:installing00:05[====================>-----------------------------------------]34%Task#00:downloading93/268[=====================>----------------------------------------]35%Task#01:downloading176/274[=======================================>----------------------]64%Task#02:installing00:01[=======================================>----------------------]65%Task#03:installing00:05[=====================>----------------------------------------]35%Task#00:downloading96/268[=====================>----------------------------------------]36%Task#01:downloading178/274[=======================================>----------------------]65%Task#02:installing00:01[==========================================>-------------------]69%Task#03:installing00:05[=====================>----------------------------------------]36%Task#00:downloading99/268[======================>---------------------------------------]37%Task#01:downloading182/274[========================================>---------------------]66%Task#02:installing00:01[===========================================>------------------]71%Task#03:installing00:05[======================>---------------------------------------]37%Task#00:downloading102/268[=======================>--------------------------------------]38%Task#01:downloading186/274[=========================================>--------------------]68%Task#02:installing00:00[==============================================>---------------]75%Task#03:installing00:06[======================>---------------------------------------]37%Task#00:downloading105/268[=======================>--------------------------------------]39%Task#01:downloading188/274[==========================================>-------------------]69%Task#02:installing00:00[===============================================>--------------]78%Task#03:installing00:06[=======================>--------------------------------------]39%Task#00:downloading107/268[========================>-------------------------------------]40%Task#01:downloading192/274[==========================================>-------------------]70%Task#02:installing00:00[=================================================>------------]80%Task#03:installing00:05[========================>-------------------------------------]40%Task#00:downloading109/268[========================>-------------------------------------]41%Task#01:downloading194/274[===========================================>------------------]71%Task#02:installing00:00[==================================================>-----------]82%Task#03:installing00:05[========================>-------------------------------------]41%Task#00:downloading112/268[=========================>------------------------------------]42%Task#01:downloading198/274[============================================>-----------------]72%Task#02:installing00:00[===================================================>----------]84%Task#03:installing00:05[=========================>------------------------------------]42%Task#00:downloading114/268[=========================>------------------------------------]43%Task#01:downloading202/274[=============================================>----------------]74%Task#02:installing00:00[=====================================================>--------]88%Task#03:installing00:05[==========================>-----------------------------------]44%Task#00:downloading116/268[==========================>-----------------------------------]43%Task#01:downloading206/274[==============================================>---------------]75%Task#02:installing00:00[========================================================>-----]92%Task#03:installing00:04[===========================>----------------------------------]46%Task#00:downloading119/268[===========================>----------------------------------]44%Task#01:downloading210/274[===============================================>--------------]77%Task#02:installing00:00[=========================================================>----]94%Task#03:installing00:04[=============================>--------------------------------]48%Task#00:downloading122/268[===========================>----------------------------------]46%Task#01:downloading212/274[===============================================>--------------]77%Task#02:installing00:00[===========================================================>--]97%Task#03:installing00:04[=============================>--------------------------------]49%Task#00:downloading124/268[============================>---------------------------------]46%Task#01:downloading214/274[===============================================>--------------]78%Task#02:installing00:00[==============================================================]99%Task#03:installing00:04[==============================>-------------------------------]50%Task#00:downloading126/268[============================>---------------------------------]47%Task#01:downloading218/274[================================================>-------------]80%Task#02:installing00:00[==============================================================]100%Task#03:installing00:04[===============================>------------------------------]52%Task#00:downloading127/268[============================>---------------------------------]47%Task#01:downloading220/274[=================================================>------------]80%Task#03:installing00:04[================================>-----------------------------]53%Task#00:downloading130/268[=============================>--------------------------------]49%Task#01:downloading224/274[==================================================>-----------]82%Task#03:installing00:03[=================================>----------------------------]55%Task#00:downloading132/268[==============================>-------------------------------]49%Task#01:downloading230/274[===================================================>----------]84%Task#03:installing00:03[==================================>---------------------------]57%Task#00:downloading134/268[==============================>-------------------------------]50%Task#01:downloading234/274[====================================================>---------]85%Task#03:installing00:03[====================================>-------------------------]59%Task#00:downloading136/268[==============================>-------------------------------]51%Task#01:downloading238/274[=====================================================>--------]87%Task#03:installing00:03[====================================>-------------------------]60%Task#00:downloading139/268[===============================>------------------------------]52%Task#01:downloading242/274[======================================================>-------]88%Task#03:installing00:03[=====================================>------------------------]61%Task#00:downloading141/268[================================>-----------------------------]53%Task#01:downloading246/274[=======================================================>------]90%Task#03:installing00:03[======================================>-----------------------]63%Task#00:downloading143/268[================================>-----------------------------]53%Task#01:downloading254/274[========================================================>-----]93%Task#03:installing00:02[=======================================>----------------------]65%Task#00:downloading147/268[=================================>----------------------------]55%Task#01:downloading258/274[=========================================================>----]94%Task#03:installing00:02[========================================>---------------------]66%Task#00:downloading149/268[=================================>----------------------------]56%Task#01:downloading262/274[==========================================================>---]96%Task#03:installing00:02[=========================================>--------------------]68%Task#00:downloading150/268[==================================>---------------------------]56%Task#01:downloading268/274[============================================================>-]98%Task#03:installing00:02[==========================================>-------------------]69%Task#00:downloading152/268[==================================>---------------------------]57%Task#01:downloading272/274[==============================================================]99%Task#03:installing00:02[===========================================>------------------]70%Task#00:downloading156/268[===================================>--------------------------]58%Task#01:downloading274/274[==============================================================]100%Task#03:installing00:02[===========================================>------------------]71%Task#00:downloading160/268[====================================>-------------------------]60%Task#01:installing00:00[==>-----------------------------------------------------------]5%Task#03:installing00:02[============================================>-----------------]73%Task#00:downloading162/268[====================================>-------------------------]60%Task#01:installing00:00[====>---------------------------------------------------------]8%Task#03:installing00:02[=============================================>----------------]74%Task#00:downloading163/268[=====================================>------------------------]61%Task#01:installing00:00[=======>------------------------------------------------------]14%Task#03:installing00:02[=============================================>----------------]75%Task#00:downloading168/268[======================================>-----------------------]63%Task#01:installing00:00[==========>---------------------------------------------------]17%Task#03:installing00:02[==============================================>---------------]76%Task#00:downloading170/268[======================================>-----------------------]63%Task#01:installing00:02[============>-------------------------------------------------]20%Task#03:installing00:02[===============================================>--------------]77%Task#00:downloading173/268[=======================================>----------------------]65%Task#01:installing00:02[===============>----------------------------------------------]25%Task#03:installing00:01[================================================>-------------]78%Task#00:downloading176/268[========================================>---------------------]66%Task#01:installing00:02[==================>-------------------------------------------]31%Task#03:installing00:01[================================================>-------------]79%Task#00:downloading178/268[========================================>---------------------]66%Task#01:installing00:01[=====================>----------------------------------------]36%Task#03:installing00:01[=================================================>------------]81%Task#00:downloading180/268[=========================================>--------------------]67%Task#01:installing00:01[======================>---------------------------------------]37%Task#03:installing00:01[==================================================>-----------]83%Task#00:downloading182/268[=========================================>--------------------]68%Task#01:installing00:01[========================>-------------------------------------]41%Task#03:installing00:01[===================================================>----------]83%Task#00:downloading185/268[==========================================>-------------------]69%Task#01:installing00:01[=========================>------------------------------------]42%Task#03:installing00:01[===================================================>----------]84%Task#00:downloading188/268[==========================================>-------------------]70%Task#01:installing00:01[===========================>----------------------------------]46%Task#03:installing00:01[====================================================>---------]85%Task#00:downloading190/268[===========================================>------------------]71%Task#01:installing00:01[=============================>--------------------------------]49%Task#03:installing00:01[=====================================================>--------]87%Task#00:downloading192/268[===========================================>------------------]72%Task#01:installing00:01[================================>-----------------------------]53%Task#03:installing00:01[======================================================>-------]88%Task#00:downloading194/268[============================================>-----------------]72%Task#01:installing00:01[=================================>----------------------------]54%Task#03:installing00:00[======================================================>-------]89%Task#00:downloading197/268[=============================================>----------------]74%Task#01:installing00:01[===================================>--------------------------]58%Task#03:installing00:00[=======================================================>------]91%Task#00:downloading198/268[=============================================>----------------]74%Task#01:installing00:01[=====================================>------------------------]61%Task#03:installing00:00[========================================================>-----]93%Task#00:downloading202/268[==============================================>---------------]75%Task#01:installing00:01[======================================>-----------------------]63%Task#03:installing00:00[=========================================================>----]93%Task#00:downloading204/268[==============================================>---------------]76%Task#01:installing00:01[========================================>---------------------]66%Task#03:installing00:00[==========================================================>---]94%Task#00:downloading206/268[===============================================>--------------]77%Task#01:installing00:01[==========================================>-------------------]69%Task#03:installing00:00[===========================================================>--]97%Task#00:downloading209/268[===============================================>--------------]78%Task#01:installing00:00[============================================>-----------------]73%Task#03:installing00:00[===========================================================>--]98%Task#00:downloading212/268[================================================>-------------]79%Task#01:installing00:00[==============================================>---------------]76%Task#03:installing00:00[============================================================>-]99%Task#00:downloading213/268[================================================>-------------]79%Task#01:installing00:00[================================================>-------------]80%Task#03:installing00:00[==============================================================]100%Task#00:downloading215/268[=================================================>------------]80%Task#01:installing00:00[=================================================>------------]81%Task#00:downloading217/268[=================================================>------------]81%Task#01:installing00:00[=====================================================>--------]86%Task#00:downloading219/268[==================================================>-----------]82%Task#01:installing00:00[======================================================>-------]88%Task#00:downloading220/268[==================================================>-----------]82%Task#01:installing00:00[========================================================>-----]92%Task#00:downloading221/268[==================================================>-----------]82%Task#01:installing00:00[=========================================================>----]93%Task#00:downloading225/268[===================================================>----------]84%Task#01:installing00:00[===========================================================>--]97%Task#00:downloading227/268[====================================================>---------]85%Task#01:installing00:00[============================================================>-]98%Task#00:downloading229/268[====================================================>---------]85%Task#01:installing00:00[==============================================================]100%Task#00:downloading230/268[====================================================>---------]86%Task#00:downloading232/268[=====================================================>--------]87%Task#00:downloading233/268[=====================================================>--------]87%Task#00:downloading235/268[=====================================================>--------]88%Task#00:downloading236/268[======================================================>-------]88%Task#00:downloading237/268[======================================================>-------]88%Task#00:downloading240/268[=======================================================>------]90%Task#00:downloading241/268[=======================================================>------]90%Task#00:downloading244/268[=======================================================>------]91%Task#00:downloading246/268[========================================================>-----]92%Task#00:downloading249/268[=========================================================>----]93%Task#00:downloading251/268[=========================================================>----]94%Task#00:downloading253/268[==========================================================>---]94%Task#00:downloading256/268[==========================================================>---]96%Task#00:downloading257/268[==========================================================>---]96%Task#00:downloading259/268[===========================================================>--]97%Task#00:downloading261/268[===========================================================>--]97%Task#00:downloading262/268[============================================================>-]98%Task#00:downloading263/268[============================================================>-]98%Task#00:downloading266/268[==============================================================]99%Task#00:downloading268/268[==============================================================]100%Task#00:installing00:00[=>------------------------------------------------------------]3%Task#00:installing00:00[======>-------------------------------------------------------]12%Task#00:installing00:00[========>-----------------------------------------------------]14%Task#00:installing00:00[============>-------------------------------------------------]20%Task#00:installing00:00[=================>--------------------------------------------]29%Task#00:installing00:01[===================>------------------------------------------]32%Task#00:installing00:01[==========================>-----------------------------------]43%Task#00:installing00:01[==============================>-------------------------------]49%Task#00:installing00:00[=================================>----------------------------]55%Task#00:installing00:00[=====================================>------------------------]61%Task#00:installing00:00[========================================>---------------------]67%Task#00:installing00:00[============================================>-----------------]72%Task#00:installing00:00[=================================================>------------]81%Task#00:installing00:00[=====================================================>--------]87%Task#00:installing00:00[=========================================================>----]93%Task#00:installing00:00[============================================================>-]99%Task#00:installing00:00[==============================================================]100%mpb-7.3.2/bar.go000066400000000000000000000324731417272200500134050ustar00rootroot00000000000000package mpb import ( "bytes" "context" "fmt" "io" "runtime/debug" "strings" "sync" "time" "github.com/acarl005/stripansi" "github.com/mattn/go-runewidth" "github.com/vbauerster/mpb/v7/decor" ) // Bar represents a progress bar. type Bar struct { priority int // used by heap index int // used by heap toShutdown bool toDrop bool noPop bool hasEwmaDecorators bool operateState chan func(*bState) frameCh chan *frame // cancel is called either by user or on complete event cancel func() // done is closed after cacheState is assigned done chan struct{} // cacheState is populated, right after close(b.done) cacheState *bState container *Progress recoveredPanic interface{} } type extenderFunc func(in io.Reader, reqWidth int, st decor.Statistics) (out io.Reader, lines int) // bState is actual bar state. It gets passed to *Bar.serve(...) monitor // goroutine. type bState struct { id int priority int reqWidth int total int64 current int64 refill int64 lastIncrement int64 trimSpace bool completed bool completeFlushed bool aborted bool triggerComplete bool dropOnComplete bool noPop bool aDecorators []decor.Decorator pDecorators []decor.Decorator averageDecorators []decor.AverageDecorator ewmaDecorators []decor.EwmaDecorator shutdownListeners []decor.ShutdownListener buffers [3]*bytes.Buffer filler BarFiller middleware func(BarFiller) BarFiller extender extenderFunc // runningBar is a key for *pState.parkedBars runningBar *Bar debugOut io.Writer } type frame struct { reader io.Reader lines int } func newBar(container *Progress, bs *bState) *Bar { ctx, cancel := context.WithCancel(container.ctx) bar := &Bar{ container: container, priority: bs.priority, toDrop: bs.dropOnComplete, noPop: bs.noPop, operateState: make(chan func(*bState)), frameCh: make(chan *frame, 1), done: make(chan struct{}), cancel: cancel, } go bar.serve(ctx, bs) return bar } // ProxyReader wraps r with metrics required for progress tracking. // Panics if r is nil. func (b *Bar) ProxyReader(r io.Reader) io.ReadCloser { if r == nil { panic("expected non nil io.Reader") } return b.newProxyReader(r) } // ID returs id of the bar. func (b *Bar) ID() int { result := make(chan int) select { case b.operateState <- func(s *bState) { result <- s.id }: return <-result case <-b.done: return b.cacheState.id } } // Current returns bar's current number, in other words sum of all increments. func (b *Bar) Current() int64 { result := make(chan int64) select { case b.operateState <- func(s *bState) { result <- s.current }: return <-result case <-b.done: return b.cacheState.current } } // SetRefill sets refill flag with specified amount. // The underlying BarFiller will change its visual representation, to // indicate refill event. Refill event may be referred to some retry // operation for example. func (b *Bar) SetRefill(amount int64) { select { case b.operateState <- func(s *bState) { s.refill = amount }: case <-b.done: } } // TraverseDecorators traverses all available decorators and calls cb func on each. func (b *Bar) TraverseDecorators(cb func(decor.Decorator)) { done := make(chan struct{}) select { case b.operateState <- func(s *bState) { for _, decorators := range [...][]decor.Decorator{ s.pDecorators, s.aDecorators, } { for _, d := range decorators { cb(extractBaseDecorator(d)) } } close(done) }: <-done case <-b.done: } } // SetTotal sets total dynamically. // If total is negative it takes progress' current value. func (b *Bar) SetTotal(total int64, triggerComplete bool) { select { case b.operateState <- func(s *bState) { s.triggerComplete = triggerComplete if total < 0 { s.total = s.current } else { s.total = total } if s.triggerComplete && !s.completed { s.current = s.total s.completed = true go b.forceRefreshIfLastUncompleted() } }: case <-b.done: } } // SetCurrent sets progress' current to an arbitrary value. // Setting a negative value will cause a panic. func (b *Bar) SetCurrent(current int64) { select { case b.operateState <- func(s *bState) { s.lastIncrement = current - s.current s.current = current if s.triggerComplete && s.current >= s.total { s.current = s.total s.completed = true go b.forceRefreshIfLastUncompleted() } }: case <-b.done: } } // Increment is a shorthand for b.IncrInt64(1). func (b *Bar) Increment() { b.IncrInt64(1) } // IncrBy is a shorthand for b.IncrInt64(int64(n)). func (b *Bar) IncrBy(n int) { b.IncrInt64(int64(n)) } // IncrInt64 increments progress by amount of n. func (b *Bar) IncrInt64(n int64) { if n <= 0 { return } select { case b.operateState <- func(s *bState) { s.lastIncrement = n s.current += n if s.triggerComplete && s.current >= s.total { s.current = s.total s.completed = true go b.forceRefreshIfLastUncompleted() } }: case <-b.done: } } // DecoratorEwmaUpdate updates all EWMA based decorators. Should be // called on each iteration, because EWMA's unit of measure is an // iteration's duration. Panics if called before *Bar.Incr... family // methods. func (b *Bar) DecoratorEwmaUpdate(dur time.Duration) { select { case b.operateState <- func(s *bState) { if s.lastIncrement > 0 { s.decoratorEwmaUpdate(dur) s.lastIncrement = 0 } else { panic("increment required before ewma iteration update") } }: case <-b.done: if b.cacheState.lastIncrement > 0 { b.cacheState.decoratorEwmaUpdate(dur) b.cacheState.lastIncrement = 0 } } } // DecoratorAverageAdjust adjusts all average based decorators. Call // if you need to adjust start time of all average based decorators // or after progress resume. func (b *Bar) DecoratorAverageAdjust(start time.Time) { select { case b.operateState <- func(s *bState) { s.decoratorAverageAdjust(start) }: case <-b.done: } } // SetPriority changes bar's order among multiple bars. Zero is highest // priority, i.e. bar will be on top. If you don't need to set priority // dynamically, better use BarPriority option. func (b *Bar) SetPriority(priority int) { b.container.UpdateBarPriority(b, priority) } // Abort interrupts bar's running goroutine. Abort won't be engaged // if bar is already in complete state. If drop is true bar will be // removed as well. func (b *Bar) Abort(drop bool) { done := make(chan struct{}) select { case b.operateState <- func(s *bState) { if s.completed { close(done) return } s.aborted = true b.cancel() // container must be run during lifetime of this inner goroutine // we control this by done channel declared above go func() { if drop { b.container.dropBar(b) } else { var uncompleted int b.container.traverseBars(func(bar *Bar) bool { if b != bar && !bar.Completed() { uncompleted++ return false } return true }) if uncompleted == 0 { b.container.refreshCh <- time.Now() } } close(done) // release hold of Abort }() }: // guarantee: container is alive during lifetime of this hold <-done case <-b.done: } } // Completed reports whether the bar is in completed state. func (b *Bar) Completed() bool { result := make(chan bool) select { case b.operateState <- func(s *bState) { result <- s.completed }: return <-result case <-b.done: return true } } func (b *Bar) serve(ctx context.Context, s *bState) { defer b.container.bwg.Done() for { select { case op := <-b.operateState: op(s) case <-ctx.Done(): s.decoratorShutdownNotify() b.cacheState = s close(b.done) return } } } func (b *Bar) render(tw int) { select { case b.operateState <- func(s *bState) { stat := newStatistics(tw, s) defer func() { // recovering if user defined decorator panics for example if p := recover(); p != nil { if b.recoveredPanic == nil { if s.debugOut != nil { fmt.Fprintln(s.debugOut, p) _, _ = s.debugOut.Write(debug.Stack()) } s.extender = makePanicExtender(p) b.toShutdown = !b.toShutdown b.recoveredPanic = p } reader, lines := s.extender(nil, s.reqWidth, stat) b.frameCh <- &frame{reader, lines + 1} } s.completeFlushed = s.completed }() reader, lines := s.extender(s.draw(stat), s.reqWidth, stat) b.toShutdown = s.completed && !s.completeFlushed b.frameCh <- &frame{reader, lines + 1} }: case <-b.done: s := b.cacheState stat := newStatistics(tw, s) var r io.Reader if b.recoveredPanic == nil { r = s.draw(stat) } reader, lines := s.extender(r, s.reqWidth, stat) b.frameCh <- &frame{reader, lines + 1} } } func (b *Bar) subscribeDecorators() { var averageDecorators []decor.AverageDecorator var ewmaDecorators []decor.EwmaDecorator var shutdownListeners []decor.ShutdownListener b.TraverseDecorators(func(d decor.Decorator) { if d, ok := d.(decor.AverageDecorator); ok { averageDecorators = append(averageDecorators, d) } if d, ok := d.(decor.EwmaDecorator); ok { ewmaDecorators = append(ewmaDecorators, d) } if d, ok := d.(decor.ShutdownListener); ok { shutdownListeners = append(shutdownListeners, d) } }) b.hasEwmaDecorators = len(ewmaDecorators) != 0 select { case b.operateState <- func(s *bState) { s.averageDecorators = averageDecorators s.ewmaDecorators = ewmaDecorators s.shutdownListeners = shutdownListeners }: case <-b.done: } } func (b *Bar) forceRefreshIfLastUncompleted() { var uncompleted int b.container.traverseBars(func(bar *Bar) bool { if b != bar && !bar.Completed() { uncompleted++ return false } return true }) if uncompleted == 0 { for { select { case b.container.refreshCh <- time.Now(): case <-b.done: return } } } } func (b *Bar) wSyncTable() [][]chan int { result := make(chan [][]chan int) select { case b.operateState <- func(s *bState) { result <- s.wSyncTable() }: return <-result case <-b.done: return b.cacheState.wSyncTable() } } func (s *bState) draw(stat decor.Statistics) io.Reader { bufP, bufB, bufA := s.buffers[0], s.buffers[1], s.buffers[2] nlr := strings.NewReader("\n") tw := stat.AvailableWidth for _, d := range s.pDecorators { str := d.Decor(stat) stat.AvailableWidth -= runewidth.StringWidth(stripansi.Strip(str)) bufP.WriteString(str) } if stat.AvailableWidth < 1 { trunc := strings.NewReader(runewidth.Truncate(stripansi.Strip(bufP.String()), tw, "…")) bufP.Reset() return io.MultiReader(trunc, nlr) } if !s.trimSpace && stat.AvailableWidth > 1 { stat.AvailableWidth -= 2 bufB.WriteByte(' ') defer bufB.WriteByte(' ') } tw = stat.AvailableWidth for _, d := range s.aDecorators { str := d.Decor(stat) stat.AvailableWidth -= runewidth.StringWidth(stripansi.Strip(str)) bufA.WriteString(str) } if stat.AvailableWidth < 1 { trunc := strings.NewReader(runewidth.Truncate(stripansi.Strip(bufA.String()), tw, "…")) bufA.Reset() return io.MultiReader(bufP, bufB, trunc, nlr) } s.filler.Fill(bufB, s.reqWidth, stat) return io.MultiReader(bufP, bufB, bufA, nlr) } func (s *bState) wSyncTable() [][]chan int { columns := make([]chan int, 0, len(s.pDecorators)+len(s.aDecorators)) var pCount int for _, d := range s.pDecorators { if ch, ok := d.Sync(); ok { columns = append(columns, ch) pCount++ } } var aCount int for _, d := range s.aDecorators { if ch, ok := d.Sync(); ok { columns = append(columns, ch) aCount++ } } table := make([][]chan int, 2) table[0] = columns[0:pCount] table[1] = columns[pCount : pCount+aCount : pCount+aCount] return table } func (s bState) decoratorEwmaUpdate(dur time.Duration) { wg := new(sync.WaitGroup) for i := 0; i < len(s.ewmaDecorators); i++ { switch d := s.ewmaDecorators[i]; i { case len(s.ewmaDecorators) - 1: d.EwmaUpdate(s.lastIncrement, dur) default: wg.Add(1) go func() { d.EwmaUpdate(s.lastIncrement, dur) wg.Done() }() } } wg.Wait() } func (s bState) decoratorAverageAdjust(start time.Time) { wg := new(sync.WaitGroup) for i := 0; i < len(s.averageDecorators); i++ { switch d := s.averageDecorators[i]; i { case len(s.averageDecorators) - 1: d.AverageAdjust(start) default: wg.Add(1) go func() { d.AverageAdjust(start) wg.Done() }() } } wg.Wait() } func (s bState) decoratorShutdownNotify() { wg := new(sync.WaitGroup) for i := 0; i < len(s.shutdownListeners); i++ { switch d := s.shutdownListeners[i]; i { case len(s.shutdownListeners) - 1: d.Shutdown() default: wg.Add(1) go func() { d.Shutdown() wg.Done() }() } } wg.Wait() } func newStatistics(tw int, s *bState) decor.Statistics { return decor.Statistics{ ID: s.id, AvailableWidth: tw, Total: s.total, Current: s.current, Refill: s.refill, Completed: s.completeFlushed, Aborted: s.aborted, } } func extractBaseDecorator(d decor.Decorator) decor.Decorator { if d, ok := d.(decor.Wrapper); ok { return extractBaseDecorator(d.Base()) } return d } func makePanicExtender(p interface{}) extenderFunc { pstr := fmt.Sprint(p) return func(_ io.Reader, _ int, st decor.Statistics) (io.Reader, int) { mr := io.MultiReader( strings.NewReader(runewidth.Truncate(pstr, st.AvailableWidth, "…")), strings.NewReader("\n"), ) return mr, 0 } } mpb-7.3.2/bar_filler.go000066400000000000000000000023621417272200500147340ustar00rootroot00000000000000package mpb import ( "io" "github.com/vbauerster/mpb/v7/decor" ) // BarFiller interface. // Bar (without decorators) renders itself by calling BarFiller's Fill method. // // reqWidth is requested width set by `func WithWidth(int) ContainerOption`. // If not set, it defaults to terminal width. // type BarFiller interface { Fill(w io.Writer, reqWidth int, stat decor.Statistics) } // BarFillerBuilder interface. // Default implementations are: // // BarStyle() // SpinnerStyle() // NopStyle() // type BarFillerBuilder interface { Build() BarFiller } // BarFillerFunc is function type adapter to convert compatible function // into BarFiller interface. type BarFillerFunc func(w io.Writer, reqWidth int, stat decor.Statistics) func (f BarFillerFunc) Fill(w io.Writer, reqWidth int, stat decor.Statistics) { f(w, reqWidth, stat) } // BarFillerBuilderFunc is function type adapter to convert compatible // function into BarFillerBuilder interface. type BarFillerBuilderFunc func() BarFiller func (f BarFillerBuilderFunc) Build() BarFiller { return f() } // NewBarFiller constructs a BarFiller from provided BarFillerBuilder. // Deprecated. Prefer using `*Progress.New(...)` directly. func NewBarFiller(b BarFillerBuilder) BarFiller { return b.Build() } mpb-7.3.2/bar_filler_bar.go000066400000000000000000000126231417272200500155610ustar00rootroot00000000000000package mpb import ( "io" "github.com/acarl005/stripansi" "github.com/mattn/go-runewidth" "github.com/vbauerster/mpb/v7/decor" "github.com/vbauerster/mpb/v7/internal" ) const ( iLbound = iota iRbound iFiller iRefiller iPadding components ) // BarStyleComposer interface. type BarStyleComposer interface { BarFillerBuilder Lbound(string) BarStyleComposer Rbound(string) BarStyleComposer Filler(string) BarStyleComposer Refiller(string) BarStyleComposer Padding(string) BarStyleComposer TipOnComplete(string) BarStyleComposer Tip(frames ...string) BarStyleComposer Reverse() BarStyleComposer } type bFiller struct { rev bool components [components]*component tip struct { count uint onComplete *component frames []*component } } type component struct { width int bytes []byte } type barStyle struct { lbound string rbound string filler string refiller string padding string tipOnComplete string tipFrames []string rev bool } // BarStyle constructs default bar style which can be altered via // BarStyleComposer interface. func BarStyle() BarStyleComposer { return &barStyle{ lbound: "[", rbound: "]", filler: "=", refiller: "+", padding: "-", tipFrames: []string{">"}, } } func (s *barStyle) Lbound(bound string) BarStyleComposer { s.lbound = bound return s } func (s *barStyle) Rbound(bound string) BarStyleComposer { s.rbound = bound return s } func (s *barStyle) Filler(filler string) BarStyleComposer { s.filler = filler return s } func (s *barStyle) Refiller(refiller string) BarStyleComposer { s.refiller = refiller return s } func (s *barStyle) Padding(padding string) BarStyleComposer { s.padding = padding return s } func (s *barStyle) TipOnComplete(tip string) BarStyleComposer { s.tipOnComplete = tip return s } func (s *barStyle) Tip(frames ...string) BarStyleComposer { if len(frames) != 0 { s.tipFrames = append(s.tipFrames[:0], frames...) } return s } func (s *barStyle) Reverse() BarStyleComposer { s.rev = true return s } func (s *barStyle) Build() BarFiller { bf := &bFiller{rev: s.rev} bf.components[iLbound] = &component{ width: runewidth.StringWidth(stripansi.Strip(s.lbound)), bytes: []byte(s.lbound), } bf.components[iRbound] = &component{ width: runewidth.StringWidth(stripansi.Strip(s.rbound)), bytes: []byte(s.rbound), } bf.components[iFiller] = &component{ width: runewidth.StringWidth(stripansi.Strip(s.filler)), bytes: []byte(s.filler), } bf.components[iRefiller] = &component{ width: runewidth.StringWidth(stripansi.Strip(s.refiller)), bytes: []byte(s.refiller), } bf.components[iPadding] = &component{ width: runewidth.StringWidth(stripansi.Strip(s.padding)), bytes: []byte(s.padding), } bf.tip.onComplete = &component{ width: runewidth.StringWidth(stripansi.Strip(s.tipOnComplete)), bytes: []byte(s.tipOnComplete), } bf.tip.frames = make([]*component, len(s.tipFrames)) for i, t := range s.tipFrames { bf.tip.frames[i] = &component{ width: runewidth.StringWidth(stripansi.Strip(t)), bytes: []byte(t), } } return bf } func (s *bFiller) Fill(w io.Writer, width int, stat decor.Statistics) { width = internal.CheckRequestedWidth(width, stat.AvailableWidth) brackets := s.components[iLbound].width + s.components[iRbound].width // don't count brackets as progress width -= brackets if width < 0 { return } ow := optimisticWriter(w) ow(s.components[iLbound].bytes) defer ow(s.components[iRbound].bytes) if width == 0 { return } var filling [][]byte var padding [][]byte var tip *component var filled int var refWidth int curWidth := int(internal.PercentageRound(stat.Total, stat.Current, uint(width))) if stat.Current >= stat.Total { tip = s.tip.onComplete } else { tip = s.tip.frames[s.tip.count%uint(len(s.tip.frames))] } if curWidth > 0 { filling = append(filling, tip.bytes) filled += tip.width s.tip.count++ } if stat.Refill > 0 { refWidth = int(internal.PercentageRound(stat.Total, stat.Refill, uint(width))) curWidth -= refWidth refWidth += curWidth } for filled < curWidth { if curWidth-filled >= s.components[iFiller].width { filling = append(filling, s.components[iFiller].bytes) if s.components[iFiller].width == 0 { break } filled += s.components[iFiller].width } else { filling = append(filling, []byte("…")) filled++ } } for filled < refWidth { if refWidth-filled >= s.components[iRefiller].width { filling = append(filling, s.components[iRefiller].bytes) if s.components[iRefiller].width == 0 { break } filled += s.components[iRefiller].width } else { filling = append(filling, []byte("…")) filled++ } } padWidth := width - filled for padWidth > 0 { if padWidth >= s.components[iPadding].width { padding = append(padding, s.components[iPadding].bytes) if s.components[iPadding].width == 0 { break } padWidth -= s.components[iPadding].width } else { padding = append(padding, []byte("…")) padWidth-- } } if s.rev { flush(ow, padding, filling) } else { flush(ow, filling, padding) } } func flush(ow func([]byte), filling, padding [][]byte) { for i := len(filling) - 1; i >= 0; i-- { ow(filling[i]) } for i := 0; i < len(padding); i++ { ow(padding[i]) } } func optimisticWriter(w io.Writer) func([]byte) { return func(p []byte) { _, err := w.Write(p) if err != nil { panic(err) } } } mpb-7.3.2/bar_filler_nop.go000066400000000000000000000004431417272200500156060ustar00rootroot00000000000000package mpb import ( "io" "github.com/vbauerster/mpb/v7/decor" ) // NopStyle provides BarFillerBuilder which builds NOP BarFiller. func NopStyle() BarFillerBuilder { return BarFillerBuilderFunc(func() BarFiller { return BarFillerFunc(func(io.Writer, int, decor.Statistics) {}) }) } mpb-7.3.2/bar_filler_spinner.go000066400000000000000000000036271417272200500164770ustar00rootroot00000000000000package mpb import ( "io" "strings" "github.com/acarl005/stripansi" "github.com/mattn/go-runewidth" "github.com/vbauerster/mpb/v7/decor" "github.com/vbauerster/mpb/v7/internal" ) const ( positionLeft = 1 + iota positionRight ) // SpinnerStyleComposer interface. type SpinnerStyleComposer interface { BarFillerBuilder PositionLeft() SpinnerStyleComposer PositionRight() SpinnerStyleComposer } type sFiller struct { count uint position uint frames []string } type spinnerStyle struct { position uint frames []string } // SpinnerStyle constructs default spinner style which can be altered via // SpinnerStyleComposer interface. func SpinnerStyle(frames ...string) SpinnerStyleComposer { ss := new(spinnerStyle) if len(frames) != 0 { ss.frames = append(ss.frames, frames...) } else { ss.frames = []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"} } return ss } func (s *spinnerStyle) PositionLeft() SpinnerStyleComposer { s.position = positionLeft return s } func (s *spinnerStyle) PositionRight() SpinnerStyleComposer { s.position = positionRight return s } func (s *spinnerStyle) Build() BarFiller { sf := &sFiller{ position: s.position, frames: s.frames, } return sf } func (s *sFiller) Fill(w io.Writer, width int, stat decor.Statistics) { width = internal.CheckRequestedWidth(width, stat.AvailableWidth) frame := s.frames[s.count%uint(len(s.frames))] frameWidth := runewidth.StringWidth(stripansi.Strip(frame)) if width < frameWidth { return } var err error rest := width - frameWidth switch s.position { case positionLeft: _, err = io.WriteString(w, frame+strings.Repeat(" ", rest)) case positionRight: _, err = io.WriteString(w, strings.Repeat(" ", rest)+frame) default: str := strings.Repeat(" ", rest/2) + frame + strings.Repeat(" ", rest/2+rest%2) _, err = io.WriteString(w, str) } if err != nil { panic(err) } s.count++ } mpb-7.3.2/bar_option.go000066400000000000000000000100601417272200500147610ustar00rootroot00000000000000package mpb import ( "bytes" "io" "github.com/vbauerster/mpb/v7/decor" ) // BarOption is a func option to alter default behavior of a bar. type BarOption func(*bState) func skipNil(decorators []decor.Decorator) (filtered []decor.Decorator) { for _, d := range decorators { if d != nil { filtered = append(filtered, d) } } return } func (s *bState) addDecorators(dest *[]decor.Decorator, decorators ...decor.Decorator) { type mergeWrapper interface { MergeUnwrap() []decor.Decorator } for _, decorator := range decorators { if mw, ok := decorator.(mergeWrapper); ok { *dest = append(*dest, mw.MergeUnwrap()...) } *dest = append(*dest, decorator) } } // AppendDecorators let you inject decorators to the bar's right side. func AppendDecorators(decorators ...decor.Decorator) BarOption { return func(s *bState) { s.addDecorators(&s.aDecorators, skipNil(decorators)...) } } // PrependDecorators let you inject decorators to the bar's left side. func PrependDecorators(decorators ...decor.Decorator) BarOption { return func(s *bState) { s.addDecorators(&s.pDecorators, skipNil(decorators)...) } } // BarID sets bar id. func BarID(id int) BarOption { return func(s *bState) { s.id = id } } // BarWidth sets bar width independent of the container. func BarWidth(width int) BarOption { return func(s *bState) { s.reqWidth = width } } // BarQueueAfter queues this (being constructed) bar to relplace // runningBar after it has been completed. func BarQueueAfter(runningBar *Bar) BarOption { if runningBar == nil { return nil } return func(s *bState) { s.runningBar = runningBar } } // BarRemoveOnComplete removes both bar's filler and its decorators // on complete event. func BarRemoveOnComplete() BarOption { return func(s *bState) { s.dropOnComplete = true } } // BarFillerClearOnComplete clears bar's filler on complete event. // It's shortcut for BarFillerOnComplete(""). func BarFillerClearOnComplete() BarOption { return BarFillerOnComplete("") } // BarFillerOnComplete replaces bar's filler with message, on complete event. func BarFillerOnComplete(message string) BarOption { return BarFillerMiddleware(func(base BarFiller) BarFiller { return BarFillerFunc(func(w io.Writer, reqWidth int, st decor.Statistics) { if st.Completed { _, err := io.WriteString(w, message) if err != nil { panic(err) } } else { base.Fill(w, reqWidth, st) } }) }) } // BarFillerMiddleware provides a way to augment the underlying BarFiller. func BarFillerMiddleware(middle func(BarFiller) BarFiller) BarOption { return func(s *bState) { s.middleware = middle } } // BarPriority sets bar's priority. Zero is highest priority, i.e. bar // will be on top. If `BarReplaceOnComplete` option is supplied, this // option is ignored. func BarPriority(priority int) BarOption { return func(s *bState) { s.priority = priority } } // BarExtender provides a way to extend bar to the next new line. func BarExtender(filler BarFiller) BarOption { if filler == nil { return nil } return func(s *bState) { s.extender = makeExtenderFunc(filler) } } func makeExtenderFunc(filler BarFiller) extenderFunc { buf := new(bytes.Buffer) return func(r io.Reader, reqWidth int, st decor.Statistics) (io.Reader, int) { filler.Fill(buf, reqWidth, st) return io.MultiReader(r, buf), bytes.Count(buf.Bytes(), []byte("\n")) } } // BarFillerTrim removes leading and trailing space around the underlying BarFiller. func BarFillerTrim() BarOption { return func(s *bState) { s.trimSpace = true } } // BarNoPop disables bar pop out of container. Effective when // PopCompletedMode of container is enabled. func BarNoPop() BarOption { return func(s *bState) { s.noPop = true } } // BarOptional will invoke provided option only when cond is true. func BarOptional(option BarOption, cond bool) BarOption { if cond { return option } return nil } // BarOptOn will invoke provided option only when higher order predicate // evaluates to true. func BarOptOn(option BarOption, predicate func() bool) BarOption { if predicate() { return option } return nil } mpb-7.3.2/bar_test.go000066400000000000000000000143101417272200500144320ustar00rootroot00000000000000package mpb_test import ( "bytes" "fmt" "io/ioutil" "strings" "sync/atomic" "testing" "time" "unicode/utf8" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func TestBarCompleted(t *testing.T) { p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(ioutil.Discard)) total := 80 bar := p.AddBar(int64(total)) var count int for !bar.Completed() { time.Sleep(10 * time.Millisecond) bar.Increment() count++ } p.Wait() if count != total { t.Errorf("got count: %d, expected %d\n", count, total) } } func TestBarID(t *testing.T) { p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(ioutil.Discard)) total := 100 wantID := 11 bar := p.AddBar(int64(total), mpb.BarID(wantID)) go func() { for i := 0; i < total; i++ { time.Sleep(50 * time.Millisecond) bar.Increment() } }() gotID := bar.ID() if gotID != wantID { t.Errorf("Expected bar id: %d, got %d\n", wantID, gotID) } bar.Abort(true) p.Wait() } func TestBarSetRefill(t *testing.T) { var buf bytes.Buffer p := mpb.New(mpb.WithOutput(&buf), mpb.WithWidth(100)) total := 100 till := 30 refiller := "+" bar := p.New(int64(total), mpb.BarStyle().Refiller(refiller), mpb.BarFillerTrim()) bar.SetRefill(int64(till)) bar.IncrBy(till) for i := 0; i < total-till; i++ { bar.Increment() time.Sleep(10 * time.Millisecond) } p.Wait() wantBar := fmt.Sprintf("[%s%s]", strings.Repeat(refiller, till-1), strings.Repeat("=", total-till-1), ) got := string(getLastLine(buf.Bytes())) if !strings.Contains(got, wantBar) { t.Errorf("Want bar: %q, got bar: %q\n", wantBar, got) } } func TestBarHas100PercentWithOnCompleteDecorator(t *testing.T) { var buf bytes.Buffer p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(&buf)) total := 50 bar := p.AddBar(int64(total), mpb.AppendDecorators( decor.OnComplete( decor.Percentage(), "done", ), ), ) for i := 0; i < total; i++ { bar.Increment() time.Sleep(10 * time.Millisecond) } p.Wait() hundred := "100 %" if !bytes.Contains(buf.Bytes(), []byte(hundred)) { t.Errorf("Bar's buffer does not contain: %q\n", hundred) } } func TestBarHas100PercentWithBarRemoveOnComplete(t *testing.T) { var buf bytes.Buffer p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(&buf)) total := 50 bar := p.AddBar(int64(total), mpb.BarRemoveOnComplete(), mpb.AppendDecorators(decor.Percentage()), ) for i := 0; i < total; i++ { bar.Increment() time.Sleep(10 * time.Millisecond) } p.Wait() hundred := "100 %" if !bytes.Contains(buf.Bytes(), []byte(hundred)) { t.Errorf("Bar's buffer does not contain: %q\n", hundred) } } func TestBarStyle(t *testing.T) { var buf bytes.Buffer customFormat := "╢▌▌░╟" runes := []rune(customFormat) total := 80 p := mpb.New(mpb.WithWidth(total), mpb.WithOutput(&buf)) bs := mpb.BarStyle() bs.Lbound(string(runes[0])) bs.Filler(string(runes[1])) bs.Tip(string(runes[2])) bs.Padding(string(runes[3])) bs.Rbound(string(runes[4])) bar := p.New(int64(total), bs, mpb.BarFillerTrim()) for i := 0; i < total; i++ { bar.Increment() time.Sleep(10 * time.Millisecond) } p.Wait() wantBar := fmt.Sprintf("%s%s%s%s", string(runes[0]), strings.Repeat(string(runes[1]), total-3), string(runes[2]), string(runes[4]), ) got := string(getLastLine(buf.Bytes())) if !strings.Contains(got, wantBar) { t.Errorf("Want bar: %q:%d, got bar: %q:%d\n", wantBar, utf8.RuneCountInString(wantBar), got, utf8.RuneCountInString(got)) } } func TestBarPanicBeforeComplete(t *testing.T) { var buf bytes.Buffer p := mpb.New( mpb.WithWidth(80), mpb.WithDebugOutput(&buf), mpb.WithOutput(ioutil.Discard), ) total := 100 panicMsg := "Upps!!!" var pCount uint32 bar := p.AddBar(int64(total), mpb.PrependDecorators(panicDecorator(panicMsg, func(st decor.Statistics) bool { if st.Current >= 42 { atomic.AddUint32(&pCount, 1) return true } return false }, )), ) for i := 0; i < total; i++ { time.Sleep(10 * time.Millisecond) bar.Increment() } p.Wait() if pCount != 1 { t.Errorf("Decor called after panic %d times\n", pCount-1) } barStr := buf.String() if !strings.Contains(barStr, panicMsg) { t.Errorf("%q doesn't contain %q\n", barStr, panicMsg) } } func TestBarPanicAfterComplete(t *testing.T) { var buf bytes.Buffer p := mpb.New( mpb.WithWidth(80), mpb.WithDebugOutput(&buf), mpb.WithOutput(ioutil.Discard), ) total := 100 panicMsg := "Upps!!!" var pCount uint32 bar := p.AddBar(int64(total), mpb.PrependDecorators(panicDecorator(panicMsg, func(st decor.Statistics) bool { if st.Completed { atomic.AddUint32(&pCount, 1) return true } return false }, )), ) for i := 0; i < total; i++ { time.Sleep(10 * time.Millisecond) bar.Increment() } p.Wait() if pCount > 2 { t.Error("Decor called after panic more than 2 times\n") } barStr := buf.String() if !strings.Contains(barStr, panicMsg) { t.Errorf("%q doesn't contain %q\n", barStr, panicMsg) } } func TestDecorStatisticsAvailableWidth(t *testing.T) { total := 100 down := make(chan struct{}) checkDone := make(chan struct{}) td1 := func(s decor.Statistics) string { if s.AvailableWidth != 80 { t.Errorf("expected AvailableWidth %d got %d\n", 80, s.AvailableWidth) } return fmt.Sprintf("\x1b[31;1;4m%s\x1b[0m", strings.Repeat("0", 20)) } td2 := func(s decor.Statistics) string { defer func() { select { case checkDone <- struct{}{}: default: } }() if s.AvailableWidth != 40 { t.Errorf("expected AvailableWidth %d got %d\n", 40, s.AvailableWidth) } return "" } p := mpb.New( mpb.WithWidth(100), mpb.WithShutdownNotifier(down), mpb.WithOutput(ioutil.Discard), ) bar := p.AddBar(int64(total), mpb.BarFillerTrim(), mpb.PrependDecorators( decor.Name(strings.Repeat("0", 20)), decor.Any(td1), ), mpb.AppendDecorators( decor.Name(strings.Repeat("0", 20)), decor.Any(td2), ), ) go func() { for { select { case <-checkDone: bar.Abort(true) case <-down: return } } }() for !bar.Completed() { bar.Increment() } p.Wait() } func panicDecorator(panicMsg string, cond func(decor.Statistics) bool) decor.Decorator { return decor.Any(func(st decor.Statistics) string { if cond(st) { panic(panicMsg) } return "" }) } mpb-7.3.2/barbench_test.go000066400000000000000000000016231417272200500154350ustar00rootroot00000000000000package mpb import ( "sync" "testing" ) const total = 1000 func BenchmarkIncrementOneBar(b *testing.B) { benchBody(1, b) } func BenchmarkIncrementTwoBars(b *testing.B) { benchBody(2, b) } func BenchmarkIncrementThreeBars(b *testing.B) { benchBody(3, b) } func BenchmarkIncrementFourBars(b *testing.B) { benchBody(4, b) } func benchBody(n int, b *testing.B) { p := New(WithOutput(nil), WithWidth(80)) wg := new(sync.WaitGroup) b.ResetTimer() for i := 0; i < b.N; i++ { for j := 0; j < n; j++ { switch j { case n - 1: bar := p.AddBar(total) for c := 0; c < total; c++ { bar.Increment() } if !bar.Completed() { b.Fail() } default: wg.Add(1) go func() { bar := p.AddBar(total) for c := 0; c < total; c++ { bar.Increment() } if !bar.Completed() { b.Fail() } wg.Done() }() } } wg.Wait() } p.Wait() } mpb-7.3.2/container_option.go000066400000000000000000000060031417272200500162010ustar00rootroot00000000000000package mpb import ( "io" "io/ioutil" "sync" "time" ) // ContainerOption is a func option to alter default behavior of a bar // container. Container term refers to a Progress struct which can // hold one or more Bars. type ContainerOption func(*pState) // WithWaitGroup provides means to have a single joint point. If // *sync.WaitGroup is provided, you can safely call just p.Wait() // without calling Wait() on provided *sync.WaitGroup. Makes sense // when there are more than one bar to render. func WithWaitGroup(wg *sync.WaitGroup) ContainerOption { return func(s *pState) { s.uwg = wg } } // WithWidth sets container width. If not set it defaults to terminal // width. A bar added to the container will inherit its width, unless // overridden by `func BarWidth(int) BarOption`. func WithWidth(width int) ContainerOption { return func(s *pState) { s.reqWidth = width } } // WithRefreshRate overrides default 120ms refresh rate. func WithRefreshRate(d time.Duration) ContainerOption { return func(s *pState) { s.rr = d } } // WithManualRefresh disables internal auto refresh time.Ticker. // Refresh will occur upon receive value from provided ch. func WithManualRefresh(ch <-chan interface{}) ContainerOption { return func(s *pState) { s.externalRefresh = ch } } // WithRenderDelay delays rendering. By default rendering starts as // soon as bar is added, with this option it's possible to delay // rendering process by keeping provided chan unclosed. In other words // rendering will start as soon as provided chan is closed. func WithRenderDelay(ch <-chan struct{}) ContainerOption { return func(s *pState) { s.renderDelay = ch } } // WithShutdownNotifier provided chanel will be closed, after all bars // have been rendered. func WithShutdownNotifier(ch chan struct{}) ContainerOption { return func(s *pState) { select { case <-ch: default: s.shutdownNotifier = ch } } } // WithOutput overrides default os.Stdout output. Setting it to nil // will effectively disable auto refresh rate and discard any output, // useful if you want to disable progress bars with little overhead. func WithOutput(w io.Writer) ContainerOption { return func(s *pState) { if w == nil { s.output = ioutil.Discard s.outputDiscarded = true return } s.output = w } } // WithDebugOutput sets debug output. func WithDebugOutput(w io.Writer) ContainerOption { if w == nil { return nil } return func(s *pState) { s.debugOut = w } } // PopCompletedMode will pop and stop rendering completed bars. func PopCompletedMode() ContainerOption { return func(s *pState) { s.popCompleted = true } } // ContainerOptional will invoke provided option only when cond is true. func ContainerOptional(option ContainerOption, cond bool) ContainerOption { if cond { return option } return nil } // ContainerOptOn will invoke provided option only when higher order // predicate evaluates to true. func ContainerOptOn(option ContainerOption, predicate func() bool) ContainerOption { if predicate() { return option } return nil } mpb-7.3.2/cwriter/000077500000000000000000000000001417272200500137605ustar00rootroot00000000000000mpb-7.3.2/cwriter/cuuAndEd_construction_bench_test.go000066400000000000000000000014311417272200500230060ustar00rootroot00000000000000package cwriter import ( "bytes" "fmt" "io/ioutil" "strconv" "testing" ) func BenchmarkWithFprintf(b *testing.B) { cuuAndEd := "\x1b[%dA\x1b[J" for i := 0; i < b.N; i++ { fmt.Fprintf(ioutil.Discard, cuuAndEd, 4) } } func BenchmarkWithJoin(b *testing.B) { bCuuAndEd := [][]byte{[]byte("\x1b["), []byte("A\x1b[J")} for i := 0; i < b.N; i++ { _, _ = ioutil.Discard.Write(bytes.Join(bCuuAndEd, []byte(strconv.Itoa(4)))) } } func BenchmarkWithAppend(b *testing.B) { escOpen := []byte("\x1b[") cuuAndEd := []byte("A\x1b[J") for i := 0; i < b.N; i++ { _, _ = ioutil.Discard.Write(append(strconv.AppendInt(escOpen, 4, 10), cuuAndEd...)) } } func BenchmarkWithCopy(b *testing.B) { w := New(ioutil.Discard) w.lines = 4 for i := 0; i < b.N; i++ { _ = w.ansiCuuAndEd() } } mpb-7.3.2/cwriter/doc.go000066400000000000000000000001321417272200500150500ustar00rootroot00000000000000// Package cwriter is a console writer abstraction for the underlying OS. package cwriter mpb-7.3.2/cwriter/util_bsd.go000066400000000000000000000002131417272200500161100ustar00rootroot00000000000000// +build darwin dragonfly freebsd netbsd openbsd package cwriter import "golang.org/x/sys/unix" const ioctlReadTermios = unix.TIOCGETA mpb-7.3.2/cwriter/util_linux.go000066400000000000000000000001531417272200500165020ustar00rootroot00000000000000// +build aix linux package cwriter import "golang.org/x/sys/unix" const ioctlReadTermios = unix.TCGETS mpb-7.3.2/cwriter/util_solaris.go000066400000000000000000000001511417272200500170150ustar00rootroot00000000000000// +build solaris package cwriter import "golang.org/x/sys/unix" const ioctlReadTermios = unix.TCGETA mpb-7.3.2/cwriter/util_zos.go000066400000000000000000000001451417272200500161570ustar00rootroot00000000000000// +build zos package cwriter import "golang.org/x/sys/unix" const ioctlReadTermios = unix.TCGETS mpb-7.3.2/cwriter/writer.go000066400000000000000000000034701417272200500156270ustar00rootroot00000000000000package cwriter import ( "bytes" "errors" "io" "os" "strconv" ) // ErrNotTTY not a TeleTYpewriter error. var ErrNotTTY = errors.New("not a terminal") // http://ascii-table.com/ansi-escape-sequences.php const ( escOpen = "\x1b[" cuuAndEd = "A\x1b[J" ) // Writer is a buffered the writer that updates the terminal. The // contents of writer will be flushed when Flush is called. type Writer struct { out io.Writer buf bytes.Buffer lines int fd int isTerminal bool } // New returns a new Writer with defaults. func New(out io.Writer) *Writer { w := &Writer{out: out} if f, ok := out.(*os.File); ok { w.fd = int(f.Fd()) w.isTerminal = IsTerminal(w.fd) } return w } // Flush flushes the underlying buffer. func (w *Writer) Flush(lines int) (err error) { // some terminals interpret 'cursor up 0' as 'cursor up 1' if w.lines > 0 { err = w.clearLines() if err != nil { return } } w.lines = lines _, err = w.buf.WriteTo(w.out) return } // Write appends the contents of p to the underlying buffer. func (w *Writer) Write(p []byte) (n int, err error) { return w.buf.Write(p) } // WriteString writes string to the underlying buffer. func (w *Writer) WriteString(s string) (n int, err error) { return w.buf.WriteString(s) } // ReadFrom reads from the provided io.Reader and writes to the // underlying buffer. func (w *Writer) ReadFrom(r io.Reader) (n int64, err error) { return w.buf.ReadFrom(r) } // GetWidth returns width of underlying terminal. func (w *Writer) GetWidth() (int, error) { if !w.isTerminal { return -1, ErrNotTTY } tw, _, err := GetSize(w.fd) return tw, err } func (w *Writer) ansiCuuAndEd() error { buf := make([]byte, 8) buf = strconv.AppendInt(buf[:copy(buf, escOpen)], int64(w.lines), 10) _, err := w.out.Write(append(buf, cuuAndEd...)) return err } mpb-7.3.2/cwriter/writer_posix.go000066400000000000000000000010641417272200500170460ustar00rootroot00000000000000// +build !windows package cwriter import ( "golang.org/x/sys/unix" ) func (w *Writer) clearLines() error { return w.ansiCuuAndEd() } // GetSize returns the dimensions of the given terminal. func GetSize(fd int) (width, height int, err error) { ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) if err != nil { return -1, -1, err } return int(ws.Col), int(ws.Row), nil } // IsTerminal returns whether the given file descriptor is a terminal. func IsTerminal(fd int) bool { _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) return err == nil } mpb-7.3.2/cwriter/writer_windows.go000066400000000000000000000040571417272200500174030ustar00rootroot00000000000000// +build windows package cwriter import ( "unsafe" "golang.org/x/sys/windows" ) var kernel32 = windows.NewLazySystemDLL("kernel32.dll") var ( procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") ) func (w *Writer) clearLines() error { if !w.isTerminal { // hope it's cygwin or similar return w.ansiCuuAndEd() } var info windows.ConsoleScreenBufferInfo if err := windows.GetConsoleScreenBufferInfo(windows.Handle(w.fd), &info); err != nil { return err } info.CursorPosition.Y -= int16(w.lines) if info.CursorPosition.Y < 0 { info.CursorPosition.Y = 0 } _, _, _ = procSetConsoleCursorPosition.Call( uintptr(w.fd), uintptr(uint32(uint16(info.CursorPosition.Y))<<16|uint32(uint16(info.CursorPosition.X))), ) // clear the lines cursor := &windows.Coord{ X: info.Window.Left, Y: info.CursorPosition.Y, } count := uint32(info.Size.X) * uint32(w.lines) _, _, _ = procFillConsoleOutputCharacter.Call( uintptr(w.fd), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(cursor)), uintptr(unsafe.Pointer(new(uint32))), ) return nil } // GetSize returns the visible dimensions of the given terminal. // // These dimensions don't include any scrollback buffer height. func GetSize(fd int) (width, height int, err error) { var info windows.ConsoleScreenBufferInfo if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil { return 0, 0, err } // terminal.GetSize from crypto/ssh adds "+ 1" to both width and height: // https://go.googlesource.com/crypto/+/refs/heads/release-branch.go1.14/ssh/terminal/util_windows.go#75 // but looks like this is a root cause of issue #66, so removing both "+ 1" have fixed it. return int(info.Window.Right - info.Window.Left), int(info.Window.Bottom - info.Window.Top), nil } // IsTerminal returns whether the given file descriptor is a terminal. func IsTerminal(fd int) bool { var st uint32 err := windows.GetConsoleMode(windows.Handle(fd), &st) return err == nil } mpb-7.3.2/decor/000077500000000000000000000000001417272200500133755ustar00rootroot00000000000000mpb-7.3.2/decor/any.go000066400000000000000000000005751417272200500145220ustar00rootroot00000000000000package decor // Any decorator displays text, that can be changed during decorator's // lifetime via provided DecorFunc. // // `fn` DecorFunc callback // // `wcc` optional WC config // func Any(fn DecorFunc, wcc ...WC) Decorator { return &any{initWC(wcc...), fn} } type any struct { WC fn DecorFunc } func (d *any) Decor(s Statistics) string { return d.FormatMsg(d.fn(s)) } mpb-7.3.2/decor/counters.go000066400000000000000000000147651417272200500156030ustar00rootroot00000000000000package decor import ( "fmt" "strings" ) const ( _ = iota UnitKiB UnitKB ) // CountersNoUnit is a wrapper around Counters with no unit param. func CountersNoUnit(pairFmt string, wcc ...WC) Decorator { return Counters(0, pairFmt, wcc...) } // CountersKibiByte is a wrapper around Counters with predefined unit // UnitKiB (bytes/1024). func CountersKibiByte(pairFmt string, wcc ...WC) Decorator { return Counters(UnitKiB, pairFmt, wcc...) } // CountersKiloByte is a wrapper around Counters with predefined unit // UnitKB (bytes/1000). func CountersKiloByte(pairFmt string, wcc ...WC) Decorator { return Counters(UnitKB, pairFmt, wcc...) } // Counters decorator with dynamic unit measure adjustment. // // `unit` one of [0|UnitKiB|UnitKB] zero for no unit // // `pairFmt` printf compatible verbs for current and total pair // // `wcc` optional WC config // // pairFmt example if unit=UnitKB: // // pairFmt="%.1f / %.1f" output: "1.0MB / 12.0MB" // pairFmt="% .1f / % .1f" output: "1.0 MB / 12.0 MB" // pairFmt="%d / %d" output: "1MB / 12MB" // pairFmt="% d / % d" output: "1 MB / 12 MB" // func Counters(unit int, pairFmt string, wcc ...WC) Decorator { producer := func(unit int, pairFmt string) DecorFunc { if pairFmt == "" { pairFmt = "%d / %d" } else if strings.Count(pairFmt, "%") != 2 { panic("expected pairFmt with exactly 2 verbs") } switch unit { case UnitKiB: return func(s Statistics) string { return fmt.Sprintf(pairFmt, SizeB1024(s.Current), SizeB1024(s.Total)) } case UnitKB: return func(s Statistics) string { return fmt.Sprintf(pairFmt, SizeB1000(s.Current), SizeB1000(s.Total)) } default: return func(s Statistics) string { return fmt.Sprintf(pairFmt, s.Current, s.Total) } } } return Any(producer(unit, pairFmt), wcc...) } // TotalNoUnit is a wrapper around Total with no unit param. func TotalNoUnit(format string, wcc ...WC) Decorator { return Total(0, format, wcc...) } // TotalKibiByte is a wrapper around Total with predefined unit // UnitKiB (bytes/1024). func TotalKibiByte(format string, wcc ...WC) Decorator { return Total(UnitKiB, format, wcc...) } // TotalKiloByte is a wrapper around Total with predefined unit // UnitKB (bytes/1000). func TotalKiloByte(format string, wcc ...WC) Decorator { return Total(UnitKB, format, wcc...) } // Total decorator with dynamic unit measure adjustment. // // `unit` one of [0|UnitKiB|UnitKB] zero for no unit // // `format` printf compatible verb for Total // // `wcc` optional WC config // // format example if unit=UnitKiB: // // format="%.1f" output: "12.0MiB" // format="% .1f" output: "12.0 MiB" // format="%d" output: "12MiB" // format="% d" output: "12 MiB" // func Total(unit int, format string, wcc ...WC) Decorator { producer := func(unit int, format string) DecorFunc { if format == "" { format = "%d" } else if strings.Count(format, "%") != 1 { panic("expected format with exactly 1 verb") } switch unit { case UnitKiB: return func(s Statistics) string { return fmt.Sprintf(format, SizeB1024(s.Total)) } case UnitKB: return func(s Statistics) string { return fmt.Sprintf(format, SizeB1000(s.Total)) } default: return func(s Statistics) string { return fmt.Sprintf(format, s.Total) } } } return Any(producer(unit, format), wcc...) } // CurrentNoUnit is a wrapper around Current with no unit param. func CurrentNoUnit(format string, wcc ...WC) Decorator { return Current(0, format, wcc...) } // CurrentKibiByte is a wrapper around Current with predefined unit // UnitKiB (bytes/1024). func CurrentKibiByte(format string, wcc ...WC) Decorator { return Current(UnitKiB, format, wcc...) } // CurrentKiloByte is a wrapper around Current with predefined unit // UnitKB (bytes/1000). func CurrentKiloByte(format string, wcc ...WC) Decorator { return Current(UnitKB, format, wcc...) } // Current decorator with dynamic unit measure adjustment. // // `unit` one of [0|UnitKiB|UnitKB] zero for no unit // // `format` printf compatible verb for Current // // `wcc` optional WC config // // format example if unit=UnitKiB: // // format="%.1f" output: "12.0MiB" // format="% .1f" output: "12.0 MiB" // format="%d" output: "12MiB" // format="% d" output: "12 MiB" // func Current(unit int, format string, wcc ...WC) Decorator { producer := func(unit int, format string) DecorFunc { if format == "" { format = "%d" } else if strings.Count(format, "%") != 1 { panic("expected format with exactly 1 verb") } switch unit { case UnitKiB: return func(s Statistics) string { return fmt.Sprintf(format, SizeB1024(s.Current)) } case UnitKB: return func(s Statistics) string { return fmt.Sprintf(format, SizeB1000(s.Current)) } default: return func(s Statistics) string { return fmt.Sprintf(format, s.Current) } } } return Any(producer(unit, format), wcc...) } // InvertedCurrentNoUnit is a wrapper around InvertedCurrent with no unit param. func InvertedCurrentNoUnit(format string, wcc ...WC) Decorator { return InvertedCurrent(0, format, wcc...) } // InvertedCurrentKibiByte is a wrapper around InvertedCurrent with predefined unit // UnitKiB (bytes/1024). func InvertedCurrentKibiByte(format string, wcc ...WC) Decorator { return InvertedCurrent(UnitKiB, format, wcc...) } // InvertedCurrentKiloByte is a wrapper around InvertedCurrent with predefined unit // UnitKB (bytes/1000). func InvertedCurrentKiloByte(format string, wcc ...WC) Decorator { return InvertedCurrent(UnitKB, format, wcc...) } // InvertedCurrent decorator with dynamic unit measure adjustment. // // `unit` one of [0|UnitKiB|UnitKB] zero for no unit // // `format` printf compatible verb for InvertedCurrent // // `wcc` optional WC config // // format example if unit=UnitKiB: // // format="%.1f" output: "12.0MiB" // format="% .1f" output: "12.0 MiB" // format="%d" output: "12MiB" // format="% d" output: "12 MiB" // func InvertedCurrent(unit int, format string, wcc ...WC) Decorator { producer := func(unit int, format string) DecorFunc { if format == "" { format = "%d" } else if strings.Count(format, "%") != 1 { panic("expected format with exactly 1 verb") } switch unit { case UnitKiB: return func(s Statistics) string { return fmt.Sprintf(format, SizeB1024(s.Total-s.Current)) } case UnitKB: return func(s Statistics) string { return fmt.Sprintf(format, SizeB1000(s.Total-s.Current)) } default: return func(s Statistics) string { return fmt.Sprintf(format, s.Total-s.Current) } } } return Any(producer(unit, format), wcc...) } mpb-7.3.2/decor/decorator.go000066400000000000000000000117111417272200500157070ustar00rootroot00000000000000package decor import ( "fmt" "time" "github.com/acarl005/stripansi" "github.com/mattn/go-runewidth" ) const ( // DidentRight bit specifies identation direction. // |foo |b | With DidentRight // | foo| b| Without DidentRight DidentRight = 1 << iota // DextraSpace bit adds extra space, makes sense with DSyncWidth only. // When DidentRight bit set, the space will be added to the right, // otherwise to the left. DextraSpace // DSyncWidth bit enables same column width synchronization. // Effective with multiple bars only. DSyncWidth // DSyncWidthR is shortcut for DSyncWidth|DidentRight DSyncWidthR = DSyncWidth | DidentRight // DSyncSpace is shortcut for DSyncWidth|DextraSpace DSyncSpace = DSyncWidth | DextraSpace // DSyncSpaceR is shortcut for DSyncWidth|DextraSpace|DidentRight DSyncSpaceR = DSyncWidth | DextraSpace | DidentRight ) // TimeStyle enum. type TimeStyle int // TimeStyle kinds. const ( ET_STYLE_GO TimeStyle = iota ET_STYLE_HHMMSS ET_STYLE_HHMM ET_STYLE_MMSS ) // Statistics consists of progress related statistics, that Decorator // may need. type Statistics struct { ID int AvailableWidth int Total int64 Current int64 Refill int64 Completed bool Aborted bool } // Decorator interface. // Most of the time there is no need to implement this interface // manually, as decor package already provides a wide range of decorators // which implement this interface. If however built-in decorators don't // meet your needs, you're free to implement your own one by implementing // this particular interface. The easy way to go is to convert a // `DecorFunc` into a `Decorator` interface by using provided // `func Any(DecorFunc, ...WC) Decorator`. type Decorator interface { Configurator Synchronizer Decor(Statistics) string } // DecorFunc func type. // To be used with `func Any`(DecorFunc, ...WC) Decorator`. type DecorFunc func(Statistics) string // Synchronizer interface. // All decorators implement this interface implicitly. Its Sync // method exposes width sync channel, if DSyncWidth bit is set. type Synchronizer interface { Sync() (chan int, bool) } // Configurator interface. type Configurator interface { GetConf() WC SetConf(WC) } // Wrapper interface. // If you're implementing custom Decorator by wrapping a built-in one, // it is necessary to implement this interface to retain functionality // of built-in Decorator. type Wrapper interface { Base() Decorator } // EwmaDecorator interface. // EWMA based decorators should implement this one. type EwmaDecorator interface { EwmaUpdate(int64, time.Duration) } // AverageDecorator interface. // Average decorators should implement this interface to provide start // time adjustment facility, for resume-able tasks. type AverageDecorator interface { AverageAdjust(time.Time) } // ShutdownListener interface. // If decorator needs to be notified once upon bar shutdown event, so // this is the right interface to implement. type ShutdownListener interface { Shutdown() } // Global convenience instances of WC with sync width bit set. // To be used with multiple bars only, i.e. not effective for single bar usage. var ( WCSyncWidth = WC{C: DSyncWidth} WCSyncWidthR = WC{C: DSyncWidthR} WCSyncSpace = WC{C: DSyncSpace} WCSyncSpaceR = WC{C: DSyncSpaceR} ) // WC is a struct with two public fields W and C, both of int type. // W represents width and C represents bit set of width related config. // A decorator should embed WC, to enable width synchronization. type WC struct { W int C int fill func(s string, w int) string wsync chan int } // FormatMsg formats final message according to WC.W and WC.C. // Should be called by any Decorator implementation. func (wc *WC) FormatMsg(msg string) string { pureWidth := runewidth.StringWidth(msg) stripWidth := runewidth.StringWidth(stripansi.Strip(msg)) maxCell := wc.W if (wc.C & DSyncWidth) != 0 { cellCount := stripWidth if (wc.C & DextraSpace) != 0 { cellCount++ } wc.wsync <- cellCount maxCell = <-wc.wsync } return wc.fill(msg, maxCell+(pureWidth-stripWidth)) } // Init initializes width related config. func (wc *WC) Init() WC { wc.fill = runewidth.FillLeft if (wc.C & DidentRight) != 0 { wc.fill = runewidth.FillRight } if (wc.C & DSyncWidth) != 0 { // it's deliberate choice to override wsync on each Init() call, // this way globals like WCSyncSpace can be reused wc.wsync = make(chan int) } return *wc } // Sync is implementation of Synchronizer interface. func (wc *WC) Sync() (chan int, bool) { if (wc.C&DSyncWidth) != 0 && wc.wsync == nil { panic(fmt.Sprintf("%T is not initialized", wc)) } return wc.wsync, (wc.C & DSyncWidth) != 0 } // GetConf is implementation of Configurator interface. func (wc *WC) GetConf() WC { return *wc } // SetConf is implementation of Configurator interface. func (wc *WC) SetConf(conf WC) { *wc = conf.Init() } func initWC(wcc ...WC) WC { var wc WC for _, nwc := range wcc { wc = nwc } return wc.Init() } mpb-7.3.2/decor/doc.go000066400000000000000000000012311417272200500144660ustar00rootroot00000000000000// Package decor provides common decorators for "github.com/vbauerster/mpb/v7" module. // // Some decorators returned by this package might have a closure state. It is ok to use // decorators concurrently, unless you share the same decorator among multiple // *mpb.Bar instances. To avoid data races, create new decorator per *mpb.Bar instance. // // Don't: // // p := mpb.New() // name := decor.Name("bar") // p.AddBar(100, mpb.AppendDecorators(name)) // p.AddBar(100, mpb.AppendDecorators(name)) // // Do: // // p := mpb.New() // p.AddBar(100, mpb.AppendDecorators(decor.Name("bar1"))) // p.AddBar(100, mpb.AppendDecorators(decor.Name("bar2"))) package decor mpb-7.3.2/decor/elapsed.go000066400000000000000000000013721417272200500153440ustar00rootroot00000000000000package decor import ( "time" ) // Elapsed decorator. It's wrapper of NewElapsed. // // `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS] // // `wcc` optional WC config // func Elapsed(style TimeStyle, wcc ...WC) Decorator { return NewElapsed(style, time.Now(), wcc...) } // NewElapsed returns elapsed time decorator. // // `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS] // // `startTime` start time // // `wcc` optional WC config // func NewElapsed(style TimeStyle, startTime time.Time, wcc ...WC) Decorator { var msg string producer := chooseTimeProducer(style) fn := func(s Statistics) string { if !s.Completed { msg = producer(time.Since(startTime)) } return msg } return Any(fn, wcc...) } mpb-7.3.2/decor/eta.go000066400000000000000000000134731417272200500145050ustar00rootroot00000000000000package decor import ( "fmt" "math" "time" "github.com/VividCortex/ewma" ) // TimeNormalizer interface. Implementors could be passed into // MovingAverageETA, in order to affect i.e. normalize its output. type TimeNormalizer interface { Normalize(time.Duration) time.Duration } // TimeNormalizerFunc is function type adapter to convert function // into TimeNormalizer. type TimeNormalizerFunc func(time.Duration) time.Duration func (f TimeNormalizerFunc) Normalize(src time.Duration) time.Duration { return f(src) } // EwmaETA exponential-weighted-moving-average based ETA decorator. // For this decorator to work correctly you have to measure each // iteration's duration and pass it to the // *Bar.DecoratorEwmaUpdate(time.Duration) method after each increment. func EwmaETA(style TimeStyle, age float64, wcc ...WC) Decorator { var average ewma.MovingAverage if age == 0 { average = ewma.NewMovingAverage() } else { average = ewma.NewMovingAverage(age) } return MovingAverageETA(style, NewThreadSafeMovingAverage(average), nil, 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` implementation of MovingAverage interface // // `normalizer` available implementations are [FixedIntervalTimeNormalizer|MaxTolerateTimeNormalizer] // // `wcc` optional WC config // func MovingAverageETA(style TimeStyle, average ewma.MovingAverage, normalizer TimeNormalizer, wcc ...WC) Decorator { d := &movingAverageETA{ WC: initWC(wcc...), average: average, normalizer: normalizer, producer: chooseTimeProducer(style), } return d } type movingAverageETA struct { WC average ewma.MovingAverage normalizer TimeNormalizer producer func(time.Duration) string } func (d *movingAverageETA) Decor(s Statistics) string { v := math.Round(d.average.Value()) remaining := time.Duration((s.Total - s.Current) * int64(v)) if d.normalizer != nil { remaining = d.normalizer.Normalize(remaining) } return d.FormatMsg(d.producer(remaining)) } func (d *movingAverageETA) EwmaUpdate(n int64, dur time.Duration) { durPerItem := float64(dur) / float64(n) if math.IsInf(durPerItem, 0) || math.IsNaN(durPerItem) { return } d.average.Add(durPerItem) } // AverageETA decorator. It's wrapper of NewAverageETA. // // `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS] // // `wcc` optional WC config // func AverageETA(style TimeStyle, wcc ...WC) Decorator { return NewAverageETA(style, time.Now(), nil, 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 // // `normalizer` available implementations are [FixedIntervalTimeNormalizer|MaxTolerateTimeNormalizer] // // `wcc` optional WC config // func NewAverageETA(style TimeStyle, startTime time.Time, normalizer TimeNormalizer, wcc ...WC) Decorator { d := &averageETA{ WC: initWC(wcc...), startTime: startTime, normalizer: normalizer, producer: chooseTimeProducer(style), } return d } type averageETA struct { WC startTime time.Time normalizer TimeNormalizer producer func(time.Duration) string } func (d *averageETA) Decor(s Statistics) string { var remaining time.Duration if s.Current != 0 { durPerItem := float64(time.Since(d.startTime)) / float64(s.Current) durPerItem = math.Round(durPerItem) remaining = time.Duration((s.Total - s.Current) * int64(durPerItem)) if d.normalizer != nil { remaining = d.normalizer.Normalize(remaining) } } return d.FormatMsg(d.producer(remaining)) } func (d *averageETA) AverageAdjust(startTime time.Time) { d.startTime = startTime } // MaxTolerateTimeNormalizer returns implementation of TimeNormalizer. func MaxTolerateTimeNormalizer(maxTolerate time.Duration) TimeNormalizer { var normalized time.Duration var lastCall time.Time return TimeNormalizerFunc(func(remaining time.Duration) time.Duration { if diff := normalized - remaining; diff <= 0 || diff > maxTolerate || remaining < time.Minute { normalized = remaining lastCall = time.Now() return remaining } normalized -= time.Since(lastCall) lastCall = time.Now() return normalized }) } // FixedIntervalTimeNormalizer returns implementation of TimeNormalizer. func FixedIntervalTimeNormalizer(updInterval int) TimeNormalizer { var normalized time.Duration var lastCall time.Time var count int return TimeNormalizerFunc(func(remaining time.Duration) time.Duration { if count == 0 || remaining < time.Minute { count = updInterval normalized = remaining lastCall = time.Now() return remaining } count-- normalized -= time.Since(lastCall) lastCall = time.Now() return normalized }) } func chooseTimeProducer(style TimeStyle) func(time.Duration) string { switch style { case ET_STYLE_HHMMSS: return func(remaining time.Duration) string { hours := int64(remaining/time.Hour) % 60 minutes := int64(remaining/time.Minute) % 60 seconds := int64(remaining/time.Second) % 60 return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds) } case ET_STYLE_HHMM: return func(remaining time.Duration) string { hours := int64(remaining/time.Hour) % 60 minutes := int64(remaining/time.Minute) % 60 return fmt.Sprintf("%02d:%02d", hours, minutes) } case ET_STYLE_MMSS: return func(remaining time.Duration) string { hours := int64(remaining/time.Hour) % 60 minutes := int64(remaining/time.Minute) % 60 seconds := int64(remaining/time.Second) % 60 if hours > 0 { return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds) } return fmt.Sprintf("%02d:%02d", minutes, seconds) } default: return func(remaining time.Duration) string { // strip off nanoseconds return ((remaining / time.Second) * time.Second).String() } } } mpb-7.3.2/decor/merge.go000066400000000000000000000046521417272200500150320ustar00rootroot00000000000000package decor import ( "strings" "github.com/acarl005/stripansi" "github.com/mattn/go-runewidth" ) // Merge wraps its decorator argument with intention to sync width // with several decorators of another bar. Visual example: // // +----+--------+---------+--------+ // | B1 | MERGE(D, P1, Pn) | // +----+--------+---------+--------+ // | B2 | D0 | D1 | Dn | // +----+--------+---------+--------+ // func Merge(decorator Decorator, placeholders ...WC) Decorator { if decorator == nil { return nil } if _, ok := decorator.Sync(); !ok || len(placeholders) == 0 { return decorator } md := &mergeDecorator{ Decorator: decorator, wc: decorator.GetConf(), placeHolders: make([]*placeHolderDecorator, len(placeholders)), } decorator.SetConf(WC{}) for i, wc := range placeholders { if (wc.C & DSyncWidth) == 0 { return decorator } md.placeHolders[i] = &placeHolderDecorator{wc.Init()} } return md } type mergeDecorator struct { Decorator wc WC placeHolders []*placeHolderDecorator } func (d *mergeDecorator) GetConf() WC { return d.wc } func (d *mergeDecorator) SetConf(conf WC) { d.wc = conf.Init() } func (d *mergeDecorator) MergeUnwrap() []Decorator { decorators := make([]Decorator, len(d.placeHolders)) for i, ph := range d.placeHolders { decorators[i] = ph } return decorators } func (d *mergeDecorator) Sync() (chan int, bool) { return d.wc.Sync() } func (d *mergeDecorator) Base() Decorator { return d.Decorator } func (d *mergeDecorator) Decor(s Statistics) string { msg := d.Decorator.Decor(s) pureWidth := runewidth.StringWidth(msg) stripWidth := runewidth.StringWidth(stripansi.Strip(msg)) cellCount := stripWidth if (d.wc.C & DextraSpace) != 0 { cellCount++ } total := runewidth.StringWidth(d.placeHolders[0].FormatMsg("")) pw := (cellCount - total) / len(d.placeHolders) rem := (cellCount - total) % len(d.placeHolders) var diff int for i := 1; i < len(d.placeHolders); i++ { ph := d.placeHolders[i] width := pw - diff if (ph.WC.C & DextraSpace) != 0 { width-- if width < 0 { width = 0 } } max := runewidth.StringWidth(ph.FormatMsg(strings.Repeat(" ", width))) total += max diff = max - pw } d.wc.wsync <- pw + rem max := <-d.wc.wsync return d.wc.fill(msg, max+total+(pureWidth-stripWidth)) } type placeHolderDecorator struct { WC } func (d *placeHolderDecorator) Decor(Statistics) string { return "" } mpb-7.3.2/decor/moving_average.go000066400000000000000000000027011417272200500167150ustar00rootroot00000000000000package decor import ( "sort" "sync" "github.com/VividCortex/ewma" ) type threadSafeMovingAverage struct { ewma.MovingAverage mu sync.Mutex } func (s *threadSafeMovingAverage) Add(value float64) { s.mu.Lock() s.MovingAverage.Add(value) s.mu.Unlock() } func (s *threadSafeMovingAverage) Value() float64 { s.mu.Lock() defer s.mu.Unlock() return s.MovingAverage.Value() } func (s *threadSafeMovingAverage) Set(value float64) { s.mu.Lock() s.MovingAverage.Set(value) s.mu.Unlock() } // NewThreadSafeMovingAverage converts provided ewma.MovingAverage // into thread safe ewma.MovingAverage. func NewThreadSafeMovingAverage(average ewma.MovingAverage) ewma.MovingAverage { if tsma, ok := average.(*threadSafeMovingAverage); ok { return tsma } return &threadSafeMovingAverage{MovingAverage: average} } type medianWindow [3]float64 func (s *medianWindow) Len() int { return len(s) } func (s *medianWindow) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s *medianWindow) Less(i, j int) bool { return s[i] < s[j] } func (s *medianWindow) Add(value float64) { s[0], s[1] = s[1], s[2] s[2] = value } func (s *medianWindow) Value() float64 { tmp := *s sort.Sort(&tmp) return tmp[1] } func (s *medianWindow) Set(value float64) { for i := 0; i < len(s); i++ { s[i] = value } } // NewMedian is fixed last 3 samples median MovingAverage. func NewMedian() ewma.MovingAverage { return NewThreadSafeMovingAverage(new(medianWindow)) } mpb-7.3.2/decor/name.go000066400000000000000000000004401417272200500146420ustar00rootroot00000000000000package decor // Name decorator displays text that is set once and can't be changed // during decorator's lifetime. // // `str` string to display // // `wcc` optional WC config // func Name(str string, wcc ...WC) Decorator { return Any(func(Statistics) string { return str }, wcc...) } mpb-7.3.2/decor/on_abort.go000066400000000000000000000015521417272200500155320ustar00rootroot00000000000000package decor // OnAbort returns decorator, which wraps provided decorator with sole // purpose to display provided message on abort event. It has no effect // if bar.Abort(drop bool) is called with true argument. // // `decorator` Decorator to wrap // // `message` message to display on abort event // func OnAbort(decorator Decorator, message string) Decorator { if decorator == nil { return nil } d := &onAbortWrapper{ Decorator: decorator, msg: message, } if md, ok := decorator.(*mergeDecorator); ok { d.Decorator, md.Decorator = md.Decorator, d return md } return d } type onAbortWrapper struct { Decorator msg string } func (d *onAbortWrapper) Decor(s Statistics) string { if s.Aborted { wc := d.GetConf() return wc.FormatMsg(d.msg) } return d.Decorator.Decor(s) } func (d *onAbortWrapper) Base() Decorator { return d.Decorator } mpb-7.3.2/decor/on_complete.go000066400000000000000000000014721417272200500162340ustar00rootroot00000000000000package decor // OnComplete returns decorator, which wraps provided decorator with // sole purpose to display provided message on complete event. // // `decorator` Decorator to wrap // // `message` message to display on complete event // func OnComplete(decorator Decorator, message string) Decorator { if decorator == nil { return nil } d := &onCompleteWrapper{ Decorator: decorator, msg: message, } if md, ok := decorator.(*mergeDecorator); ok { d.Decorator, md.Decorator = md.Decorator, d return md } return d } type onCompleteWrapper struct { Decorator msg string } func (d *onCompleteWrapper) Decor(s Statistics) string { if s.Completed { wc := d.GetConf() return wc.FormatMsg(d.msg) } return d.Decorator.Decor(s) } func (d *onCompleteWrapper) Base() Decorator { return d.Decorator } mpb-7.3.2/decor/on_condition.go000066400000000000000000000007411417272200500164100ustar00rootroot00000000000000package decor // OnPredicate returns decorator if predicate evaluates to true. // // `decorator` Decorator // // `predicate` func() bool // func OnPredicate(decorator Decorator, predicate func() bool) Decorator { if predicate() { return decorator } return nil } // OnCondition returns decorator if condition is true. // // `decorator` Decorator // // `cond` bool // func OnCondition(decorator Decorator, cond bool) Decorator { if cond { return decorator } return nil } mpb-7.3.2/decor/optimistic_string_writer.go000066400000000000000000000002671417272200500210770ustar00rootroot00000000000000package decor import "io" func optimisticStringWriter(w io.Writer) func(string) { return func(s string) { _, err := io.WriteString(w, s) if err != nil { panic(err) } } } mpb-7.3.2/decor/percentage.go000066400000000000000000000021111417272200500160340ustar00rootroot00000000000000package decor import ( "fmt" "strconv" "github.com/vbauerster/mpb/v7/internal" ) type percentageType float64 func (s percentageType) Format(st fmt.State, verb rune) { var prec int switch verb { case 'd': case 's': prec = -1 default: if p, ok := st.Precision(); ok { prec = p } else { prec = 6 } } osw := optimisticStringWriter(st) osw(strconv.FormatFloat(float64(s), 'f', prec, 64)) if st.Flag(' ') { osw(" ") } osw("%") } // Percentage returns percentage decorator. It's a wrapper of NewPercentage. func Percentage(wcc ...WC) Decorator { return NewPercentage("% d", wcc...) } // NewPercentage percentage decorator with custom format string. // // format examples: // // format="%.1f" output: "1.0%" // format="% .1f" output: "1.0 %" // format="%d" output: "1%" // format="% d" output: "1 %" // func NewPercentage(format string, wcc ...WC) Decorator { if format == "" { format = "% d" } f := func(s Statistics) string { p := internal.Percentage(s.Total, s.Current, 100) return fmt.Sprintf(format, percentageType(p)) } return Any(f, wcc...) } mpb-7.3.2/decor/size_type.go000066400000000000000000000036061417272200500157440ustar00rootroot00000000000000package decor import ( "fmt" "strconv" ) //go:generate stringer -type=SizeB1024 -trimprefix=_i //go:generate stringer -type=SizeB1000 -trimprefix=_ const ( _ib SizeB1024 = iota + 1 _iKiB SizeB1024 = 1 << (iota * 10) _iMiB _iGiB _iTiB ) // SizeB1024 named type, which implements fmt.Formatter interface. It // adjusts its value according to byte size multiple by 1024 and appends // appropriate size marker (KiB, MiB, GiB, TiB). type SizeB1024 int64 func (self SizeB1024) Format(st fmt.State, verb rune) { var prec int switch verb { case 'd': case 's': prec = -1 default: if p, ok := st.Precision(); ok { prec = p } else { prec = 6 } } var unit SizeB1024 switch { case self < _iKiB: unit = _ib case self < _iMiB: unit = _iKiB case self < _iGiB: unit = _iMiB case self < _iTiB: unit = _iGiB default: unit = _iTiB } osw := optimisticStringWriter(st) osw(strconv.FormatFloat(float64(self)/float64(unit), 'f', prec, 64)) if st.Flag(' ') { osw(" ") } osw(unit.String()) } const ( _b SizeB1000 = 1 _KB SizeB1000 = _b * 1000 _MB SizeB1000 = _KB * 1000 _GB SizeB1000 = _MB * 1000 _TB SizeB1000 = _GB * 1000 ) // SizeB1000 named type, which implements fmt.Formatter interface. It // adjusts its value according to byte size multiple by 1000 and appends // appropriate size marker (KB, MB, GB, TB). type SizeB1000 int64 func (self SizeB1000) Format(st fmt.State, verb rune) { var prec int switch verb { case 'd': case 's': prec = -1 default: if p, ok := st.Precision(); ok { prec = p } else { prec = 6 } } var unit SizeB1000 switch { case self < _KB: unit = _b case self < _MB: unit = _KB case self < _GB: unit = _MB case self < _TB: unit = _GB default: unit = _TB } osw := optimisticStringWriter(st) osw(strconv.FormatFloat(float64(self)/float64(unit), 'f', prec, 64)) if st.Flag(' ') { osw(" ") } osw(unit.String()) } mpb-7.3.2/decor/size_type_test.go000066400000000000000000000074351417272200500170070ustar00rootroot00000000000000package decor import ( "fmt" "testing" ) func TestB1024(t *testing.T) { cases := map[string]struct { value int64 verb string expected string }{ "verb %f": {12345678, "%f", "11.773756MiB"}, "verb %.0f": {12345678, "%.0f", "12MiB"}, "verb %.1f": {12345678, "%.1f", "11.8MiB"}, "verb %.2f": {12345678, "%.2f", "11.77MiB"}, "verb %.3f": {12345678, "%.3f", "11.774MiB"}, "verb % f": {12345678, "% f", "11.773756 MiB"}, "verb % .0f": {12345678, "% .0f", "12 MiB"}, "verb % .1f": {12345678, "% .1f", "11.8 MiB"}, "verb % .2f": {12345678, "% .2f", "11.77 MiB"}, "verb % .3f": {12345678, "% .3f", "11.774 MiB"}, "1000 %f": {1000, "%f", "1000.000000b"}, "1000 %d": {1000, "%d", "1000b"}, "1000 %s": {1000, "%s", "1000b"}, "1024 %f": {1024, "%f", "1.000000KiB"}, "1024 %d": {1024, "%d", "1KiB"}, "1024 %.1f": {1024, "%.1f", "1.0KiB"}, "1024 %s": {1024, "%s", "1KiB"}, "3*MiB+140KiB %f": {3*int64(_iMiB) + 140*int64(_iKiB), "%f", "3.136719MiB"}, "3*MiB+140KiB %d": {3*int64(_iMiB) + 140*int64(_iKiB), "%d", "3MiB"}, "3*MiB+140KiB %.1f": {3*int64(_iMiB) + 140*int64(_iKiB), "%.1f", "3.1MiB"}, "3*MiB+140KiB %s": {3*int64(_iMiB) + 140*int64(_iKiB), "%s", "3.13671875MiB"}, "2*GiB %f": {2 * int64(_iGiB), "%f", "2.000000GiB"}, "2*GiB %d": {2 * int64(_iGiB), "%d", "2GiB"}, "2*GiB %.1f": {2 * int64(_iGiB), "%.1f", "2.0GiB"}, "2*GiB %s": {2 * int64(_iGiB), "%s", "2GiB"}, "4*TiB %f": {4 * int64(_iTiB), "%f", "4.000000TiB"}, "4*TiB %d": {4 * int64(_iTiB), "%d", "4TiB"}, "4*TiB %.1f": {4 * int64(_iTiB), "%.1f", "4.0TiB"}, "4*TiB %s": {4 * int64(_iTiB), "%s", "4TiB"}, } for name, tc := range cases { t.Run(name, func(t *testing.T) { got := fmt.Sprintf(tc.verb, SizeB1024(tc.value)) if got != tc.expected { t.Fatalf("expected: %q, got: %q\n", tc.expected, got) } }) } } func TestB1000(t *testing.T) { cases := map[string]struct { value int64 verb string expected string }{ "verb %f": {12345678, "%f", "12.345678MB"}, "verb %.0f": {12345678, "%.0f", "12MB"}, "verb %.1f": {12345678, "%.1f", "12.3MB"}, "verb %.2f": {12345678, "%.2f", "12.35MB"}, "verb %.3f": {12345678, "%.3f", "12.346MB"}, "verb % f": {12345678, "% f", "12.345678 MB"}, "verb % .0f": {12345678, "% .0f", "12 MB"}, "verb % .1f": {12345678, "% .1f", "12.3 MB"}, "verb % .2f": {12345678, "% .2f", "12.35 MB"}, "verb % .3f": {12345678, "% .3f", "12.346 MB"}, "1000 %f": {1000, "%f", "1.000000KB"}, "1000 %d": {1000, "%d", "1KB"}, "1000 %s": {1000, "%s", "1KB"}, "1024 %f": {1024, "%f", "1.024000KB"}, "1024 %d": {1024, "%d", "1KB"}, "1024 %.1f": {1024, "%.1f", "1.0KB"}, "1024 %s": {1024, "%s", "1.024KB"}, "3*MB+140*KB %f": {3*int64(_MB) + 140*int64(_KB), "%f", "3.140000MB"}, "3*MB+140*KB %d": {3*int64(_MB) + 140*int64(_KB), "%d", "3MB"}, "3*MB+140*KB %.1f": {3*int64(_MB) + 140*int64(_KB), "%.1f", "3.1MB"}, "3*MB+140*KB %s": {3*int64(_MB) + 140*int64(_KB), "%s", "3.14MB"}, "2*GB %f": {2 * int64(_GB), "%f", "2.000000GB"}, "2*GB %d": {2 * int64(_GB), "%d", "2GB"}, "2*GB %.1f": {2 * int64(_GB), "%.1f", "2.0GB"}, "2*GB %s": {2 * int64(_GB), "%s", "2GB"}, "4*TB %f": {4 * int64(_TB), "%f", "4.000000TB"}, "4*TB %d": {4 * int64(_TB), "%d", "4TB"}, "4*TB %.1f": {4 * int64(_TB), "%.1f", "4.0TB"}, "4*TB %s": {4 * int64(_TB), "%s", "4TB"}, } for name, tc := range cases { t.Run(name, func(t *testing.T) { got := fmt.Sprintf(tc.verb, SizeB1000(tc.value)) if got != tc.expected { t.Fatalf("expected: %q, got: %q\n", tc.expected, got) } }) } } mpb-7.3.2/decor/sizeb1000_string.go000066400000000000000000000015721417272200500167340ustar00rootroot00000000000000// Code generated by "stringer -type=SizeB1000 -trimprefix=_"; DO NOT EDIT. package decor import "strconv" func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. var x [1]struct{} _ = x[_b-1] _ = x[_KB-1000] _ = x[_MB-1000000] _ = x[_GB-1000000000] _ = x[_TB-1000000000000] } const ( _SizeB1000_name_0 = "b" _SizeB1000_name_1 = "KB" _SizeB1000_name_2 = "MB" _SizeB1000_name_3 = "GB" _SizeB1000_name_4 = "TB" ) func (i SizeB1000) String() string { switch { case i == 1: return _SizeB1000_name_0 case i == 1000: return _SizeB1000_name_1 case i == 1000000: return _SizeB1000_name_2 case i == 1000000000: return _SizeB1000_name_3 case i == 1000000000000: return _SizeB1000_name_4 default: return "SizeB1000(" + strconv.FormatInt(int64(i), 10) + ")" } } mpb-7.3.2/decor/sizeb1024_string.go000066400000000000000000000016101417272200500167330ustar00rootroot00000000000000// Code generated by "stringer -type=SizeB1024 -trimprefix=_i"; DO NOT EDIT. package decor import "strconv" func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. var x [1]struct{} _ = x[_ib-1] _ = x[_iKiB-1024] _ = x[_iMiB-1048576] _ = x[_iGiB-1073741824] _ = x[_iTiB-1099511627776] } const ( _SizeB1024_name_0 = "b" _SizeB1024_name_1 = "KiB" _SizeB1024_name_2 = "MiB" _SizeB1024_name_3 = "GiB" _SizeB1024_name_4 = "TiB" ) func (i SizeB1024) String() string { switch { case i == 1: return _SizeB1024_name_0 case i == 1024: return _SizeB1024_name_1 case i == 1048576: return _SizeB1024_name_2 case i == 1073741824: return _SizeB1024_name_3 case i == 1099511627776: return _SizeB1024_name_4 default: return "SizeB1024(" + strconv.FormatInt(int64(i), 10) + ")" } } mpb-7.3.2/decor/speed.go000066400000000000000000000102771417272200500150330ustar00rootroot00000000000000package decor import ( "fmt" "math" "time" "github.com/VividCortex/ewma" ) // FmtAsSpeed adds "/s" to the end of the input formatter. To be // used with SizeB1000 or SizeB1024 types, for example: // // fmt.Printf("%.1f", FmtAsSpeed(SizeB1024(2048))) // func FmtAsSpeed(input fmt.Formatter) fmt.Formatter { return &speedFormatter{input} } type speedFormatter struct { fmt.Formatter } func (self *speedFormatter) Format(st fmt.State, verb rune) { self.Formatter.Format(st, verb) optimisticStringWriter(st)("/s") } // EwmaSpeed exponential-weighted-moving-average based speed decorator. // For this decorator to work correctly you have to measure each // iteration's duration and pass it to the // *Bar.DecoratorEwmaUpdate(time.Duration) method after each increment. func EwmaSpeed(unit int, format string, age float64, wcc ...WC) Decorator { var average ewma.MovingAverage if age == 0 { average = ewma.NewMovingAverage() } else { average = ewma.NewMovingAverage(age) } return MovingAverageSpeed(unit, format, NewThreadSafeMovingAverage(average), wcc...) } // MovingAverageSpeed decorator relies on MovingAverage implementation // to calculate its average. // // `unit` one of [0|UnitKiB|UnitKB] zero for no unit // // `format` printf compatible verb for value, like "%f" or "%d" // // `average` MovingAverage implementation // // `wcc` optional WC config // // format examples: // // unit=UnitKiB, format="%.1f" output: "1.0MiB/s" // unit=UnitKiB, format="% .1f" output: "1.0 MiB/s" // unit=UnitKB, format="%.1f" output: "1.0MB/s" // unit=UnitKB, format="% .1f" output: "1.0 MB/s" // func MovingAverageSpeed(unit int, format string, average ewma.MovingAverage, wcc ...WC) Decorator { if format == "" { format = "%.0f" } d := &movingAverageSpeed{ WC: initWC(wcc...), average: average, producer: chooseSpeedProducer(unit, format), } return d } type movingAverageSpeed struct { WC producer func(float64) string average ewma.MovingAverage msg string } func (d *movingAverageSpeed) Decor(s Statistics) string { if !s.Completed { var speed float64 if v := d.average.Value(); v > 0 { speed = 1 / v } d.msg = d.producer(speed * 1e9) } return d.FormatMsg(d.msg) } func (d *movingAverageSpeed) EwmaUpdate(n int64, dur time.Duration) { durPerByte := float64(dur) / float64(n) if math.IsInf(durPerByte, 0) || math.IsNaN(durPerByte) { return } d.average.Add(durPerByte) } // AverageSpeed decorator with dynamic unit measure adjustment. It's // a wrapper of NewAverageSpeed. func AverageSpeed(unit int, format string, wcc ...WC) Decorator { return NewAverageSpeed(unit, format, 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 // // `format` printf compatible verb for value, like "%f" or "%d" // // `startTime` start time // // `wcc` optional WC config // // format examples: // // unit=UnitKiB, format="%.1f" output: "1.0MiB/s" // unit=UnitKiB, format="% .1f" output: "1.0 MiB/s" // unit=UnitKB, format="%.1f" output: "1.0MB/s" // unit=UnitKB, format="% .1f" output: "1.0 MB/s" // func NewAverageSpeed(unit int, format string, startTime time.Time, wcc ...WC) Decorator { if format == "" { format = "%.0f" } d := &averageSpeed{ WC: initWC(wcc...), startTime: startTime, producer: chooseSpeedProducer(unit, format), } return d } type averageSpeed struct { WC startTime time.Time producer func(float64) string msg string } func (d *averageSpeed) Decor(s Statistics) string { if !s.Completed { speed := float64(s.Current) / float64(time.Since(d.startTime)) d.msg = d.producer(speed * 1e9) } return d.FormatMsg(d.msg) } func (d *averageSpeed) AverageAdjust(startTime time.Time) { d.startTime = startTime } func chooseSpeedProducer(unit int, format string) func(float64) string { switch unit { case UnitKiB: return func(speed float64) string { return fmt.Sprintf(format, FmtAsSpeed(SizeB1024(math.Round(speed)))) } case UnitKB: return func(speed float64) string { return fmt.Sprintf(format, FmtAsSpeed(SizeB1000(math.Round(speed)))) } default: return func(speed float64) string { return fmt.Sprintf(format, speed) } } } mpb-7.3.2/decor/speed_test.go000066400000000000000000000120531417272200500160640ustar00rootroot00000000000000package decor import ( "testing" "time" ) func TestSpeedKiBDecor(t *testing.T) { cases := []struct { name string fmt string unit int current int64 elapsed time.Duration expected string }{ { name: "empty fmt", unit: UnitKiB, fmt: "", current: 0, elapsed: time.Second, expected: "0b/s", }, { name: "UnitKiB:%d:0b", unit: UnitKiB, fmt: "%d", current: 0, elapsed: time.Second, expected: "0b/s", }, { name: "UnitKiB:% .2f:0b", unit: UnitKiB, fmt: "% .2f", current: 0, elapsed: time.Second, expected: "0.00 b/s", }, { name: "UnitKiB:%d:1b", unit: UnitKiB, fmt: "%d", current: 1, elapsed: time.Second, expected: "1b/s", }, { name: "UnitKiB:% .2f:1b", unit: UnitKiB, fmt: "% .2f", current: 1, elapsed: time.Second, expected: "1.00 b/s", }, { name: "UnitKiB:%d:KiB", unit: UnitKiB, fmt: "%d", current: 2 * int64(_iKiB), elapsed: 1 * time.Second, expected: "2KiB/s", }, { name: "UnitKiB:% .f:KiB", unit: UnitKiB, fmt: "% .2f", current: 2 * int64(_iKiB), elapsed: 1 * time.Second, expected: "2.00 KiB/s", }, { name: "UnitKiB:%d:MiB", unit: UnitKiB, fmt: "%d", current: 2 * int64(_iMiB), elapsed: 1 * time.Second, expected: "2MiB/s", }, { name: "UnitKiB:% .2f:MiB", unit: UnitKiB, fmt: "% .2f", current: 2 * int64(_iMiB), elapsed: 1 * time.Second, expected: "2.00 MiB/s", }, { name: "UnitKiB:%d:GiB", unit: UnitKiB, fmt: "%d", current: 2 * int64(_iGiB), elapsed: 1 * time.Second, expected: "2GiB/s", }, { name: "UnitKiB:% .2f:GiB", unit: UnitKiB, fmt: "% .2f", current: 2 * int64(_iGiB), elapsed: 1 * time.Second, expected: "2.00 GiB/s", }, { name: "UnitKiB:%d:TiB", unit: UnitKiB, fmt: "%d", current: 2 * int64(_iTiB), elapsed: 1 * time.Second, expected: "2TiB/s", }, { name: "UnitKiB:% .2f:TiB", unit: UnitKiB, fmt: "% .2f", current: 2 * int64(_iTiB), elapsed: 1 * time.Second, expected: "2.00 TiB/s", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { decor := NewAverageSpeed(tc.unit, tc.fmt, time.Now().Add(-tc.elapsed)) stat := Statistics{ Current: tc.current, } res := decor.Decor(stat) if res != tc.expected { t.Fatalf("expected: %q, got: %q\n", tc.expected, res) } }) } } func TestSpeedKBDecor(t *testing.T) { cases := []struct { name string fmt string unit int current int64 elapsed time.Duration expected string }{ { name: "empty fmt", unit: UnitKB, fmt: "", current: 0, elapsed: time.Second, expected: "0b/s", }, { name: "UnitKB:%d:0b", unit: UnitKB, fmt: "%d", current: 0, elapsed: time.Second, expected: "0b/s", }, { name: "UnitKB:% .2f:0b", unit: UnitKB, fmt: "% .2f", current: 0, elapsed: time.Second, expected: "0.00 b/s", }, { name: "UnitKB:%d:1b", unit: UnitKB, fmt: "%d", current: 1, elapsed: time.Second, expected: "1b/s", }, { name: "UnitKB:% .2f:1b", unit: UnitKB, fmt: "% .2f", current: 1, elapsed: time.Second, expected: "1.00 b/s", }, { name: "UnitKB:%d:KB", unit: UnitKB, fmt: "%d", current: 2 * int64(_KB), elapsed: 1 * time.Second, expected: "2KB/s", }, { name: "UnitKB:% .f:KB", unit: UnitKB, fmt: "% .2f", current: 2 * int64(_KB), elapsed: 1 * time.Second, expected: "2.00 KB/s", }, { name: "UnitKB:%d:MB", unit: UnitKB, fmt: "%d", current: 2 * int64(_MB), elapsed: 1 * time.Second, expected: "2MB/s", }, { name: "UnitKB:% .2f:MB", unit: UnitKB, fmt: "% .2f", current: 2 * int64(_MB), elapsed: 1 * time.Second, expected: "2.00 MB/s", }, { name: "UnitKB:%d:GB", unit: UnitKB, fmt: "%d", current: 2 * int64(_GB), elapsed: 1 * time.Second, expected: "2GB/s", }, { name: "UnitKB:% .2f:GB", unit: UnitKB, fmt: "% .2f", current: 2 * int64(_GB), elapsed: 1 * time.Second, expected: "2.00 GB/s", }, { name: "UnitKB:%d:TB", unit: UnitKB, fmt: "%d", current: 2 * int64(_TB), elapsed: 1 * time.Second, expected: "2TB/s", }, { name: "UnitKB:% .2f:TB", unit: UnitKB, fmt: "% .2f", current: 2 * int64(_TB), elapsed: 1 * time.Second, expected: "2.00 TB/s", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { decor := NewAverageSpeed(tc.unit, tc.fmt, time.Now().Add(-tc.elapsed)) stat := Statistics{ Current: tc.current, } res := decor.Decor(stat) if res != tc.expected { t.Fatalf("expected: %q, got: %q\n", tc.expected, res) } }) } } mpb-7.3.2/decor/spinner.go000066400000000000000000000007771417272200500154150ustar00rootroot00000000000000package decor var defaultSpinnerStyle = []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"} // Spinner returns spinner decorator. // // `frames` spinner frames, if nil or len==0, default is used // // `wcc` optional WC config func Spinner(frames []string, wcc ...WC) Decorator { if len(frames) == 0 { frames = defaultSpinnerStyle } var count uint f := func(s Statistics) string { frame := frames[count%uint(len(frames))] count++ return frame } return Any(f, wcc...) } mpb-7.3.2/decorators_test.go000066400000000000000000000101151417272200500160320ustar00rootroot00000000000000package mpb_test import ( "sync" "testing" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func TestNameDecorator(t *testing.T) { tests := []struct { decorator decor.Decorator want string }{ { decorator: decor.Name("Test"), want: "Test", }, { decorator: decor.Name("Test", decor.WC{W: len("Test")}), want: "Test", }, { decorator: decor.Name("Test", decor.WC{W: 10}), want: " Test", }, { decorator: decor.Name("Test", decor.WC{W: 10, C: decor.DidentRight}), want: "Test ", }, } for _, test := range tests { got := test.decorator.Decor(decor.Statistics{}) if got != test.want { t.Errorf("Want: %q, Got: %q\n", test.want, got) } } } type step struct { stat decor.Statistics decorator decor.Decorator want string } func TestPercentageDwidthSync(t *testing.T) { testCases := [][]step{ { { decor.Statistics{Total: 100, Current: 8}, decor.Percentage(decor.WCSyncWidth), "8 %", }, { decor.Statistics{Total: 100, Current: 9}, decor.Percentage(decor.WCSyncWidth), "9 %", }, }, { { decor.Statistics{Total: 100, Current: 9}, decor.Percentage(decor.WCSyncWidth), " 9 %", }, { decor.Statistics{Total: 100, Current: 10}, decor.Percentage(decor.WCSyncWidth), "10 %", }, }, { { decor.Statistics{Total: 100, Current: 9}, decor.Percentage(decor.WCSyncWidth), " 9 %", }, { decor.Statistics{Total: 100, Current: 100}, decor.Percentage(decor.WCSyncWidth), "100 %", }, }, } testDecoratorConcurrently(t, testCases) } func TestPercentageDwidthSyncDidentRight(t *testing.T) { testCases := [][]step{ { { decor.Statistics{Total: 100, Current: 8}, decor.Percentage(decor.WCSyncWidthR), "8 %", }, { decor.Statistics{Total: 100, Current: 9}, decor.Percentage(decor.WCSyncWidthR), "9 %", }, }, { { decor.Statistics{Total: 100, Current: 9}, decor.Percentage(decor.WCSyncWidthR), "9 % ", }, { decor.Statistics{Total: 100, Current: 10}, decor.Percentage(decor.WCSyncWidthR), "10 %", }, }, { { decor.Statistics{Total: 100, Current: 9}, decor.Percentage(decor.WCSyncWidthR), "9 % ", }, { decor.Statistics{Total: 100, Current: 100}, decor.Percentage(decor.WCSyncWidthR), "100 %", }, }, } testDecoratorConcurrently(t, testCases) } func TestPercentageDSyncSpace(t *testing.T) { testCases := [][]step{ { { decor.Statistics{Total: 100, Current: 8}, decor.Percentage(decor.WCSyncSpace), " 8 %", }, { decor.Statistics{Total: 100, Current: 9}, decor.Percentage(decor.WCSyncSpace), " 9 %", }, }, { { decor.Statistics{Total: 100, Current: 9}, decor.Percentage(decor.WCSyncSpace), " 9 %", }, { decor.Statistics{Total: 100, Current: 10}, decor.Percentage(decor.WCSyncSpace), " 10 %", }, }, { { decor.Statistics{Total: 100, Current: 9}, decor.Percentage(decor.WCSyncSpace), " 9 %", }, { decor.Statistics{Total: 100, Current: 100}, decor.Percentage(decor.WCSyncSpace), " 100 %", }, }, } testDecoratorConcurrently(t, testCases) } func testDecoratorConcurrently(t *testing.T, testCases [][]step) { if len(testCases) == 0 { t.Fail() } for _, columnCase := range testCases { mpb.SyncWidth(toSyncMatrix(columnCase)) numBars := len(columnCase) gott := make([]chan string, numBars) wg := new(sync.WaitGroup) wg.Add(numBars) for i, step := range columnCase { step := step ch := make(chan string, 1) go func() { defer wg.Done() ch <- step.decorator.Decor(step.stat) }() gott[i] = ch } wg.Wait() for i, ch := range gott { got := <-ch want := columnCase[i].want if got != want { t.Errorf("Want: %q, Got: %q\n", want, got) } } } } func toSyncMatrix(ss []step) map[int][]chan int { var column []chan int for _, s := range ss { if ch, ok := s.decorator.Sync(); ok { column = append(column, ch) } } return map[int][]chan int{0: column} } mpb-7.3.2/doc.go000066400000000000000000000001361417272200500133750ustar00rootroot00000000000000// Package mpb is a library for rendering progress bars in terminal applications. package mpb mpb-7.3.2/draw_test.go000066400000000000000000001075711417272200500146370ustar00rootroot00000000000000package mpb import ( "bytes" "testing" "unicode/utf8" ) func TestDrawDefault(t *testing.T) { // key is termWidth testSuite := map[int][]struct { style BarStyleComposer name string total int64 current int64 refill int64 barWidth int trim bool want string }{ 0: { { style: BarStyle(), name: "t,c{60,20}", total: 60, current: 20, want: "", }, { style: BarStyle(), name: "t,c{60,20}trim", total: 60, current: 20, trim: true, want: "", }, }, 1: { { style: BarStyle(), name: "t,c{60,20}", total: 60, current: 20, want: "", }, { style: BarStyle(), name: "t,c{60,20}trim", total: 60, current: 20, trim: true, want: "", }, }, 2: { { style: BarStyle(), name: "t,c{60,20}", total: 60, current: 20, want: " ", }, { style: BarStyle(), name: "t,c{60,20}trim", total: 60, current: 20, trim: true, want: "[]", }, }, 3: { { style: BarStyle(), name: "t,c{60,20}", total: 60, current: 20, want: " ", }, { style: BarStyle(), name: "t,c{60,20}trim", total: 60, current: 20, trim: true, want: "[-]", }, { style: BarStyle(), name: "t,c{60,59}", total: 60, current: 59, want: " ", }, { style: BarStyle(), name: "t,c{60,59}trim", total: 60, current: 59, trim: true, want: "[>]", }, { style: BarStyle(), name: "t,c{60,60}", total: 60, current: 60, want: " ", }, { style: BarStyle(), name: "t,c{60,60}trim", total: 60, current: 60, trim: true, want: "[=]", }, }, 4: { { style: BarStyle(), name: "t,c{60,20}", total: 60, current: 20, want: " [] ", }, { style: BarStyle(), name: "t,c{60,20}trim", total: 60, current: 20, trim: true, want: "[>-]", }, { style: BarStyle(), name: "t,c{60,59}", total: 60, current: 59, want: " [] ", }, { style: BarStyle(), name: "t,c{60,59}trim", total: 60, current: 59, trim: true, want: "[=>]", }, { style: BarStyle(), name: "t,c{60,60}", total: 60, current: 60, want: " [] ", }, { style: BarStyle(), name: "t,c{60,60}trim", total: 60, current: 60, trim: true, want: "[==]", }, }, 5: { { style: BarStyle(), name: "t,c{60,20}", total: 60, current: 20, want: " [-] ", }, { style: BarStyle(), name: "t,c{60,20}trim", total: 60, current: 20, trim: true, want: "[>--]", }, { style: BarStyle(), name: "t,c{60,59}", total: 60, current: 59, want: " [>] ", }, { style: BarStyle(), name: "t,c{60,59}trim", total: 60, current: 59, trim: true, want: "[==>]", }, { style: BarStyle(), name: "t,c{60,60}", total: 60, current: 60, want: " [=] ", }, { style: BarStyle(), name: "t,c{60,60}trim", total: 60, current: 60, trim: true, want: "[===]", }, }, 6: { { style: BarStyle(), name: "t,c{60,20}", total: 60, current: 20, want: " [>-] ", }, { style: BarStyle(), name: "t,c{60,20}trim", total: 60, current: 20, trim: true, want: "[>---]", }, { style: BarStyle(), name: "t,c{60,59}", total: 60, current: 59, want: " [=>] ", }, { style: BarStyle(), name: "t,c{60,59}trim", total: 60, current: 59, trim: true, want: "[===>]", }, { style: BarStyle(), name: "t,c{60,60}", total: 60, current: 60, want: " [==] ", }, { style: BarStyle(), name: "t,c{60,60}trim", total: 60, current: 60, trim: true, want: "[====]", }, }, 7: { { style: BarStyle(), name: "t,c{60,20}", total: 60, current: 20, want: " [>--] ", }, { style: BarStyle(), name: "t,c{60,20}trim", total: 60, current: 20, trim: true, want: "[=>---]", }, { style: BarStyle(), name: "t,c{60,59}", total: 60, current: 59, want: " [==>] ", }, { style: BarStyle(), name: "t,c{60,59}trim", total: 60, current: 59, trim: true, want: "[====>]", }, { style: BarStyle(), name: "t,c{60,60}", total: 60, current: 60, want: " [===] ", }, { style: BarStyle(), name: "t,c{60,60}trim", total: 60, current: 60, trim: true, want: "[=====]", }, }, 8: { { style: BarStyle(), name: "t,c{60,20}", total: 60, current: 20, want: " [>---] ", }, { style: BarStyle(), name: "t,c{60,20}trim", total: 60, current: 20, trim: true, want: "[=>----]", }, { style: BarStyle(), name: "t,c{60,59}", total: 60, current: 59, want: " [===>] ", }, { style: BarStyle(), name: "t,c{60,59}trim", total: 60, current: 59, trim: true, want: "[=====>]", }, { style: BarStyle(), name: "t,c{60,60}", total: 60, current: 60, want: " [====] ", }, { style: BarStyle(), name: "t,c{60,60}trim", total: 60, current: 60, trim: true, want: "[======]", }, }, 80: { { style: BarStyle(), name: "t,c{60,20}", total: 60, current: 20, want: " [========================>---------------------------------------------------] ", }, { style: BarStyle(), name: "t,c{60,20}trim", total: 60, current: 20, trim: true, want: "[=========================>----------------------------------------------------]", }, { style: BarStyle(), name: "t,c,bw{60,20,60}", total: 60, current: 20, barWidth: 60, want: " [==================>---------------------------------------] ", }, { style: BarStyle(), name: "t,c,bw{60,20,60}trim", total: 60, current: 20, barWidth: 60, trim: true, want: "[==================>---------------------------------------]", }, { style: BarStyle(), name: "t,c{60,59}", total: 60, current: 59, want: " [==========================================================================>-] ", }, { style: BarStyle(), name: "t,c{60,59}trim", total: 60, current: 59, trim: true, want: "[============================================================================>-]", }, { style: BarStyle(), name: "t,c,bw{60,59,60}", total: 60, current: 59, barWidth: 60, want: " [========================================================>-] ", }, { style: BarStyle(), name: "t,c,bw{60,59,60}trim", total: 60, current: 59, barWidth: 60, trim: true, want: "[========================================================>-]", }, { style: BarStyle(), name: "t,c{60,60}", total: 60, current: 60, want: " [============================================================================] ", }, { style: BarStyle(), name: "t,c{60,60}trim", total: 60, current: 60, trim: true, want: "[==============================================================================]", }, { style: BarStyle(), name: "t,c,bw{60,60,60}", total: 60, current: 60, barWidth: 60, want: " [==========================================================] ", }, { style: BarStyle(), name: "t,c,bw{60,60,60}trim", total: 60, current: 60, barWidth: 60, trim: true, want: "[==========================================================]", }, }, 99: { { style: BarStyle(), name: "t,c{100,1}", total: 100, current: 1, want: " [>----------------------------------------------------------------------------------------------] ", }, { style: BarStyle(), name: "t,c{100,1}trim", total: 100, current: 1, trim: true, want: "[>------------------------------------------------------------------------------------------------]", }, { style: BarStyle(), name: "t,c,r{100,40,33}", total: 100, current: 40, refill: 33, want: " [+++++++++++++++++++++++++++++++======>---------------------------------------------------------] ", }, { style: BarStyle(), name: "t,c,r{100,40,33}trim", total: 100, current: 40, refill: 33, trim: true, want: "[++++++++++++++++++++++++++++++++======>----------------------------------------------------------]", }, { style: BarStyle().Tip("<").Reverse(), name: "t,c,r{100,40,33},rev", total: 100, current: 40, refill: 33, want: " [---------------------------------------------------------<======+++++++++++++++++++++++++++++++] ", }, { style: BarStyle().Tip("<").Reverse(), name: "t,c,r{100,40,33}trim,rev", total: 100, current: 40, refill: 33, trim: true, want: "[----------------------------------------------------------<======++++++++++++++++++++++++++++++++]", }, { style: BarStyle(), name: "t,c{100,99}", total: 100, current: 99, want: " [=============================================================================================>-] ", }, { style: BarStyle(), name: "t,c{100,99}trim", total: 100, current: 99, trim: true, want: "[===============================================================================================>-]", }, { style: BarStyle(), name: "t,c{100,100}", total: 100, current: 100, want: " [===============================================================================================] ", }, { style: BarStyle(), name: "t,c{100,100}trim", total: 100, current: 100, trim: true, want: "[=================================================================================================]", }, { style: BarStyle(), name: "t,c,r{100,100,99}", total: 100, current: 100, refill: 99, want: " [++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=] ", }, { style: BarStyle(), name: "t,c,r{100,100,99}trim", total: 100, current: 100, refill: 99, trim: true, want: "[++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=]", }, { style: BarStyle().Reverse(), name: "t,c,r{100,100,99}rev", total: 100, current: 100, refill: 99, want: " [=++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++] ", }, { style: BarStyle().Reverse(), name: "t,c,r{100,100,99}trim,rev", total: 100, current: 100, refill: 99, trim: true, want: "[=++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++]", }, { style: BarStyle(), name: "t,c,r{100,100,100}", total: 100, current: 100, refill: 100, want: " [+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++] ", }, { style: BarStyle(), name: "t,c,r{100,100,100}trim", total: 100, current: 100, refill: 100, trim: true, want: "[+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++]", }, { style: BarStyle().Reverse(), name: "t,c,r{100,100,100}rev", total: 100, current: 100, refill: 100, want: " [+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++] ", }, { style: BarStyle().Reverse(), name: "t,c,r{100,100,100}trim", total: 100, current: 100, refill: 100, trim: true, want: "[+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++]", }, }, 100: { { style: BarStyle(), name: "t,c{100,0}", total: 100, current: 0, want: " [------------------------------------------------------------------------------------------------] ", }, { style: BarStyle(), name: "t,c{100,0}trim", total: 100, current: 0, trim: true, want: "[--------------------------------------------------------------------------------------------------]", }, { style: BarStyle(), name: "t,c{100,1}", total: 100, current: 1, want: " [>-----------------------------------------------------------------------------------------------] ", }, { style: BarStyle(), name: "t,c{100,1}trim", total: 100, current: 1, trim: true, want: "[>-------------------------------------------------------------------------------------------------]", }, { style: BarStyle(), name: "t,c{100,99}", total: 100, current: 99, want: " [==============================================================================================>-] ", }, { style: BarStyle(), name: "t,c{100,99}trim", total: 100, current: 99, trim: true, want: "[================================================================================================>-]", }, { style: BarStyle(), name: "t,c{100,100}", total: 100, current: 100, want: " [================================================================================================] ", }, { style: BarStyle(), name: "t,c{100,100}trim", total: 100, current: 100, trim: true, want: "[==================================================================================================]", }, { style: BarStyle(), name: "t,c,r{100,100,99}", total: 100, current: 100, refill: 99, want: " [+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=] ", }, { style: BarStyle(), name: "t,c,r{100,100,99}trim", total: 100, current: 100, refill: 99, trim: true, want: "[+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=]", }, { style: BarStyle(), name: "t,c,r{100,100,100}", total: 100, current: 100, refill: 100, want: " [++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++] ", }, { style: BarStyle(), name: "t,c,r{100,100,100}trim", total: 100, current: 100, refill: 100, trim: true, want: "[++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++]", }, { style: BarStyle().Reverse(), name: "t,c,r{100,100,99}rev", total: 100, current: 100, refill: 99, want: " [=+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++] ", }, { style: BarStyle().Reverse(), name: "t,c,r{100,100,99}trim,rev", total: 100, current: 100, refill: 99, trim: true, want: "[=+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++]", }, { style: BarStyle().Reverse(), name: "t,c,r{100,100,100}rev", total: 100, current: 100, refill: 100, want: " [++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++] ", }, { style: BarStyle().Reverse(), name: "t,c,r{100,100,100}trim", total: 100, current: 100, refill: 100, trim: true, want: "[++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++]", }, { style: BarStyle(), name: "t,c,r{100,40,33}", total: 100, current: 40, refill: 33, want: " [++++++++++++++++++++++++++++++++=====>----------------------------------------------------------] ", }, { style: BarStyle(), name: "t,c,r{100,40,33}trim", total: 100, current: 40, refill: 33, trim: true, want: "[++++++++++++++++++++++++++++++++======>-----------------------------------------------------------]", }, { style: BarStyle().Tip("<").Reverse(), name: "t,c,r{100,40,33},rev", total: 100, current: 40, refill: 33, want: " [----------------------------------------------------------<=====++++++++++++++++++++++++++++++++] ", }, { style: BarStyle().Tip("<").Reverse(), name: "t,c,r{100,40,33}trim,rev", total: 100, current: 40, refill: 33, trim: true, want: "[-----------------------------------------------------------<======++++++++++++++++++++++++++++++++]", }, }, } var tmpBuf bytes.Buffer for tw, cases := range testSuite { for _, tc := range cases { s := newTestState(tc.style.Build()) s.reqWidth = tc.barWidth s.total = tc.total s.current = tc.current s.trimSpace = tc.trim s.refill = tc.refill tmpBuf.Reset() _, err := tmpBuf.ReadFrom(s.draw(newStatistics(tw, s))) if err != nil { t.FailNow() } by := tmpBuf.Bytes() got := string(by[:len(by)-1]) if !utf8.ValidString(got) { t.Fail() } if got != tc.want { t.Errorf("termWidth:%d %q want: %q %d, got: %q %d\n", tw, tc.name, tc.want, utf8.RuneCountInString(tc.want), got, utf8.RuneCountInString(got)) } } } } func TestDrawTipOnComplete(t *testing.T) { // key is termWidth testSuite := map[int][]struct { style BarStyleComposer name string total int64 current int64 refill int64 barWidth int trim bool want string }{ 3: { { style: BarStyle().TipOnComplete(">"), name: "t,c{60,60}", total: 60, current: 60, want: " ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,60}trim", total: 60, current: 60, trim: true, want: "[>]", }, }, 4: { { style: BarStyle().TipOnComplete(">"), name: "t,c{60,59}", total: 60, current: 59, want: " [] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,59}trim", total: 60, current: 59, trim: true, want: "[=>]", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,60}", total: 60, current: 60, want: " [] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,60}trim", total: 60, current: 60, trim: true, want: "[=>]", }, }, 5: { { style: BarStyle().TipOnComplete(">"), name: "t,c{60,59}", total: 60, current: 59, want: " [>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,59}trim", total: 60, current: 59, trim: true, want: "[==>]", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,60}", total: 60, current: 60, want: " [>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,60}trim", total: 60, current: 60, trim: true, want: "[==>]", }, }, 6: { { style: BarStyle().TipOnComplete(">"), name: "t,c{60,59}", total: 60, current: 59, want: " [=>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,59}trim", total: 60, current: 59, trim: true, want: "[===>]", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,60}", total: 60, current: 60, want: " [=>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,60}trim", total: 60, current: 60, trim: true, want: "[===>]", }, }, 7: { { style: BarStyle().TipOnComplete(">"), name: "t,c{60,59}", total: 60, current: 59, want: " [==>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,59}trim", total: 60, current: 59, trim: true, want: "[====>]", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,60}", total: 60, current: 60, want: " [==>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,60}trim", total: 60, current: 60, trim: true, want: "[====>]", }, }, 8: { { style: BarStyle().TipOnComplete(">"), name: "t,c{60,59}", total: 60, current: 59, want: " [===>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,59}trim", total: 60, current: 59, trim: true, want: "[=====>]", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,60}", total: 60, current: 60, want: " [===>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,60}trim", total: 60, current: 60, trim: true, want: "[=====>]", }, }, 80: { { style: BarStyle().TipOnComplete(">"), name: "t,c{60,59}", total: 60, current: 59, want: " [==========================================================================>-] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,59}trim", total: 60, current: 59, trim: true, want: "[============================================================================>-]", }, { style: BarStyle().TipOnComplete(">"), name: "t,c,bw{60,59,60}", total: 60, current: 59, barWidth: 60, want: " [========================================================>-] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c,bw{60,59,60}trim", total: 60, current: 59, barWidth: 60, trim: true, want: "[========================================================>-]", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,60}", total: 60, current: 60, want: " [===========================================================================>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{60,60}trim", total: 60, current: 60, trim: true, want: "[=============================================================================>]", }, { style: BarStyle().TipOnComplete(">"), name: "t,c,bw{60,60,60}", total: 60, current: 60, barWidth: 60, want: " [=========================================================>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c,bw{60,60,60}trim", total: 60, current: 60, barWidth: 60, trim: true, want: "[=========================================================>]", }, }, 99: { { style: BarStyle().TipOnComplete(">"), name: "t,c{100,99}", total: 100, current: 99, want: " [=============================================================================================>-] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{100,99}trim", total: 100, current: 99, trim: true, want: "[===============================================================================================>-]", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{100,100}", total: 100, current: 100, want: " [==============================================================================================>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{100,100}trim", total: 100, current: 100, trim: true, want: "[================================================================================================>]", }, { style: BarStyle().TipOnComplete(">"), name: "t,c,r{100,100,99}", total: 100, current: 100, refill: 99, want: " [++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c,r{100,100,99}trim", total: 100, current: 100, refill: 99, trim: true, want: "[++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>]", }, { style: BarStyle().TipOnComplete("<").Reverse(), name: `t,c,r{100,100,99}TipOnComplete("<").Reverse()`, total: 100, current: 100, refill: 99, want: " [<++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++] ", }, { style: BarStyle().TipOnComplete("<").Reverse(), name: `t,c,r{100,100,99}TipOnComplete("<").Reverse()trim`, total: 100, current: 100, refill: 99, trim: true, want: "[<++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++]", }, { style: BarStyle().TipOnComplete(">"), name: "t,c,r{100,100,100}", total: 100, current: 100, refill: 100, want: " [++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c,r{100,100,100}trim", total: 100, current: 100, refill: 100, trim: true, want: "[++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>]", }, { style: BarStyle().TipOnComplete("<").Reverse(), name: `t,c,r{100,100,100}TipOnComplete("<").Reverse()`, total: 100, current: 100, refill: 100, want: " [<++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++] ", }, { style: BarStyle().TipOnComplete("<").Reverse(), name: `t,c,r{100,100,100}TipOnComplete("<").Reverse()trim`, total: 100, current: 100, refill: 100, trim: true, want: "[<++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++]", }, }, 100: { { style: BarStyle().TipOnComplete(">"), name: "t,c{100,99}", total: 100, current: 99, want: " [==============================================================================================>-] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{100,99}trim", total: 100, current: 99, trim: true, want: "[================================================================================================>-]", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{100,100}", total: 100, current: 100, want: " [===============================================================================================>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c{100,100}trim", total: 100, current: 100, trim: true, want: "[=================================================================================================>]", }, { style: BarStyle().TipOnComplete(">"), name: "t,c,r{100,100,99}", total: 100, current: 100, refill: 99, want: " [+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c,r{100,100,99}trim", total: 100, current: 100, refill: 99, trim: true, want: "[+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>]", }, { style: BarStyle().TipOnComplete(">"), name: "t,c,r{100,100,100}", total: 100, current: 100, refill: 100, want: " [+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>] ", }, { style: BarStyle().TipOnComplete(">"), name: "t,c,r{100,100,100}trim", total: 100, current: 100, refill: 100, trim: true, want: "[+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>]", }, }, } var tmpBuf bytes.Buffer for tw, cases := range testSuite { for _, tc := range cases { s := newTestState(tc.style.Build()) s.reqWidth = tc.barWidth s.total = tc.total s.current = tc.current s.trimSpace = tc.trim s.refill = tc.refill tmpBuf.Reset() _, err := tmpBuf.ReadFrom(s.draw(newStatistics(tw, s))) if err != nil { t.FailNow() } by := tmpBuf.Bytes() got := string(by[:len(by)-1]) if !utf8.ValidString(got) { t.Fail() } if got != tc.want { t.Errorf("termWidth:%d %q want: %q %d, got: %q %d\n", tw, tc.name, tc.want, utf8.RuneCountInString(tc.want), got, utf8.RuneCountInString(got)) } } } } func TestDrawDoubleWidth(t *testing.T) { // key is termWidth testSuite := map[int][]struct { style BarStyleComposer name string total int64 current int64 refill int64 barWidth int trim bool want string }{ 99: { { style: BarStyle().Lbound("の").Rbound("の"), name: `t,c{100,1}.Lbound("の").Rbound("の")`, total: 100, current: 1, want: " の>--------------------------------------------------------------------------------------------の ", }, { style: BarStyle().Lbound("の").Rbound("の"), name: `t,c{100,1}.Lbound("の").Rbound("の")`, total: 100, current: 2, want: " の=>-------------------------------------------------------------------------------------------の ", }, { style: BarStyle().Tip("だ"), name: `t,c{100,1}Tip("だ")`, total: 100, current: 1, want: " [だ---------------------------------------------------------------------------------------------] ", }, { style: BarStyle().Tip("だ"), name: `t,c{100,2}Tip("だ")`, total: 100, current: 2, want: " [だ---------------------------------------------------------------------------------------------] ", }, { style: BarStyle().Tip("だ"), name: `t,c{100,3}Tip("だ")`, total: 100, current: 3, want: " [=だ--------------------------------------------------------------------------------------------] ", }, { style: BarStyle().Tip("だ"), name: `t,c{100,99}Tip("だ")`, total: 100, current: 99, want: " [============================================================================================だ-] ", }, { style: BarStyle().Tip("だ"), name: `t,c{100,100}Tip("だ")`, total: 100, current: 100, want: " [===============================================================================================] ", }, { style: BarStyle().TipOnComplete("だ"), name: `t,c{100,100}TipOnComplete("だ")`, total: 100, current: 100, want: " [=============================================================================================だ] ", }, { style: BarStyle().Filler("の").Tip("だ").Padding("つ"), name: `t,c{100,1}Filler("の").Tip("だ").Padding("つ")`, total: 100, current: 1, want: " [だつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつ…] ", }, { style: BarStyle().Filler("の").Tip("だ").Padding("つ"), name: `t,c{100,2}Filler("の").Tip("だ").Padding("つ")`, total: 100, current: 2, want: " [だつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつつ…] ", }, { style: BarStyle().Filler("の").Tip("だ").Padding("つ"), name: `t,c{100,99}Filler("の").Tip("だ").Padding("つ")`, total: 100, current: 99, want: " [ののののののののののののののののののののののののののののののののののののののののののののののだ…] ", }, { style: BarStyle().Filler("の").Tip("だ").Padding("つ"), name: `t,c{100,100}.Filler("の").Tip("だ").Padding("つ")`, total: 100, current: 100, want: " […ののののののののののののののののののののののののののののののののののののののののののののののの] ", }, { style: BarStyle().Filler("の").Tip("だ").Padding("つ").Reverse(), name: `t,c{100,100}Filler("の").Tip("だ").Padding("つ").Reverse()`, total: 100, current: 100, want: " [ののののののののののののののののののののののののののののののののののののののののののののののの…] ", }, { style: BarStyle().Filler("の").Tip("だ").TipOnComplete("だ").Padding("つ"), name: `t,c{100,99}Filler("の").Tip("だ").TipOnComplete("だ").Padding("つ")`, total: 100, current: 99, want: " [ののののののののののののののののののののののののののののののののののののののののののののののだ…] ", }, { style: BarStyle().Filler("の").Tip("だ").TipOnComplete("だ").Padding("つ"), name: `t,c{100,100}.Filler("の").Tip("だ").TipOnComplete("だ").Padding("つ")`, total: 100, current: 100, want: " […ののののののののののののののののののののののののののののののののののののののののののののののだ] ", }, { style: BarStyle().Filler("の").Tip("だ").TipOnComplete("だ").Padding("つ").Reverse(), name: `t,c{100,100}.Filler("の").Tip("だ").TipOnComplete("だ").Padding("つ").Reverse()`, total: 100, current: 100, want: " [だのののののののののののののののののののののののののののののののののののののののののののののの…] ", }, { style: BarStyle().Refiller("の"), name: `t,c,r{100,100,99}Refiller("の")`, total: 100, current: 100, refill: 99, want: " [ののののののののののののののののののののののののののののののののののののののののののののののの=] ", }, { style: BarStyle().Refiller("の"), name: `t,c,r{100,100,99}Refiller("の")trim`, total: 100, current: 100, refill: 99, trim: true, want: "[のののののののののののののののののののののののののののののののののののののののののののののののの=]", }, }, } var tmpBuf bytes.Buffer for tw, cases := range testSuite { for _, tc := range cases { s := newTestState(tc.style.Build()) s.reqWidth = tc.barWidth s.total = tc.total s.current = tc.current s.trimSpace = tc.trim s.refill = tc.refill tmpBuf.Reset() _, err := tmpBuf.ReadFrom(s.draw(newStatistics(tw, s))) if err != nil { t.FailNow() } by := tmpBuf.Bytes() got := string(by[:len(by)-1]) if !utf8.ValidString(got) { t.Fail() } if got != tc.want { t.Errorf("termWidth:%d %q want: %q %d, got: %q %d\n", tw, tc.name, tc.want, utf8.RuneCountInString(tc.want), got, utf8.RuneCountInString(got)) } } } } func newTestState(filler BarFiller) *bState { bs := &bState{ filler: filler, } for i := 0; i < len(bs.buffers); i++ { bs.buffers[i] = bytes.NewBuffer(make([]byte, 0, 512)) } return bs } mpb-7.3.2/example_test.go000066400000000000000000000040511417272200500153220ustar00rootroot00000000000000package mpb_test import ( crand "crypto/rand" "io" "io/ioutil" "math/rand" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func Example() { // initialize progress container, with custom width p := mpb.New(mpb.WithWidth(64)) total := 100 name := "Single Bar:" // create a single bar, which will inherit container's width bar := p.New(int64(total), // BarFillerBuilder with custom style mpb.BarStyle().Lbound("╢").Filler("▌").Tip("▌").Padding("░").Rbound("╟"), mpb.PrependDecorators( // display our name with one space on the right decor.Name(name, decor.WC{W: len(name) + 1, C: decor.DidentRight}), // replace ETA decorator with "done" message, OnComplete event decor.OnComplete( // ETA decorator with ewma age of 60, and width reservation of 4 decor.EwmaETA(decor.ET_STYLE_GO, 60, decor.WC{W: 4}), "done", ), ), mpb.AppendDecorators(decor.Percentage()), ) // simulating some work max := 100 * time.Millisecond for i := 0; i < total; i++ { // start variable is solely for EWMA calculation // EWMA's unit of measure is an iteration's duration start := time.Now() time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) bar.Increment() // we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract bar.DecoratorEwmaUpdate(time.Since(start)) } // wait for our bar to complete and flush p.Wait() } func ExampleBar_Completed() { p := mpb.New() bar := p.AddBar(100) max := 100 * time.Millisecond for !bar.Completed() { time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10) bar.Increment() } p.Wait() } func ExampleBar_ProxyReader() { // import crand "crypto/rand" var total int64 = 1024 * 1024 * 500 reader := io.LimitReader(crand.Reader, total) p := mpb.New() bar := p.AddBar(total, mpb.AppendDecorators( decor.CountersKibiByte("% .2f / % .2f"), ), ) // create proxy reader proxyReader := bar.ProxyReader(reader) defer proxyReader.Close() // and copy from reader, ignoring errors _, _ = io.Copy(ioutil.Discard, proxyReader) p.Wait() } mpb-7.3.2/export_test.go000066400000000000000000000001741417272200500152120ustar00rootroot00000000000000package mpb // make syncWidth func public in test var SyncWidth = syncWidth var MaxWidthDistributor = &maxWidthDistributor mpb-7.3.2/go.mod000066400000000000000000000003741417272200500134130ustar00rootroot00000000000000module github.com/vbauerster/mpb/v7 require ( github.com/VividCortex/ewma v1.2.0 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/mattn/go-runewidth v0.0.13 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 ) go 1.14 mpb-7.3.2/go.sum000066400000000000000000000016731417272200500134430ustar00rootroot00000000000000github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= mpb-7.3.2/internal/000077500000000000000000000000001417272200500141155ustar00rootroot00000000000000mpb-7.3.2/internal/percentage.go000066400000000000000000000007311417272200500165620ustar00rootroot00000000000000package internal import "math" // Percentage is a helper function, to calculate percentage. func Percentage(total, current int64, width uint) float64 { if total <= 0 { return 0 } if current >= total { return float64(width) } return float64(int64(width)*current) / float64(total) } // PercentageRound same as Percentage but with math.Round. func PercentageRound(total, current int64, width uint) float64 { return math.Round(Percentage(total, current, width)) } mpb-7.3.2/internal/percentage_test.go000066400000000000000000000041131417272200500176170ustar00rootroot00000000000000package internal import "testing" func TestPercentage(t *testing.T) { // key is barWidth testSuite := map[uint][]struct { name string total int64 current int64 expected int64 }{ 100: { {"t,c,e{-1,-1,0}", -1, -1, 0}, {"t,c,e{0,-1,0}", 0, -1, 0}, {"t,c,e{0,0,0}", 0, 0, 0}, {"t,c,e{0,1,0}", 0, 1, 0}, {"t,c,e{100,0,0}", 100, 0, 0}, {"t,c,e{100,10,10}", 100, 10, 10}, {"t,c,e{100,15,15}", 100, 15, 15}, {"t,c,e{100,50,50}", 100, 50, 50}, {"t,c,e{100,99,99}", 100, 99, 99}, {"t,c,e{100,100,100}", 100, 100, 100}, {"t,c,e{100,101,101}", 100, 101, 100}, {"t,c,e{120,0,0}", 120, 0, 0}, {"t,c,e{120,10,8}", 120, 10, 8}, {"t,c,e{120,15,13}", 120, 15, 13}, {"t,c,e{120,50,42}", 120, 50, 42}, {"t,c,e{120,60,50}", 120, 60, 50}, {"t,c,e{120,99,83}", 120, 99, 83}, {"t,c,e{120,101,84}", 120, 101, 84}, {"t,c,e{120,118,98}", 120, 118, 98}, {"t,c,e{120,119,99}", 120, 119, 99}, {"t,c,e{120,120,100}", 120, 120, 100}, {"t,c,e{120,121,101}", 120, 121, 100}, }, 80: { {"t,c,e{-1,-1,0}", -1, -1, 0}, {"t,c,e{0,-1,0}", 0, -1, 0}, {"t,c,e{0,0,0}", 0, 0, 0}, {"t,c,e{0,1,0}", 0, 1, 0}, {"t,c,e{100,0,0}", 100, 0, 0}, {"t,c,e{100,10,8}", 100, 10, 8}, {"t,c,e{100,15,12}", 100, 15, 12}, {"t,c,e{100,50,40}", 100, 50, 40}, {"t,c,e{100,99,79}", 100, 99, 79}, {"t,c,e{100,100,80}", 100, 100, 80}, {"t,c,e{100,101,81}", 100, 101, 80}, {"t,c,e{120,0,0}", 120, 0, 0}, {"t,c,e{120,10,7}", 120, 10, 7}, {"t,c,e{120,15,10}", 120, 15, 10}, {"t,c,e{120,50,33}", 120, 50, 33}, {"t,c,e{120,60,40}", 120, 60, 40}, {"t,c,e{120,99,66}", 120, 99, 66}, {"t,c,e{120,101,67}", 120, 101, 67}, {"t,c,e{120,118,79}", 120, 118, 79}, {"t,c,e{120,119,79}", 120, 119, 79}, {"t,c,e{120,120,80}", 120, 120, 80}, {"t,c,e{120,121,81}", 120, 121, 80}, }, } for width, cases := range testSuite { for _, tc := range cases { got := int64(PercentageRound(tc.total, tc.current, width)) if got != tc.expected { t.Errorf("width %d; %s: Expected: %d, got: %d\n", width, tc.name, tc.expected, got) } } } } mpb-7.3.2/internal/width.go000066400000000000000000000003721417272200500155650ustar00rootroot00000000000000package internal // CheckRequestedWidth checks that requested width doesn't overflow // available width func CheckRequestedWidth(requested, available int) int { if requested < 1 || requested >= available { return available } return requested } mpb-7.3.2/priority_queue.go000066400000000000000000000011331417272200500157130ustar00rootroot00000000000000package mpb // A priorityQueue implements heap.Interface type priorityQueue []*Bar func (pq priorityQueue) Len() int { return len(pq) } func (pq priorityQueue) Less(i, j int) bool { return pq[i].priority < pq[j].priority } func (pq priorityQueue) Swap(i, j int) { pq[i], pq[j] = pq[j], pq[i] pq[i].index = i pq[j].index = j } func (pq *priorityQueue) Push(x interface{}) { s := *pq bar := x.(*Bar) bar.index = len(s) s = append(s, bar) *pq = s } func (pq *priorityQueue) Pop() interface{} { s := *pq *pq = s[0 : len(s)-1] bar := s[len(s)-1] bar.index = -1 // for safety return bar } mpb-7.3.2/progress.go000066400000000000000000000223441417272200500145010ustar00rootroot00000000000000package mpb import ( "bytes" "container/heap" "context" "fmt" "io" "math" "os" "sync" "time" "github.com/vbauerster/mpb/v7/cwriter" "github.com/vbauerster/mpb/v7/decor" ) const ( // default RefreshRate prr = 150 * time.Millisecond ) // Progress represents a container that renders one or more progress // bars. type Progress struct { ctx context.Context uwg *sync.WaitGroup cwg *sync.WaitGroup bwg *sync.WaitGroup operateState chan func(*pState) done chan struct{} refreshCh chan time.Time once sync.Once } // pState holds bars in its priorityQueue. It gets passed to // *Progress.serve(...) monitor goroutine. type pState struct { bHeap priorityQueue heapUpdated bool pMatrix map[int][]chan int aMatrix map[int][]chan int barShutdownQueue []*Bar // following are provided/overrided by user idCount int reqWidth int popCompleted bool outputDiscarded bool rr time.Duration uwg *sync.WaitGroup externalRefresh <-chan interface{} renderDelay <-chan struct{} shutdownNotifier chan struct{} parkedBars map[*Bar]*Bar output io.Writer debugOut io.Writer } // New creates new Progress container instance. It's not possible to // reuse instance after *Progress.Wait() method has been called. func New(options ...ContainerOption) *Progress { return NewWithContext(context.Background(), options...) } // NewWithContext creates new Progress container instance with provided // context. It's not possible to reuse instance after *Progress.Wait() // method has been called. func NewWithContext(ctx context.Context, options ...ContainerOption) *Progress { s := &pState{ bHeap: priorityQueue{}, rr: prr, parkedBars: make(map[*Bar]*Bar), output: os.Stdout, } for _, opt := range options { if opt != nil { opt(s) } } p := &Progress{ ctx: ctx, uwg: s.uwg, cwg: new(sync.WaitGroup), bwg: new(sync.WaitGroup), operateState: make(chan func(*pState)), done: make(chan struct{}), } p.cwg.Add(1) go p.serve(s, cwriter.New(s.output)) return p } // AddBar creates a bar with default bar filler. func (p *Progress) AddBar(total int64, options ...BarOption) *Bar { return p.New(total, BarStyle(), options...) } // AddSpinner creates a bar with default spinner filler. func (p *Progress) AddSpinner(total int64, options ...BarOption) *Bar { return p.New(total, SpinnerStyle(), options...) } // New creates a bar with provided BarFillerBuilder. func (p *Progress) New(total int64, builder BarFillerBuilder, options ...BarOption) *Bar { return p.Add(total, builder.Build(), options...) } // Add creates a bar which renders itself by provided filler. // If `total <= 0` trigger complete event is disabled until reset with *bar.SetTotal(int64, bool). // Panics if *Progress instance is done, i.e. called after *Progress.Wait(). func (p *Progress) Add(total int64, filler BarFiller, options ...BarOption) *Bar { if filler == nil { filler = NopStyle().Build() } p.bwg.Add(1) result := make(chan *Bar) select { case p.operateState <- func(ps *pState) { bs := ps.makeBarState(total, filler, options...) bar := newBar(p, bs) if bs.runningBar != nil { bs.runningBar.noPop = true ps.parkedBars[bs.runningBar] = bar } else { heap.Push(&ps.bHeap, bar) ps.heapUpdated = true } ps.idCount++ result <- bar }: bar := <-result bar.subscribeDecorators() return bar case <-p.done: p.bwg.Done() panic(fmt.Sprintf("%T instance can't be reused after it's done!", p)) } } func (p *Progress) dropBar(b *Bar) { select { case p.operateState <- func(s *pState) { if b.index < 0 { return } heap.Remove(&s.bHeap, b.index) s.heapUpdated = true }: case <-p.done: } } func (p *Progress) traverseBars(cb func(b *Bar) bool) { done := make(chan struct{}) select { case p.operateState <- func(s *pState) { for i := 0; i < s.bHeap.Len(); i++ { bar := s.bHeap[i] if !cb(bar) { break } } close(done) }: <-done case <-p.done: } } // UpdateBarPriority same as *Bar.SetPriority(int). func (p *Progress) UpdateBarPriority(b *Bar, priority int) { select { case p.operateState <- func(s *pState) { if b.index < 0 { return } b.priority = priority heap.Fix(&s.bHeap, b.index) }: case <-p.done: } } // BarCount returns bars count. func (p *Progress) BarCount() int { result := make(chan int) select { case p.operateState <- func(s *pState) { result <- s.bHeap.Len() }: return <-result case <-p.done: return 0 } } // Wait waits for all bars to complete and finally shutdowns container. // After this method has been called, there is no way to reuse *Progress // instance. func (p *Progress) Wait() { if p.uwg != nil { // wait for user wg p.uwg.Wait() } // wait for bars to quit, if any p.bwg.Wait() p.once.Do(p.shutdown) // wait for container to quit p.cwg.Wait() } func (p *Progress) shutdown() { close(p.done) } func (p *Progress) serve(s *pState, cw *cwriter.Writer) { defer p.cwg.Done() p.refreshCh = s.newTicker(p.done) for { select { case op := <-p.operateState: op(s) case <-p.refreshCh: if err := s.render(cw); err != nil { if s.debugOut != nil { _, e := fmt.Fprintln(s.debugOut, err) if e != nil { panic(err) } } else { panic(err) } } case <-s.shutdownNotifier: for s.heapUpdated { if err := s.render(cw); err != nil { if s.debugOut != nil { _, e := fmt.Fprintln(s.debugOut, err) if e != nil { panic(err) } } else { panic(err) } } } return } } } func (s *pState) newTicker(done <-chan struct{}) chan time.Time { ch := make(chan time.Time) if s.shutdownNotifier == nil { s.shutdownNotifier = make(chan struct{}) } go func() { if s.renderDelay != nil { <-s.renderDelay } var internalRefresh <-chan time.Time if !s.outputDiscarded { if s.externalRefresh == nil { ticker := time.NewTicker(s.rr) defer ticker.Stop() internalRefresh = ticker.C } } else { s.externalRefresh = nil } for { select { case t := <-internalRefresh: ch <- t case x := <-s.externalRefresh: if t, ok := x.(time.Time); ok { ch <- t } else { ch <- time.Now() } case <-done: close(s.shutdownNotifier) return } } }() return ch } func (s *pState) render(cw *cwriter.Writer) error { if s.heapUpdated { s.updateSyncMatrix() s.heapUpdated = false } syncWidth(s.pMatrix) syncWidth(s.aMatrix) tw, err := cw.GetWidth() if err != nil { tw = s.reqWidth } for i := 0; i < s.bHeap.Len(); i++ { bar := s.bHeap[i] go bar.render(tw) } return s.flush(cw) } func (s *pState) flush(cw *cwriter.Writer) error { var totalLines int bm := make(map[*Bar]int, s.bHeap.Len()) for s.bHeap.Len() > 0 { b := heap.Pop(&s.bHeap).(*Bar) frame := <-b.frameCh _, err := cw.ReadFrom(frame.reader) if err != nil { return err } if b.toShutdown { if b.recoveredPanic != nil { s.barShutdownQueue = append(s.barShutdownQueue, b) b.toShutdown = false } else { // shutdown at next flush // this ensures no bar ends up with less than 100% rendered defer func() { s.barShutdownQueue = append(s.barShutdownQueue, b) }() } } bm[b] = frame.lines totalLines += frame.lines } for _, b := range s.barShutdownQueue { if parkedBar := s.parkedBars[b]; parkedBar != nil { parkedBar.priority = b.priority heap.Push(&s.bHeap, parkedBar) delete(s.parkedBars, b) b.toDrop = true } if s.popCompleted && !b.noPop { totalLines -= bm[b] b.toDrop = true } if b.toDrop { delete(bm, b) s.heapUpdated = true } b.cancel() } s.barShutdownQueue = s.barShutdownQueue[0:0] for b := range bm { heap.Push(&s.bHeap, b) } return cw.Flush(totalLines) } func (s *pState) updateSyncMatrix() { s.pMatrix = make(map[int][]chan int) s.aMatrix = make(map[int][]chan int) for i := 0; i < s.bHeap.Len(); i++ { bar := s.bHeap[i] table := bar.wSyncTable() pRow, aRow := table[0], table[1] for i, ch := range pRow { s.pMatrix[i] = append(s.pMatrix[i], ch) } for i, ch := range aRow { s.aMatrix[i] = append(s.aMatrix[i], ch) } } } func (s *pState) makeBarState(total int64, filler BarFiller, options ...BarOption) *bState { bs := &bState{ id: s.idCount, priority: s.idCount, reqWidth: s.reqWidth, total: total, filler: filler, extender: func(r io.Reader, _ int, _ decor.Statistics) (io.Reader, int) { return r, 0 }, debugOut: s.debugOut, } if total > 0 { bs.triggerComplete = true } for _, opt := range options { if opt != nil { opt(bs) } } if bs.middleware != nil { bs.filler = bs.middleware(filler) bs.middleware = nil } if s.popCompleted && !bs.noPop { bs.priority = -(math.MaxInt32 - s.idCount) } for i := 0; i < len(bs.buffers); i++ { bs.buffers[i] = bytes.NewBuffer(make([]byte, 0, 512)) } return bs } func syncWidth(matrix map[int][]chan int) { for _, column := range matrix { go maxWidthDistributor(column) } } var maxWidthDistributor = func(column []chan int) { var maxWidth int for _, ch := range column { if w := <-ch; w > maxWidth { maxWidth = w } } for _, ch := range column { ch <- maxWidth } } mpb-7.3.2/progress_test.go000066400000000000000000000075231417272200500155420ustar00rootroot00000000000000package mpb_test import ( "bytes" "context" "io/ioutil" "math/rand" "sync" "testing" "time" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" ) func init() { rand.Seed(time.Now().UnixNano()) } func TestBarCount(t *testing.T) { p := mpb.New(mpb.WithOutput(ioutil.Discard)) var wg sync.WaitGroup wg.Add(1) b := p.AddBar(100) go func() { rng := rand.New(rand.NewSource(time.Now().UnixNano())) for i := 0; i < 100; i++ { if i == 33 { wg.Done() } b.Increment() time.Sleep((time.Duration(rng.Intn(10)+1) * (10 * time.Millisecond)) / 2) } }() wg.Wait() count := p.BarCount() if count != 1 { t.Errorf("BarCount want: %q, got: %q\n", 1, count) } b.Abort(true) p.Wait() } func TestBarAbort(t *testing.T) { p := mpb.New(mpb.WithOutput(ioutil.Discard)) var wg sync.WaitGroup wg.Add(1) bars := make([]*mpb.Bar, 3) for i := 0; i < 3; i++ { b := p.AddBar(100) rng := rand.New(rand.NewSource(time.Now().UnixNano())) go func(n int) { for i := 0; !b.Completed(); i++ { if n == 0 && i >= 33 { b.Abort(true) wg.Done() } b.Increment() time.Sleep((time.Duration(rng.Intn(10)+1) * (10 * time.Millisecond)) / 2) } }(i) bars[i] = b } wg.Wait() count := p.BarCount() if count != 2 { t.Errorf("BarCount want: %d, got: %d\n", 2, count) } bars[1].Abort(true) bars[2].Abort(true) p.Wait() } func TestWithContext(t *testing.T) { shutdown := make(chan struct{}) ctx, cancel := context.WithCancel(context.Background()) p := mpb.NewWithContext(ctx, mpb.WithShutdownNotifier(shutdown), mpb.WithOutput(ioutil.Discard)) start := make(chan struct{}) done := make(chan struct{}) fail := make(chan struct{}) bar := p.AddBar(0) // never complete bar go func() { close(start) for !bar.Completed() { bar.Increment() time.Sleep(randomDuration(100 * time.Millisecond)) } close(done) }() go func() { select { case <-done: p.Wait() case <-time.After(150 * time.Millisecond): close(fail) } }() <-start cancel() select { case <-shutdown: case <-fail: t.Error("Progress didn't shutdown") } } // MaxWidthDistributor shouldn't stuck in the middle while removing or aborting a bar func TestMaxWidthDistributor(t *testing.T) { makeWrapper := func(f func([]chan int), start, end chan struct{}) func([]chan int) { return func(column []chan int) { start <- struct{}{} f(column) <-end } } ready := make(chan struct{}) start := make(chan struct{}) end := make(chan struct{}) *mpb.MaxWidthDistributor = makeWrapper(*mpb.MaxWidthDistributor, start, end) total := 80 numBars := 6 p := mpb.New(mpb.WithOutput(ioutil.Discard)) for i := 0; i < numBars; i++ { bar := p.AddBar(int64(total), mpb.BarOptional(mpb.BarRemoveOnComplete(), i == 0), mpb.PrependDecorators( decor.EwmaETA(decor.ET_STYLE_GO, 60, decor.WCSyncSpace), ), ) go func() { <-ready rng := rand.New(rand.NewSource(time.Now().UnixNano())) for i := 0; i < total; i++ { start := time.Now() if id := bar.ID(); id > 1 && i >= 42 { if id&1 == 1 { bar.Abort(true) } else { bar.Abort(false) } } time.Sleep((time.Duration(rng.Intn(10)+1) * (50 * time.Millisecond)) / 2) bar.IncrInt64(rand.Int63n(5) + 1) bar.DecoratorEwmaUpdate(time.Since(start)) } }() } go func() { <-ready p.Wait() close(start) }() res := t.Run("maxWidthDistributor", func(t *testing.T) { close(ready) for v := range start { timer := time.NewTimer(100 * time.Millisecond) select { case end <- v: timer.Stop() case <-timer.C: t.FailNow() } } }) if !res { t.Error("maxWidthDistributor stuck in the middle") } } func getLastLine(bb []byte) []byte { split := bytes.Split(bb, []byte("\n")) return split[len(split)-2] } func randomDuration(max time.Duration) time.Duration { return time.Duration(rand.Intn(10)+1) * max / 10 } mpb-7.3.2/proxyreader.go000066400000000000000000000027511417272200500152010ustar00rootroot00000000000000package mpb import ( "io" "io/ioutil" "time" ) type proxyReader struct { io.ReadCloser bar *Bar } func (x proxyReader) Read(p []byte) (int, error) { n, err := x.ReadCloser.Read(p) x.bar.IncrBy(n) if err == io.EOF { go x.bar.SetTotal(-1, true) } return n, err } type proxyWriterTo struct { proxyReader wt io.WriterTo } func (x proxyWriterTo) WriteTo(w io.Writer) (int64, error) { n, err := x.wt.WriteTo(w) x.bar.IncrInt64(n) if err == io.EOF { go x.bar.SetTotal(-1, true) } return n, err } type ewmaProxyReader struct { proxyReader } func (x ewmaProxyReader) Read(p []byte) (int, error) { start := time.Now() n, err := x.proxyReader.Read(p) if n > 0 { x.bar.DecoratorEwmaUpdate(time.Since(start)) } return n, err } type ewmaProxyWriterTo struct { ewmaProxyReader wt proxyWriterTo } func (x ewmaProxyWriterTo) WriteTo(w io.Writer) (int64, error) { start := time.Now() n, err := x.wt.WriteTo(w) if n > 0 { x.bar.DecoratorEwmaUpdate(time.Since(start)) } return n, err } func (b *Bar) newProxyReader(r io.Reader) (rc io.ReadCloser) { pr := proxyReader{toReadCloser(r), b} if wt, ok := r.(io.WriterTo); ok { pw := proxyWriterTo{pr, wt} if b.hasEwmaDecorators { rc = ewmaProxyWriterTo{ewmaProxyReader{pr}, pw} } else { rc = pw } } else if b.hasEwmaDecorators { rc = ewmaProxyReader{pr} } else { rc = pr } return rc } func toReadCloser(r io.Reader) io.ReadCloser { if rc, ok := r.(io.ReadCloser); ok { return rc } return ioutil.NopCloser(r) } mpb-7.3.2/proxyreader_test.go000066400000000000000000000037701417272200500162420ustar00rootroot00000000000000package mpb_test import ( "bytes" "io" "io/ioutil" "strings" "testing" "github.com/vbauerster/mpb/v7" ) const content = `Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.` type testReader struct { io.Reader called bool } func (r *testReader) Read(p []byte) (n int, err error) { r.called = true return r.Reader.Read(p) } func TestProxyReader(t *testing.T) { p := mpb.New(mpb.WithOutput(ioutil.Discard)) tReader := &testReader{strings.NewReader(content), false} bar := p.AddBar(int64(len(content)), mpb.BarFillerTrim()) var buf bytes.Buffer _, err := io.Copy(&buf, bar.ProxyReader(tReader)) if err != nil { t.Errorf("Error copying from reader: %+v\n", err) } p.Wait() if !tReader.called { t.Error("Read not called") } if got := buf.String(); got != content { t.Errorf("Expected content: %s, got: %s\n", content, got) } } type testWriterTo struct { io.Reader wt io.WriterTo called bool } func (wt *testWriterTo) WriteTo(w io.Writer) (n int64, err error) { wt.called = true return wt.wt.WriteTo(w) } func TestProxyWriterTo(t *testing.T) { p := mpb.New(mpb.WithOutput(ioutil.Discard)) var reader io.Reader = strings.NewReader(content) tReader := &testWriterTo{reader, reader.(io.WriterTo), false} bar := p.AddBar(int64(len(content)), mpb.BarFillerTrim()) var buf bytes.Buffer _, err := io.Copy(&buf, bar.ProxyReader(tReader)) if err != nil { t.Errorf("Error copying from reader: %+v\n", err) } p.Wait() if !tReader.called { t.Error("WriteTo not called") } if got := buf.String(); got != content { t.Errorf("Expected content: %s, got: %s\n", content, got) } }