multi progress bar for Go cli applications

Multi Progress Bar

GoDoc Build Status Go Report Card

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

Rendering single bar

package main

import (
    "math/rand"
    "time"

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

func main() {
    // initialize progress container, with custom width
    p := mpb.New(mpb.WithWidth(64))

    total := 100
    name := "Single Bar:"
    // adding a single bar, which will inherit container's width
    bar := p.Add(int64(total),
        // progress bar filler with customized style
        mpb.NewBarFiller("╢▌▌░╟"),
        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

    var wg sync.WaitGroup
    // pass &wg (optional), so p will wait for it eventually
    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), "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))
            }
        }()
    }
    // Waiting for passed &wg and for all bars to complete and flush
    p.Wait()

Dynamic total

dynamic total

Complex example

complex

Bytes counters

byte counters

Owner
Comments
  • Empty progress bars never finish

    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

  • AppendDecorators display wrong

    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

  • progress: always force a render on shutdown

    progress: always force a render on shutdown

    fix a race issue where a cancelled context might cause the progress bar to never be rendered.

    More details here: https://github.com/containers/image/issues/1013

    Signed-off-by: Giuseppe Scrivano [email protected]

  • runtime error: makeslice: len out of range

    runtime error: makeslice: len out of range

    We launched a developer tool using this lib last week, 2 users reported the error below, but it works for most of us. We are distributing a compiled binary through homebrew, so we can be sure everyone is running the same go binary.

    One of them is using iTerm2 3.3.6, I tested against the same version, but works fine for me

    Our implementation looks very similar to one in https://github.com/vbauerster/mpb/blob/master/_examples/complex/main.go

    runtime error: makeslice: len out of range
    decor.Statistics{ID:0, AvailableWidth:144, Total:215, Current:-21, Refill:0, Completed:false}
    goroutine 59 [running]:
    runtime/debug.Stack(0xc0006897b0, 0x1, 0x1)
    /home/kochiku/.cache/pants/bin/go/linux/x86_64/1.14.3/go/go/src/runtime/debug/stack.go:24 +0x9d
    github.com/vbauerster/mpb.makePanicExtender(0x16fb340, 0x18d7870, 0x18d7870)
    /home/kochiku/data/.pants.d/binary/golang/src/github.com/vbauerster/mpb/bar.go:468 +0x8a
    github.com/vbauerster/mpb.(*Bar).render.func1.1(0xc0002130e0, 0x0, 0x90, 0xd7, 0xffffffffffffffeb, 0x0, 0x0, 0xc00010a800)
    /home/kochiku/data/.pants.d/binary/golang/src/github.com/vbauerster/mpb/bar.go:308 +0x86
    panic(0x16fb340, 0x18d7870)
    /home/kochiku/.cache/pants/bin/go/linux/x86_64/1.14.3/go/go/src/runtime/panic.go:969 +0x166
    github.com/vbauerster/mpb.(*barFiller).Fill(0xc000237c80, 0x18e5b00, 0xc0004fbef0, 0x40, 0x0, 0x6e, 0xd7, 0xffffffffffffffeb, 0x0, 0x0)
    /home/kochiku/data/.pants.d/binary/golang/src/github.com/vbauerster/mpb/bar_filler_bar.go:117 +0x228
    github.com/vbauerster/mpb.BarFillerOnComplete.func1.1(0x18e5b00, 0xc0004fbef0, 0x40, 0x0, 0x6e, 0xd7, 0xffffffffffffffeb, 0x0, 0x0)
    /home/kochiku/data/.pants.d/binary/golang/src/github.com/vbauerster/mpb/bar_option.go:85 +0xb3
    github.com/vbauerster/mpb.BarFillerFunc.Fill(0xc0004fbe90, 0x18e5b00, 0xc0004fbef0, 0x40, 0x0, 0x6e, 0xd7, 0xffffffffffffffeb, 0x0, 0x0)
    /home/kochiku/data/.pants.d/binary/golang/src/github.com/vbauerster/mpb/bar_filler.go:29 +0x68
    github.com/vbauerster/mpb.(*bState).draw(0xc0002130e0, 0x0, 0x6e, 0xd7, 0xffffffffffffffeb, 0x0, 0x0, 0x0, 0x0)
    /home/kochiku/data/.pants.d/binary/golang/src/github.com/vbauerster/mpb/bar.go:410 +0x6cc
    github.com/vbauerster/mpb.(*Bar).render.func1(0xc0002130e0)
    /home/kochiku/data/.pants.d/binary/golang/src/github.com/vbauerster/mpb/bar.go:318 +0x1be
    github.com/vbauerster/mpb.(*Bar).serve(0xc00010a800, 0x18f7d60, 0xc0000b9ec0, 0xc0002130e0)
    /home/kochiku/data/.pants.d/binary/golang/src/github.com/vbauerster/mpb/bar.go:288 +0x83
    created by github.com/vbauerster/mpb.newBar
    /home/kochiku/data/.pants.d/binary/golang/src/github.com/vbauerster/mpb/bar.go:96 +0x371
    
  • Add width option that allows Decorator to be cut off in its length

    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.)

  • Don't print bar

    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.

  • The log will be overwritten while the progress bar is printed

    The log will be overwritten while the progress bar is printed

    The log will be overwritten while the progress bar is printed. How to set not to overwrite the log, but to move the progress bar down one line?

    package main
    
    import (
    	"time"
    
    	"github.com/sirupsen/logrus"
    
    	"github.com/vbauerster/mpb/v7"
    	"github.com/vbauerster/mpb/v7/decor"
    )
    
    var logger *logrus.Logger
    
    func main() {
    	logger = logrus.New()
    	total := 10000
    	p := mpb.New(mpb.WithWidth(64), mpb.WithOutput(logger.Writer()))
    	b := p.AddBar(0, // disable triggerComplete
    		mpb.PrependDecorators(
    			decor.Name("test count: ", decor.WCSyncWidth),
    			decor.CountersNoUnit("%d / %d"),
    		),
    		mpb.AppendDecorators(
    			decor.OnComplete(decor.Percentage(decor.WC{W: 5}), "done"),
    			decor.OnComplete(
    				decor.AverageETA(decor.ET_STYLE_GO, decor.WC{W: 6}), "",
    			),
    		),
    	)
    	b.SetTotal(int64(total), false)
    
    	for {
    		logger.Infof(time.Now().String())
    		time.Sleep(1 * time.Second)
    		b.Increment()
    	}
    	b.SetTotal(0, true)
    }
    
    
  • Possible content corruption

    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 :)

  • Removal is not thread safe

    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.

  • Support for complex filler 'runes'?

    Support for complex filler 'runes'?

    Suggestion: Allowing Fillers to have assignable strings instead of runes. This would allow users to insert colour codes, complex shapes, and more.

    Instead of having:

    mpb.NewBarFiller("[=> |"),
    

    we could do something like this:

    mpb.NewBarFiller("[", "=", ">", "|"),
    
  • bar: add WithSpinner option

    bar: add WithSpinner option

    #29 ~ mpb is great for showing many tasks at once, but sometimes those tasks are unknown. For the time being we are faking the loading with a fake ETA.

    https://asciinema.org/a/1VbZgh5uuY2thL1AWkddBpfPi

  • Any option to print logs below progress bar, without progress bar getting duplicated?

    Any option to print logs below progress bar, without progress bar getting duplicated?

    Currently my single progress bar gets duplicated, if any log output is printed in any of the calling functions.

    Bar 1 ∙∙∙ [############################################..................] 71 %
    Log output 1
    Bar 1    [##############################################################] 100 %
    Log output 2
    

    Is there a way to print any associated logs like this, for a single progress bar?

    Bar 1    [##############################################################] 100 %
    Log output 1
    Log output 2
    
  • Add support for ReadSeeker for uploads to s3

    Add support for ReadSeeker for uploads to s3

    Unfortunately s3 sdk uses ReadSeeker for uploads. So in this case it is tricky to wrap a file that you trying to upload: curremt API only allows ReadCloser but not ReadSeeker.

progress_bar creates a single customizable progress bar for Linux terminal.
progress_bar creates a single customizable progress bar for Linux terminal.

progress_bar Go Progress Bar Features progress_bar creates a single customizable progress bar for Linux terminal. Installation go get -u github.com/er

Aug 12, 2022
Console progress bar for Golang

Terminal progress bar for Go Installation go get github.com/cheggaaa/pb/v3 Documentation for v1 bar available here Quick start package main import (

Jan 9, 2023
Go simple progress bar writing to output
Go simple progress bar writing to output

?? progress-go Go simple progress bar writing to output ?? ABOUT Contributors: Rafał Lorenz Want to contribute ? Feel free to send pull requests! Have

Oct 30, 2022
A cli that shows a GitHub-like language usage statistics bar.
A cli that shows a GitHub-like language usage statistics bar.

barley A cli that shows a GitHub-like language usage statistics bar. barley analyses the programming languages used in a directory and creates a used

Jan 8, 2022
🍫 A customisable, universally compatible terminal status bar
🍫 A customisable, universally compatible terminal status bar

Shox: Terminal Status Bar A customisable terminal status bar with universal shell/terminal compatibility. Currently works on Mac/Linux. Installation N

Dec 27, 2022
Custom i3status bar built with Barista.

Custom i3status Customized i3status command built with Barista. Includes a Barista module for strongSwan. Install go install enr0n.net/i3status/cmd/i3

Jan 10, 2022
Gobby-cli - CLI application to debug gobby applications

go(bby) Interactive debugging tool for gobby applications Usage Coming soon™ Ins

Feb 8, 2022
Go (golang) package with 70+ configurable terminal spinner/progress indicators.
Go (golang) package with 70+ configurable terminal spinner/progress indicators.

Spinner spinner is a simple package to add a spinner / progress indicator to any terminal application. Examples can be found below as well as full exa

Dec 26, 2022
Utilities to prettify console output of tables, lists, progress-bars, text, etc.
Utilities to prettify console output of tables, lists, progress-bars, text, etc.

go-pretty Utilities to prettify console output of tables, lists, progress-bars, text, etc. Table Pretty-print tables into ASCII/Unicode strings.

Dec 29, 2022
hierarchical progress bars in terminal on steroids
hierarchical progress bars in terminal on steroids

Echelon - hierarchical progress in terminals Cross-platform library to organize logs in a hierarchical structure. Here is an example how it looks for

Nov 26, 2022
Print day progress in your terminal

Day progress Print day progress in your terminal Install go install github.com/tsivinsky/day-progress@latest Usage day-progress By default, day-progre

Jan 10, 2022
Golang-video-screensaver - A work in progress Microsoft Windows video screensaver implemented in Go

golang-video-screensaver A work in progress Microsoft Windows video screensaver

Sep 5, 2022
A versatile library for building CLI applications in Go

mow.cli Package cli provides a framework to build command line applications in Go with most of the burden of arguments parsing and validation placed o

Dec 28, 2022
An easy to use menu structure for cli applications that prompts users to make choices.
An easy to use menu structure for cli applications that prompts users to make choices.

WMenu Package wmenu creates menus for cli programs. It uses wlog for its interface with the command line. It uses os.Stdin, os.Stdout, and os.Stderr w

Dec 26, 2022
Jan 3, 2023
Dinogo is an CLI framework for build terminal and shell applications in Go.

dinogo Dinogo is an CLI framework for build terminal and shell applications in Go. Features Cross Platform Fast and efficient Keyboard API Enable/Disa

Aug 29, 2022
Template repository for testing CLI features of applications written in Go

Go CLI testing example This repository provides a template on how to create a testable CLI applications in Go language. As an example, this applicatio

Sep 8, 2022
Prompts users to enter values for required flags in Cobra CLI applications

Cobra Flag Prompt Cobra Flag Prompt prompts users to enter values for required flags. It is an extension of Cobra, and requires that you use Cobra to

Nov 13, 2021
A general purpose project template for golang CLI applications

golang-cli-template A general purpose project template for golang CLI applications golang-cli-template Features Project Layout How to use this templat

Jan 15, 2022