Git Product home page Git Product logo

mpb's Introduction

Multi Progress Bar

GoDoc Test status Lint status

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 based ETA, Percentage, Bytes counter
  • Decorator's width sync: Synchronized decorator's width among multiple bars

Usage

package main

import (
    "math/rand"
    "time"

    "github.com/vbauerster/mpb/v8"
    "github.com/vbauerster/mpb/v8/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{C: decor.DindentRight | decor.DextraSpace}),
            // replace ETA decorator with "done" message, OnComplete event
            decor.OnComplete(decor.AverageETA(decor.ET_STYLE_GO), "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()
}
    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 30
                    decor.EwmaETA(decor.ET_STYLE_GO, 30, 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)
                // we need to call EwmaIncrement to fulfill ewma decorator's contract
                bar.EwmaIncrement(time.Since(start))
            }
        }()
    }
    // wait for passed wg and for all bars to complete and flush
    p.Wait()

dynamic total

complex

byte counters

mpb's People

Contributors

alevinval avatar asellappen avatar fd0 avatar lanwen avatar mogigoma avatar najohnsn avatar samlturner avatar vbauerster avatar xakep666 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mpb's Issues

Clear spinner on complete

Is there a way to clear the spinner after complete? Like the one for bar using mpb.BarClearOnComplete()

How do I vendor this library?

Hi,

first off, thanks for this great library. I am quite excited about it!

