I'm trying to make two-lined progress bar(s) with mpb.
Let's say that I have a slice which contains absolute paths of files.
list := []string{"C:\Temp\01.png", "C:\Temp\02.png", "C:\Temp\03.png", "C:\Temp\test.png", "C:\Temp\test01.png"}
And I want it to be displayed like this:
Processing 01.png ...
0 / 5 [ ] 0%
Processing 02.png ...
1 / 5 [== ] 20%
Processing 03.png ...
2 / 5 [==== ] 40%
and so on.
The reasons of separting 'Processing ...' part and progress bar are these:
Processing 01.png ... [Mode: WebP]
0 / 5 [ ] 0%
Processing 01.mp4 ... [Mode: WebM] [Pass: 1/2]
0 / 5 [ ] 0%
Processing 01.mp4 ... [Mode: WebM] [Pass: 2/2]
0 / 5 [ ] 0%
Note that progress bar isn't changed.Processing 01.mp4 ... [Mode: WebM] [Pass: 1/2]
4 / 5 [================ ] 0%
Processing 01.png ... [Mode: WebP]
2 / 5 [======== ] 0%
Processing DONE [Mode: MP3]
5 / 5 [====================] 100%
Each progress bar should be updated ASAP when something got changed, not 'update every progress bar every 0.5 sec'.I couldn't find a way of doing this. Every example code of mpb was doing its thing in single-line.
First time I see this library but after exploring some code I found how to add new and customize the bars as we want. I have done some modifications to the example which you provided the link in your comment to demonstrative the adding and customizing the bars.
package main
import (
"fmt"
"io"
"math/rand"
"time"
"github.com/vbauerster/mpb/v8"
"github.com/vbauerster/mpb/v8/decor"
)
func main() {
p := mpb.New()
var piece, piece2 int64
var way, way2 int64
file := func(_ decor.Statistics) string {
return "file.extension "
}
file2 := func(_ decor.Statistics) string {
return "file2.extension "
}
part := func(s decor.Statistics) string {
s.Current = piece
s.Total = 5
return fmt.Sprintf(" Part %d/%d", s.Current, s.Total)
}
part2 := func(s decor.Statistics) string {
s.Current = piece2
s.Total = 10
return fmt.Sprintf(" Part %d/%d", s.Current, s.Total)
}
pass := func(s decor.Statistics) string {
s.Current = way
s.Total = 2
return fmt.Sprintf(" Pass %d/%d", s.Current, s.Total)
}
pass2 := func(s decor.Statistics) string {
s.Current = way2
s.Total = 4
return fmt.Sprintf(" Pass %d/%d", s.Current, s.Total)
}
var total = 100
bar := p.New(int64(total),
mpb.NopStyle(), // make main bar style nop, so there are just decorators
mpb.BarExtender(extended(mpb.BarStyle().Build()), false), // extend wtih normal bar on the next line
mpb.PrependDecorators(
decor.Any(file),
decor.Name("Percentage: "),
decor.NewPercentage("%d"),
decor.Any(part),
decor.Any(pass),
),
)
bar2 := p.New(int64(total+100),
mpb.NopStyle(),
mpb.BarExtender(extended(mpb.BarStyle().Build()), false),
mpb.PrependDecorators(
decor.Any(file2),
decor.Name("Percentage: "),
decor.NewPercentage("%d"),
decor.Any(part2),
decor.Any(pass2),
),
)
// simulating some work
max := 100 * time.Millisecond
for i := 0; i < total+100; i++ {
switch {
case i == 20 || i == 40 || i == 60 ||
i == 80 || i == 100 || i == 120 ||
i == 140 || i == 160 || i == 180:
piece2++
if i == 100 {
way2++
piece = 5
way = 2
} else if i < 100 {
piece++
}
case i == 50 || i == 150:
if i < 100 {
way++
}
way2++
}
time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
if i < 100 {
bar.Increment()
}
bar2.Increment()
}
way2 = 4
piece2 = 10
// wait for our bar to complete and flush
p.Wait()
}
func extended(base mpb.BarFiller) mpb.BarFiller {
return mpb.BarFillerFunc(func(w io.Writer, st decor.Statistics) error {
err := base.Fill(w, st)
if err != nil {
return err
}
_, err = io.WriteString(w, "\n")
return err
})
}
Assuming you already know how to make custom decorators.
To make a new bar you can do this:
bar := p.New(int64(total),
mpb.NopStyle(), // make main bar style nop, so there are just decorators
mpb.BarExtender(extended(mpb.BarStyle().Build()), false), // extend wtih normal bar on the next line
mpb.PrependDecorators(
decor.Any(file),
decor.Name("Percentage: "),
decor.NewPercentage("%d"),
decor.Any(part),
decor.Any(pass),
),
)
I have only made two bars for example but you make more than two.
In this example to demonstrative the making new bars I have used New()
method but after doing some research I have found there are more ways to make a new bar. The difference is mostly how the bars will look. You can find them by looking methods that returns Bar
instance in method list of the Progress
struct in the documentation.
First argument of p.New()
is for define a total value for the bar, in this bar it is 100.
Just put your decorators/sections to mpb.PrependDecorators
or mpb.AppendDecorators
.
mpb.PrependDecorators(
decor.Any(file),
decor.Name("Percentage: "),
decor.NewPercentage("%d"),
decor.Any(part),
decor.Any(pass),
),
You can use same decorators for every bar but I recommend making new one for every bar to avoid possibility of conflicts.
This will respectively show file name, percentage, part and pass:
file.extension Percentage: 100% Part 5/5 Pass 2/2
[==============================================================================]
In this example every decoration increases by 1 depending its set value in loop that iterates through total value of the bar. In this bar I just iterated 1 to 100. And I aimed the 100 to 5 parts. When loop variable encounters with one of 5 parts of the 100, the Part
decoration of the bar will increase by 1.
And when it comes to 50, the Pass
decoration will increase by 1.
for i := 0; i < total+100; i++ {
switch {
case i == 20 || i == 40 || i == 60 ||
i == 80 || i == 100 || i == 120 ||
i == 140 || i == 160 || i == 180:
piece2++
if i == 100 {
way2++
piece = 5
way = 2
} else if i < 100 {
piece++
}
case i == 50 || i == 150:
if i < 100 {
way++
}
way2++
}
time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
if i < 100 {
bar.Increment()
}
bar2.Increment()
}
This loop will work for second bar too. I just combined two bars' increment status in single loop to make the code shorter. If the loop variable less than 100 increase first bar's status. When it is 100, complete increase all decorations to its total then continue increase the status of the second bar until loop finish. After loop finish complete rest of second bar's increments to total.
way2 = 4
piece2 = 10
The second bar is 10 parts and 4 passes and total value is 200.
And output of the whole code is:
file.extension Percentage: 9% Part 0/5 Pass 0/2
[======>-----------------------------------------------------------------------]
file2.extension Percentage: 4% Part 0/10 Pass 0/4
[===>--------------------------------------------------------------------------]
file.extension Percentage: 49% Part 2/5 Pass 0/2
[=====================================>----------------------------------------]
file2.extension Percentage: 24% Part 2/10 Pass 0/4
[==================>-----------------------------------------------------------]
file.extension Percentage: 100% Part 5/5 Pass 2/2
[==============================================================================]
file2.extension Percentage: 74% Part 7/10 Pass 2/4
[=========================================================>--------------------]
file.extension Percentage: 100% Part 5/5 Pass 2/2
[==============================================================================]
file2.extension Percentage: 100% Part 10/10 Pass 4/4
[==============================================================================]