I am working on porting our tools to use it (see containers/image#581) but I am currently stuck with the below issue.

We need to vendor the code and use github.com/LK4D4/vndr for managing the dependencies. So far I tried vendoring github.com/vbauerster/mpb directly and also doing dance with gopkg.in/vbauerster/mpb.v4/ as shown in the error below. None of it succeeded.

Can you shed some light on my issue?

vendor/gopkg.in/vbauerster/mpb.v4/progress.go:13:2: cannot find package "github.com/vbauerster/mpb/v4/cwriter" in any of:  
        /home/valentin/go/src/github.com/containers/skopeo/vendor/github.com/vbauerster/mpb/v4/cwriter (vendor tree)       
        /usr/lib/golang/src/github.com/vbauerster/mpb/v4/cwriter (from $GOROOT)
        /home/valentin/go/src/github.com/vbauerster/mpb/v4/cwriter (from $GOPATH)
vendor/gopkg.in/vbauerster/mpb.v4/bar.go:14:2: cannot find package "github.com/vbauerster/mpb/v4/decor" in any of:         
        /home/valentin/go/src/github.com/containers/skopeo/vendor/github.com/vbauerster/mpb/v4/decor (vendor tree)         
        /usr/lib/golang/src/github.com/vbauerster/mpb/v4/decor (from $GOROOT)
        /home/valentin/go/src/github.com/vbauerster/mpb/v4/decor (from $GOPATH)
vendor/gopkg.in/vbauerster/mpb.v4/bar_filler.go:9:2: cannot find package "github.com/vbauerster/mpb/v4/internal" in any of:
        /home/valentin/go/src/github.com/containers/skopeo/vendor/github.com/vbauerster/mpb/v4/internal (vendor tree)      
        /usr/lib/golang/src/github.com/vbauerster/mpb/v4/internal (from $GOROOT)
        /home/valentin/go/src/github.com/vbauerster/mpb/v4/internal (from $GOPATH)

non-complete bar says 100%

Task 47 : 1881 / 1885 [================================]  100 %:    00:06:

This is in reference to the 1881 / 1885 which is calculated with using
decor.CountersNoUnit("%d / %d", decor.WCSyncWidth),

injecting custom fillBar

Hi,

We are using mpb and would like have some spinners rather than progress bars. Do you see an easy way to inject a strategy for a custom s.fillBar(width) ?

Bars get duplicated when terminal shows less lines than number of bars

Hi,
Thanks for your library and all your work!

Im running mpb v4.6.0 on macOS.
I tried running the stress example and it seems that when the number of lines displayed in the terminal (a matter of font & window size) is lower than the number of bars, the first bars get duplicated.

For example, when running the example with the default 32 bars, while terminal displays less than 30 lines:
last lines printed:
image
first lines printed:
image

Please correct me if I'm doing something wrong, or it is a known limitation I'm unaware of.
Thanks!

Need a light on this, please.

Hello,
OBS. I am extremely new with Golang.

I'm looking for a solution to an idea, I want to improve the output of this program:
https://github.com/dgraph-io/dgraph/tree/master/dgraph/cmd/live

I seek for bars like mpb (sounds like brasilian music LOL) but that it can generate a clean output. All projects with bars generate many lines (per second). I'm using | & tee -a bartest.txt to test.

go run main.go |& tee -a bartest.txt

I wonder if it would be possible to combine the best of both worlds. Bar + a clean output.

The program also issues errors while continuing the process. It would be interesting to display the errors while the progress bar maintains its rhythm. And the output also collects the errors.

At the end of the process if is either fatal error, cancellation, SIGTERM or something else. The program still generates a clean output of what happened.

All this Would it be possible?

This would be an example of the current output


2018/07/29 22:31:59 run.go:337: Creating temp client directory at /var/folders/vb/l72zg91129q5wyqygw59cr2h0000gn/T/x236306353
Processing 21million.schema
2018/07/29 22:32:00 run.go:354: Processed schema file
Processing 1million.rdf.gz
Total Txns done:        0 RDFs per second:       0 Time Elapsed: 2s, Aborts: 0
Total Txns done:        0 RDFs per second:       0 Time Elapsed: 4s, Aborts: 0
Total Txns done:        0 RDFs per second:       0 Time Elapsed: 6s, Aborts: 0
Total Txns done:        0 RDFs per second:       0 Time Elapsed: 8s, Aborts: 0
Total Txns done:      323 RDFs per second:    1564 Time Elapsed: 3m26s, Aborts: 0
2018/07/29 22:35:27 batch.go:125: Error while mutating Predicate is being moved, please retry later
Total Txns done:      327 RDFs per second:    1568 Time Elapsed: 3m28s, Aborts: 1
2018/07/29 22:35:28 batch.go:125: Error while mutating Predicate is being moved, please retry later
2018/07/29 22:35:28 batch.go:125: Error while mutating Predicate is being moved, please retry later
2018/07/29 22:35:28 batch.go:125: Error while mutating Predicate is being moved, please retry later

It displays transactions, time and possible aborts.

Request: Performance improvements

When 4 bars where updated with nearly 8 goroutines each, cpu usage have raised from 20% to 75%,.

After removing progress bar, same computation took less than 25% cpu usage.

Questions: Bar extension, Logging

Hi again! 🙂
A few questions if I may:

  1. Is there an option to extend the bar such that the progress bar is printed on the 2nd line, while a static string on the first?
    I have tried:
  • Passing a decor.Name("name\n"), but that gets the first line duplicated.
  • Using p.Add() with a filler that prints a string as the 2nd argument, and a
    mpb.BarExtender() with a bar as filler as a BarOption. Both lines are duplicated.
  1. We would like to print logs to the same out while bars are running. Since these logs interfere with the bars, we thought about printing them as completed bars.
    Is adding a completed bar even possible, or do we have to increment once? Do you happen to have a better suggestion to doing so (not as a decorator to an existing bar, as the logs are not related to a specific bar)?

Thanks a lot in advance!

[Windows] Single bar duplicates when exactly terminal width

Running the IO example given here https://github.com/vbauerster/mpb/blob/master/_examples/io/main.go with some modifications to prepend a long name, I have reproduced an issue I'm having where bars get duplicated once they reach the edge of the terminal window.

image

Actual code
package main

import (
	"crypto/rand"
	"io"
	"io/ioutil"
	"time"

	"github.com/vbauerster/mpb/v5"
	"github.com/vbauerster/mpb/v5/decor"
)

func main() {
	var total int64 = 1024 * 1024 * 1024
	reader := io.LimitReader(rand.Reader, total)

	p := mpb.New(
		mpb.WithWidth(60),
		mpb.WithRefreshRate(180*time.Millisecond),
	)

	bar := p.AddBar(total, mpb.BarStyle("[=>-|"),
		mpb.PrependDecorators(
			decor.Name("This is a really long name. I'm sorry it's so long but that's just the way it goes sometimes. "),
			decor.CountersKibiByte("% .2f / % .2f"),
			decor.Percentage(decor.WCSyncSpace),
		),
		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()
}

The bar is clearly flexing to fill available space, but is still one character too long, it seems. Shorter names do not produce this issue.

OS: Windows 10

Add a non zero init value for bars

A non zero init value will be really helpful, As it would make the average speed and eta more accurate for resume able task. Hope I can convey my thoughts clearly.

Can I stop bar completing while total still being calculated

Hello,
Is it possible to prevent a bar from completing until the final total is set?

My problem is the code to determine size is slower than the code to process items so the bar completes before I have a chance to set the final total.

In the interim I have worked around by artificially adding an extra item to the total at the start and then subtracting this at the end.

Cheers
Seth

nil dereference crash on Bar.SetTotal

I'm honestly not sure how it's crashing here..

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x4d07c7]

goroutine 1 [running]:
github.com/vbauerster/mpb.(*Bar).SetTotal(0x0, 0x19cb8, 0x4aa600)
        /home/meghan/go/src/github.com/vbauerster/mpb/bar.go:214 +0x37```

wishlist: mix line-based output with progress bar status

I haven't seen an obvious way to do this with mpb, but I'd love to be able to print line-based output ("Downloaded file a\nDownloaded file b\n" etc) while also having a progress bar.

Ideally this would be presented as an io.Writer so I can plug it into existing code that is expecting to just write non-atomically directly to stdout.

Replace internal github imports with gopkg.in

Currently, mpb's implementation imports from github. Thus if you exec go get gopkg.in/vbauerster/mpb.v3 you actually fetch the project twice. Besides, the second copy from github is not synced with v3 release, and the project may become unusable.

Another side effect is that if you import mpb like that:

import (
  "gopkg.in/vbauerster/mpb.v3"
  "gopkg.in/vbauerster/mpb.v3/decor"
)

The build fails because "gopkg.in/vbauerster/mpb.v3" imports "github.com/vbauerster/mpb/decor" and the types from decor do not match:

cannot use "gopkg.in/vbauerster/mpb.v3/decor".DynamicName(func literal, 10, 0) (type "gopkg.in/vbauerster/mpb.v3/decor".DecoratorFunc) as type "github.com/vbauerster/mpb/decor".DecoratorFunc in argument to mpb.PrependDecorators

So to actually build the examples, we need

import (
  "gopkg.in/vbauerster/mpb.v3"
  "github.com/vbauerster/mpb/decor"
)

which does not make any sense to me. So I propose to rediect the internal imports to gopkg.in, as the rest of the folks do.

Old progressbars are removed too late

Take the following sample code:

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strconv"

	"github.com/vbauerster/mpb"
	"github.com/vbauerster/mpb/decor"
)

func main() {
	workers := 3
	tiny := "https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"
	urls := []string{tiny, tiny, tiny, tiny, tiny, tiny, "http://ipv4.download.thinkbroadband.com/512MB.zip"}

	jobs := make(chan string, len(urls))
	done := make(chan bool, workers)

	p := mpb.New(mpb.WithWidth(64))

	for w := 1; w <= workers; w++ {
		go func(jobs <-chan string) {
			for entry := range jobs {
				download(entry, p)
			}
			done <- true
		}(jobs)
	}

	for _, url := range urls {
		jobs <- url
	}
	close(jobs)

	for w := 1; w <= workers; w++ {
		<-done
	}

	p.Wait()

	fmt.Println("done")
}

func download(url string, p *mpb.Progress) {
	resp, err := http.Head(url)
	if err != nil {
		panic(err)
	}

	size, _ := strconv.Atoi(resp.Header.Get("Content-Length"))

	resp, err = http.Get(url)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		fmt.Printf("Server return non-200 status: %s\n", resp.Status)
		return
	}

	// create dest
	destName := filepath.Base(url)
	dest, err := os.Create(destName)
	if err != nil {
		fmt.Printf("Can't create %s: %v\n", destName, err)
		return
	}
	defer dest.Close()

	bar := p.AddBar(int64(size),
		mpb.BarRemoveOnComplete(),
		mpb.PrependDecorators(
			decor.CountersKibiByte("% 6.1f / % 6.1f", 18, 0)),
		mpb.AppendDecorators(decor.ETA(0, decor.DwidthSync)))

	// create proxy reader
	reader := bar.ProxyReader(resp.Body)

	// and copy from reader, ignoring errors
	io.Copy(dest, reader)
}

Note that this is using 3 channel workers, so only 3 downloads occur at a time. A new worker (and thus progressbar) isnt created until an old one has completed.

When you run the code you briefly see all progressbars spawned and then see the expired ones disappear soon after. It seems it is prioritising creating new progressbars over destroying old ones, making it so your screen gets filled with stale progressbars and creating a glitchy user experience.

Removal is not thread safe

Take the following example code:

package main

/* This example creates three bars: b1, b2, and b3.
 * b1 is created in the main thread but runs in a separate thread.
 * b2 is created in b1's thread, but runs in its own thread.
 * b3 is created and run in its own thread.
 * b1 and b3 appear immediately, but b2 comes later.
 * b2 is the fastest and should complete and be removed first.
 * b1 is second fastest and should complete and be removed second.
 * b3 is the slowest and should complete last.
 */

import (
        "time"

        "github.com/vbauerster/mpb"
        "github.com/vbauerster/mpb/decor"
)

const sleep = 100 * time.Millisecond

func main() {
        p := mpb.New()

        b1 := p.AddBar(int64(100), mpb.PrependDecorators(decor.StaticName("bar1", 0, 0)))
        // Run thread for b1.
        go func() {
                defer p.RemoveBar(b1)

                // Create and run thread for b2, which starts after a time.
                go func() {
                        time.Sleep(10 * sleep)
                        b2 := p.AddBar(int64(100), mpb.PrependDecorators(decor.StaticName("bar2", 0, 0)))
                        defer p.RemoveBar(b2)
                        for j := 0; !b2.Completed(); j++ {
                                b2.IncrBy(10) // fastest
                                time.Sleep(sleep)
                        }
                }()

                for i := 0; !b1.Completed(); i++ {
                        b1.IncrBy(2) // second fastest
                        time.Sleep(sleep)
                }
        }()

        // Create and run thread for b3, which starts immediately.
        go func() {
                b3 := p.AddBar(int64(100), mpb.PrependDecorators(decor.StaticName("bar3", 0, 0)))
                defer p.RemoveBar(b3)
                for k := 0; !b3.Completed(); k++ {
                        b3.IncrBy(1) // slowest
                        time.Sleep(sleep)
                }
        }()

        p.Wait()
}

None of the bars will end up being removed.

Be able to update decorator text

Right now there is no way to update the bar title or any decorator text, only change their configs.

Additionally, decor.CBFunc takes no index, so you have no idea which decorating with Bar.TraverseDecorators.

GoDoc comment for func EwmaSpeed is incorrect

The method signature has age but the comment has average function

func EwmaSpeed
func EwmaSpeed(unit int, unitFormat string, age float64, wcc ...WC) Decorator

`unit` one of [0|UnitKiB|UnitKB] zero for no unit

`unitFormat` printf compatible verb for value, like "%f" or "%d"

`average` MovingAverage implementation

`wcc` optional WC config

decor.ETA is extremely inaccurate

Use the following sample code:

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"sync"

	"github.com/vbauerster/mpb"
	"github.com/vbauerster/mpb/decor"
)

func main() {
	var wg sync.WaitGroup
	wg.Add(3)
	p := mpb.New(mpb.WithWaitGroup(&wg), mpb.WithWidth(64))
	go download(p, &wg)
	go download(p, &wg)
	go download(p, &wg)

	wg.Wait()
	p.Wait() // if you omit this line, rendering bars goroutine will quit early
	fmt.Println("done")
}

func download(p *mpb.Progress, wg *sync.WaitGroup) {
	defer wg.Done()

	url := "http://ipv4.download.thinkbroadband.com/512MB.zip"

	resp, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		fmt.Printf("Server return non-200 status: %s\n", resp.Status)
		return
	}

	size := resp.ContentLength

	// create dest
	destName := filepath.Base(url)
	dest, err := os.Create(destName)
	if err != nil {
		fmt.Printf("Can't create %s: %v\n", destName, err)
		return
	}
	defer dest.Close()

	bar := p.AddBar(size,
		mpb.PrependDecorators(
			decor.CountersKibiByte("% 6.1f / % 6.1f", 18, 0)),
		mpb.AppendDecorators(decor.ETA(0, decor.DwidthSync)))

	// create proxy reader
	reader := bar.ProxyReader(resp.Body)

	// and copy from reader, ignoring errors
	io.Copy(dest, reader)

	fmt.Printf("Downloaded")
}

Note the ETA's on the downloads are jumping up and down all over the place, they do not settle down as time goes on. In my actual use-case they actually run down to 0 in the first 50% and then remain there, I'm not sure how to get that to reproduce though.

How to make decor.Elapsed of multi bars calculate independently?

I want to calculate the elapsed time of each progress bar, and output the time on
AppendDecorators. But the time of finished bar keep growing, even when the progress of this bar is finished. Thus, the final elapsed time is always the same.

BTW, is it possible to write a progress bar group that dropout each bar when it is finished. But keep the final completed one.

Panic with different number of columns

mpb panics when multiple bars have different number of prependers / appenders.

from progress_posix.go

b0 := s.bars[0]
if numP == -1 {
    numP = b0.NumOfPrependers()
}

This assumes all bars use the same number of prependers / appenders.
It can be fixed in a naive (slow) way that calculates the maxmium number of columns every tick:

// if(numP==-1) <-- numP can be changed if you add/remove a bar.

for _, bar := range s.bars {
    num := bar.NumOfPrependers()
    if num > numP {
        numP = num
    }
}

Empty progress bars never finish

When using the ProxyReader with empty files, progress bars never complete and end up locking up the program on exit. This also seems to happen with empty normal progress bars

Add width options that makes decorator remember width for short time

With my library that I primarily to use to make web scrapers, there are two main types of bars. those being manual value ones and download ones. and as the byte formatting makes the counter column much wider than normal as shown below.

image

image

however, as many downloads may appear and disappear but a parent bar, this width difference can cause it to be very spam-y and make that column hard to read.

therefore I was hoping it would be possible to be able to tell mpb that the width of that column should be remembered shortly (perhaps 1s) before shrinking. currently I use decor.WCSyncWidth.

Removal is very buggy to the point of being unusable

Apply the following diff:

diff --git a/examples/remove/main.go b/examples/remove/main.go
index 8abfaea..a727bc2 100644
--- a/examples/remove/main.go
+++ b/examples/remove/main.go
@@ -39,13 +39,10 @@ func main() {
                        defer wg.Done()
                        max := 200 * time.Millisecond
                        for i := 0; i < total; i++ {
-                               if b.ID() == 1 && i == 42 {
-                                       p.RemoveBar(b)
-                                       return
-                               }
-                               time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
+                               time.Sleep(time.Duration(rand.Intn(10)+1) * max / 100)
                                b.Increment()
                        }
+                       p.RemoveBar(b)
                }()
        }

Then run examples/remove/main.go repeatedly. Note sometimes some bars are removed, but in general the output is very inconsistent.

I tried debugging the r.toRemove part in the writeAndFlush function, it seems to never be called at all.

I'm not familiar enough with this code to efficiently debug it further myself. My guess is bars that are completed don't get updated anymore, hence they don't get removed.

Left time field and Speed field remain zero while running

Description

I am implementing a progress bar using your great repo, but I got stuck on the following situation. The speed field and left time field remains zero while the program is running, could you please help me to figure out where I am wrong? Thank you so much!

Sample code

package main

import (
	"time"

	"github.com/vbauerster/mpb/v5"
	"github.com/vbauerster/mpb/v5/decor"
)

func main() {
	var totalBytes int64 = 1024

	p := mpb.New(
		mpb.WithWidth(60),
		mpb.WithRefreshRate(180*time.Millisecond),
	)

	bar := p.AddBar(totalBytes, mpb.BarStyle("[=>-|"),
		mpb.PrependDecorators(
			decor.CountersKibiByte("% .2f / % .2f"),
		),
		mpb.AppendDecorators(
			decor.EwmaETA(decor.ET_STYLE_GO, 90),
			decor.Name(" ] "),
			decor.EwmaSpeed(decor.UnitKiB, "% .2f", 60),
		),
	)

	for i := 0; i < 1024; i++ {
		bar.Increment()
		time.Sleep(1 * time.Second)
	}

	p.Wait()
}

Current output after 4s running

4.00 b / 1.00 KiB [----------------------------------------------------------| 0s ] 0.00 b/s

Expected output after 4s running

4.00 b / 1.00 KiB [----------------------------------------------------------| 1020s ] 1.00 b/s

Possible content corruption

Hi,

We're investigating a weird content corruption in our S3-compatible CLI tool, which is using the minio/minio-go/v6 and mpb/v4 packages. We've opened an issue at minio-go to discuss the problem, and while performing tests we've found out that the content corruption is directly linked to the progress bar usage. Could you please have a look at this and point to us to a potential misuse of your package in our code? That'd be great to help ruling out possibilities :)

Sometimes a bar fails to clear after completing and calling `Wait`

Although I've used BarRemoveOnComplete on AddBar, I am making sure SetTotal and SetCurrent are correctly set to be completed, and I'm waiting for Wait to complete, sometimes the bar fails to be removed after completion.

Through experimentation, I've observed that waiting after Wait the same amount of time (plus some extra) as I've set with mpb.WithRefreshRate, seems to solve the issue.

This makes me think there is perhaps a race condition happening inside Wait?

Don't print bar

Hi,

we're currently using v3.3.4 as we're not (yet) using Go mod. Is there a way to create a new bar that doesn't display a progress bar?

What we're trying to achieve is first print some kind of "placeholder" bar that is later being replaced with another bar if needed. Imagine it as follows:

Bar 1: waiting for something to happen
Bar 2: performing work [=======> ]

At a later point, we want to replace Bar 1 with something similar to Bar 2.

stops at SetTotal

Hi, I'm trying to using SetTotal after progress done before to ensure the progress state.

However, it stops at SetTotal:

Here is the code:

package main

import (
	"fmt"
	"time"

	"github.com/vbauerster/mpb"
	"github.com/vbauerster/mpb/decor"
)

func main() {
	index := "index"
	p := mpb.New(mpb.WithRefreshRate(time.Second))
	bar := p.AddBar(0,
		// mpb.BarRemoveOnComplete(),
		mpb.PrependDecorators(
			// simple name decorator
			decor.Name(index),
			// 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",
			),
		),
	)
	bar.SetTotal(2, false)
	time.Sleep(2 * time.Second)
	bar.Increment()
	fmt.Printf("incr1\n")
	time.Sleep(2 * time.Second)
	bar.Increment()
	fmt.Printf("incr2\n")
	time.Sleep(2 * time.Second)
	fmt.Printf("incr3\n")
	bar.Increment()
	fmt.Printf("incr4\n")
	bar.SetTotal(2, true)
	fmt.Printf("setTotal\n")
	fmt.Printf("done\n")
}

it will never print setTotal and stop at bar.SetTotal(2, true).

"go get github.com/vbauerster/mpb" yields warning message

When I "go get" this package, I get this complaint:

package context: unrecognized import path "context" (import path does not begin with hostname)

I am guessing this must be due to progress.go and bar.go importing context while there is no context.go.

ETA is not accurate; could use help

The ETA isn't working correctly. It's initially non-zero, but drops to zero and stays there for most of the duration. I have a wrapper around theio.Reader that iteratively provides counts and durations. The durations are in the microsecond range.

The documentation for the timing arguments is very terse and, simple person that I am, the examples don't expand the understanding in any way that'd help to debug. I'd appreciate some assistance.

Implementation (based on the example):

progress := mpb.New()

bar := progress.AddBar(
    fi.Size(),

    mpb.PrependDecorators(
        // display our name with one space on the right
        decor.Name(
            currentFilepath,
            decor.WC{W: len(currentFilepath) + 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()),
)

progressCb = func(n int, duration time.Duration, isEof bool) error {
    bar.IncrBy(n, duration)
    return nil
}

I'm trying to understand how the ETA is supposed to work, but it's not clear, at least to me, from the documentation.

Output:

$ time go run cmd/gozp/main.go -f /tmp/big.gzp file.mp4
file.mp4   0s [==============================================>-------------------------------] 60 %
^Csignal: interrupt

real	0m12.364s
user	0m12.862s
sys	0m0.356s

This has at least another ten or twenty seconds to go at the 60% mark, but it dropped to (0) right after starting.

incrementing vs setting progress

The increment only or relative interface feels a little awkward for some use cases. Is there a particular reason not to allow for setting the absolute value of the progress?

Please add a way to remove a bar

I'm writing a downloader that shows bars as workers, a download can be hundreds of files so I want to have it reuse X number of bars. So either I need to reset a bar (feels dirty) or remove a bar when it's finished and add a new one.

Regardless of my use case, allowing for a bar to be removed seems like a basic functionality others would likely also benefit from.

How to update starting point (resumed downloads)

How do I set the starting point for use with resumed downloads?

	p := mpb.New(
		mpb.WithWidth(60),
		mpb.WithRefreshRate(180*time.Millisecond),
	)

	bar := p.AddBar(d.size, mpb.BarStyle("[=>-|"),
		mpb.PrependDecorators(
			decor.CountersKibiByte("\t% 6.1f / % 6.1f"),
		),
		mpb.AppendDecorators(
			decor.EwmaETA(decor.ET_STYLE_MMSS, float64(d.size)/2048),
			decor.Name(" ] "),
			decor.AverageSpeed(decor.UnitKiB, "% .2f"),
		),
	)

	if d.canResume {
		bar.SetCurrent(d.bytesResumed )
	}
	// create proxy reader
	reader := bar.ProxyReader(resp.Body)
	defer reader.Close()
   • resuming a previous download of: iPhone12_1_13.1.1_17A854_Restore.ipsw
	1.1 GiB /    0 b [----------------------------------------------------------| -48:-3 ] 71.44 MiB/s

See the total byte sits at 0b and the estimated time is negative??

Thank you!

Please consider an actual code license, like BSD-3-Clause, instead of Unlicense

Unlicense is a type of Public Domain attribution that has significant legal issues due to local rules about Public Domain status, and may actually make it difficult for people to use or contribute.

Looking back at the history of this project, it actually was BSD-3-Clause before, which does not have these legal issues. Frankly that's a major step back. Going to BSD-2-Clause would have been better, MIT/ISC too.

I would strongly urge you to pick a real code license and not a PD attribution-like license. MIT/BSD's are all fine, Apache-2.0 would be fine, but Unlicense and other PD attributions should be avoided.

Disclaimer: IANAL

Bar Positioning

My goroutines dynamically create/remove bars, and their order on the screen depend on the order of execution (which is random). Is it possible to give a specific order between bars?

If not, can we add something like p.AddBar(priority=int), or to prevent a frequent move, p.AddBar(absolute_row=int).

Close progress bar

how close progress bar (stop rendering) without close whole program ?

Add proxywriter

The io.Copy function has optimizations where the Reader implements io.ReadFrom.

// copyBuffer is the actual implementation of Copy and CopyBuffer.
// if buf is nil, one is allocated.
func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
	// If the reader has a WriteTo method, use it to do the copy.
	// Avoids an allocation and a copy.
	if wt, ok := src.(WriterTo); ok {
		return wt.WriteTo(dst)
	}
	// Similarly, if the writer has a ReadFrom method, use it to do the copy.
	if rt, ok := dst.(ReaderFrom); ok {
		return rt.ReadFrom(src)
	}
        ....

For example sftp.File implements io.ReadFrom. So if you attempt to download a file from sftp and wrap it with a mpb.proxyReader then io.Copy is unable to use the io.ReaderFrom optimization.

I was thinking about migrating from https://github.com/cheggaaa/pb to mpb since it has multiple progress bar support and noticed that mpb just proxies a reader. Would it be of interest to do a writer proxy as well?

Scrolling output above progress bars

Hello,
Do you have an example where I can have a scrolling output above a progress bar? I don't need it above each individual bar just above the progress.

Cheers
Seth

Callback before refreshing bars

Is there any possibility of having a call-back function being called before refreshing bars, If so how?

i.e.,

bar.BeforeRefresh(func(){})

If this is not possible, can you provide it?

Why do I need it?
I use aria2c for downloading, I'm trying to get status of from aria2c, only before refreshing, so I can save some CPU time.

Thank you.

Dynamic total value

First of all, many thanks for your work!
I have a question: How can I dynamic setting the total value of bar?

Thanks!

AppendDecorators display wrong

The following code represents my progress bar

p.AddBar(fileInfo.Size(),
			mpb.PrependDecorators(
				// simple name decorator
				decor.Name(task.string),
				// 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",
			 	),
			 ),
		)

this is the output during progress:

 an example 4 % [=>------------------------------------------------------------] 0s

then when it is done

an example 100 % [=============================================] done

Why during the progress ETA is displayed and why is doesn't working ?

if I remove this part of code:

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",
			 	),
			 ),

It's works good, but done message at the end is not displayed naturally

Add width option that allows Decorator to be cut off in its length

This issue has popped up due to the fact that the way I use mpb I don't always know the exact titles that are going to be on all the bars I use, namely URLs. This leads to a situation where the line overflows and then the erase/redraw isn't clean and repeats a bunch of lines until the bar is finished/removed.

So being able to set a particular decorator as 'able to be cropped' would be very handy.

(If you're unsure of what I'm referring to I can try and reproduce and at screenshots at a later time.)

Reset the bar

Hi. How do I reset the bar and restart after it's completed?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.