Codebase list golang-github-vbauerster-mpb / bd4ab3c
Merge branch 'experimental' into debian/sid Reinhard Tartler 1 year, 7 months ago
58 changed file(s) with 931 addition(s) and 902 deletion(s). Raw diff Collapse all Expand all
2121 os: [ubuntu-latest, macos-latest]
2222 runs-on: ${{ matrix.os }}
2323 steps:
24 - uses: actions/checkout@v3
25 - uses: actions/setup-go@v4
24 - uses: actions/checkout@v4
25 - uses: actions/setup-go@v5
2626 with:
2727 go-version: ${{ matrix.go-version }}
2828 cache: false
29 - uses: golangci/golangci-lint-action@v3
29 - uses: golangci/golangci-lint-action@v6
3030 with:
3131 # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
3232 version: latest
33 # Optional: working directory, useful for monorepos
34 # working-directory: somedir
3533
3634 # Optional: golangci-lint command line arguments.
3735 # args: --issues-exit-code=0
55 - v*
66 branches:
77 - master
8 - v*
8 - main
99 pull_request:
1010
1111 permissions:
2020 os: [ubuntu-latest, macos-latest, windows-latest]
2121 runs-on: ${{ matrix.os }}
2222 steps:
23 - uses: actions/checkout@v3
24 - uses: actions/setup-go@v4
23 - uses: actions/checkout@v4
24 - uses: actions/setup-go@v5
2525 with:
2626 go-version: ${{ matrix.go-version }}
2727 - run: go test -race ./...
4141 mpb.BarStyle().Lbound("╢").Filler("▌").Tip("▌").Padding("░").Rbound("╟"),
4242 mpb.PrependDecorators(
4343 // display our name with one space on the right
44 decor.Name(name, decor.WC{W: len(name) + 1, C: decor.DidentRight}),
44 decor.Name(name, decor.WC{C: decor.DindentRight | decor.DextraSpace}),
4545 // replace ETA decorator with "done" message, OnComplete event
46 decor.OnComplete(
47 decor.AverageETA(decor.ET_STYLE_GO, decor.WC{W: 4}), "done",
48 ),
46 decor.OnComplete(decor.AverageETA(decor.ET_STYLE_GO), "done"),
4947 ),
5048 mpb.AppendDecorators(decor.Percentage()),
5149 )
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
22 go 1.17
33
44 require (
5 github.com/fatih/color v1.15.0
6 github.com/vbauerster/mpb/v8 v8.6.1
5 github.com/fatih/color v1.17.0
6 github.com/vbauerster/mpb/v8 v8.8.2
77 )
88
99 require (
1010 github.com/VividCortex/ewma v1.2.0 // indirect
1111 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
1212 github.com/mattn/go-colorable v0.1.13 // indirect
13 github.com/mattn/go-isatty v0.0.19 // indirect
14 github.com/mattn/go-runewidth v0.0.15 // indirect
15 github.com/rivo/uniseg v0.4.4 // indirect
16 golang.org/x/sys v0.11.0 // indirect
13 github.com/mattn/go-isatty v0.0.20 // indirect
14 github.com/mattn/go-runewidth v0.0.16 // indirect
15 github.com/rivo/uniseg v0.4.7 // indirect
16 golang.org/x/sys v0.24.0 // indirect
1717 )
2424 queue := make([]*mpb.Bar, 2)
2525 queue[0] = p.AddBar(rand.Int63n(201)+100,
2626 mpb.PrependDecorators(
27 decor.Name(task, decor.WC{W: len(task) + 1, C: decor.DidentRight}),
27 decor.Name(task, decor.WC{C: decor.DindentRight | decor.DextraSpace}),
2828 decor.Name("downloading", decor.WCSyncSpaceR),
2929 decor.CountersNoUnit("%d / %d", decor.WCSyncWidth),
3030 ),
3636 mpb.BarQueueAfter(queue[0]), // this bar is queued
3737 mpb.BarFillerClearOnComplete(),
3838 mpb.PrependDecorators(
39 decor.Name(task, decor.WC{W: len(task) + 1, C: decor.DidentRight}),
39 decor.Name(task, decor.WC{C: decor.DindentRight | decor.DextraSpace}),
4040 decor.OnCompleteMeta(
4141 decor.OnComplete(
4242 decor.Meta(decor.Name("installing", decor.WCSyncSpaceR), toMetaFunc(red)),
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
0 #!/bin/sh
1 set -e
2
3 for d in *; do
4 [ ! -d "$d" ] && continue
5 pushd "$d" >/dev/null 2>&1
6 go mod tidy
7 popd >/dev/null 2>&1
8 done
+0
-8
_examples/gomodtidyall.sh less more
0 #!/bin/sh
1
2 for d in *; do
3 [ ! -d "$d" ] && continue
4 pushd "$d" >/dev/null 2>&1
5 go mod tidy
6 popd >/dev/null 2>&1
7 done
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
22 import (
33 "crypto/rand"
44 "io"
5 "io/ioutil"
65 "time"
76
87 "github.com/vbauerster/mpb/v8"
109 )
1110
1211 func main() {
13 var total int64 = 1024 * 1024 * 500
14 reader := io.LimitReader(rand.Reader, total)
12 var total int64 = 64 * 1024 * 1024
13
14 r, w := io.Pipe()
15
16 go func() {
17 for i := 0; i < 1024; i++ {
18 _, _ = io.Copy(w, io.LimitReader(rand.Reader, 64*1024))
19 time.Sleep(time.Second / 10)
20 }
21 w.Close()
22 }()
1523
1624 p := mpb.New(
1725 mpb.WithWidth(60),
3139 )
3240
3341 // create proxy reader
34 proxyReader := bar.ProxyReader(reader)
42 proxyReader := bar.ProxyReader(r)
3543 defer proxyReader.Close()
3644
3745 // copy from proxyReader, ignoring errors
38 _, _ = io.Copy(ioutil.Discard, proxyReader)
46 _, _ = io.Copy(io.Discard, proxyReader)
3947
4048 p.Wait()
4149 }
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
2323 ),
2424 mpb.AppendDecorators(
2525 decor.OnComplete(decor.Name(" "), ""),
26 decor.OnComplete(decor.EwmaETA(decor.ET_STYLE_GO, 60), ""),
26 decor.OnComplete(decor.EwmaETA(decor.ET_STYLE_GO, 30), ""),
2727 ),
2828 )
2929 // simulating some work
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
1212
1313 func main() {
1414 total, numBars := 100, 2
15 var wg sync.WaitGroup
16 wg.Add(numBars)
15 var bwg, qwg sync.WaitGroup
16 bwg.Add(numBars)
17 qwg.Add(1)
1718 done := make(chan interface{})
18 p := mpb.New(
19 mpb.WithWidth(64),
20 mpb.WithWaitGroup(&wg),
21 mpb.WithShutdownNotifier(done),
22 )
19 p := mpb.New(mpb.WithWidth(64), mpb.WithShutdownNotifier(done), mpb.WithWaitGroup(&qwg))
2320
2421 log.SetOutput(p)
22
23 go func() {
24 defer qwg.Done()
25 for {
26 select {
27 case <-done:
28 // after done, underlying io.Writer returns mpb.DoneError
29 // so following isn't printed
30 log.Println("all done")
31 return
32 default:
33 log.Println("waiting for done")
34 time.Sleep(150 * time.Millisecond)
35 }
36 }
37 }()
38
39 nopBar := p.MustAdd(0, nil)
2540
2641 for i := 0; i < numBars; i++ {
2742 name := fmt.Sprintf("Bar#%d:", i)
3853 )
3954 // simulating some work
4055 go func() {
41 defer wg.Done()
56 defer bwg.Done()
4257 rng := rand.New(rand.NewSource(time.Now().UnixNano()))
4358 max := 100 * time.Millisecond
4459 for i := 0; i < total; i++ {
5368 }()
5469 }
5570
56 var qwg sync.WaitGroup
57 qwg.Add(1)
58 go func() {
59 quit:
60 for {
61 select {
62 case <-done:
63 // after done, underlying io.Writer returns mpb.DoneError
64 // so following isn't printed
65 log.Println("all done")
66 break quit
67 default:
68 log.Println("waiting for done")
69 time.Sleep(100 * time.Millisecond)
70 }
71 }
72 qwg.Done()
73 }()
71 bwg.Wait()
72 log.Println("completing nop bar")
73 nopBar.EnableTriggerComplete()
7474
7575 p.Wait()
76 qwg.Wait()
7776 }
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
1919 mpb.BarStyle().Lbound("╢").Filler("▌").Tip("▌").Padding("░").Rbound("╟"),
2020 mpb.PrependDecorators(
2121 // display our name with one space on the right
22 decor.Name(name, decor.WC{W: len(name) + 1, C: decor.DidentRight}),
22 decor.Name(name, decor.WC{C: decor.DindentRight | decor.DextraSpace}),
2323 // replace ETA decorator with "done" message, OnComplete event
24 decor.OnComplete(
25 decor.AverageETA(decor.ET_STYLE_GO, decor.WC{W: 4}), "done",
26 ),
24 decor.OnComplete(decor.AverageETA(decor.ET_STYLE_GO), "done"),
2725 ),
2826 mpb.AppendDecorators(decor.Percentage()),
2927 )
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
33
44 require (
55 github.com/pkg/profile v1.7.0
6 github.com/vbauerster/mpb/v8 v8.6.1
6 github.com/vbauerster/mpb/v8 v8.8.2
77 )
88
99 require (
1010 github.com/VividCortex/ewma v1.2.0 // indirect
1111 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
12 github.com/felixge/fgprof v0.9.3 // indirect
13 github.com/google/pprof v0.0.0-20230821062121-407c9e7a662f // indirect
14 github.com/mattn/go-runewidth v0.0.15 // indirect
15 github.com/rivo/uniseg v0.4.4 // indirect
16 golang.org/x/sys v0.11.0 // indirect
12 github.com/felixge/fgprof v0.9.4 // indirect
13 github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
14 github.com/mattn/go-runewidth v0.0.16 // indirect
15 github.com/rivo/uniseg v0.4.7 // indirect
16 golang.org/x/sys v0.24.0 // indirect
1717 )
1313 )
1414
1515 const (
16 totalBars = 32
16 totalBars = 42
1717 )
1818
1919 var proftype = flag.String("prof", "", "profile type (cpu, mem)")
3737 bar := p.AddBar(int64(total),
3838 mpb.PrependDecorators(
3939 decor.Name(name, decor.WCSyncWidthR),
40 decor.Elapsed(decor.ET_STYLE_GO, decor.WCSyncWidth),
40 decor.OnComplete(decor.Percentage(decor.WCSyncWidth), "done"),
4141 ),
4242 mpb.AppendDecorators(
43 decor.OnComplete(
44 decor.Percentage(decor.WC{W: 5}), "done",
45 ),
43 decor.OnComplete(decor.EwmaETA(decor.ET_STYLE_GO, 30, decor.WCSyncWidth), ""),
44 decor.EwmaSpeed(decor.SizeB1024(0), "", 30, decor.WCSyncSpace),
4645 ),
4746 )
4847
5049 defer wg.Done()
5150 rng := rand.New(rand.NewSource(time.Now().UnixNano()))
5251 max := 100 * time.Millisecond
53 for !bar.Completed() {
52 for bar.IsRunning() {
53 start := time.Now()
5454 time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10)
55 bar.Increment()
55 bar.EwmaIncrement(time.Since(start))
5656 }
5757 }()
5858 }
11
22 go 1.17
33
4 require (
5 github.com/mattn/go-runewidth v0.0.15
6 github.com/vbauerster/mpb/v8 v8.6.1
7 )
4 require github.com/vbauerster/mpb/v8 v8.8.2
85
96 require (
107 github.com/VividCortex/ewma v1.2.0 // indirect
118 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
12 github.com/rivo/uniseg v0.4.4 // indirect
13 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1412 )
22 import (
33 "errors"
44 "fmt"
5 "io"
5 "math"
66 "math/rand"
77 "sync"
88 "time"
99
10 "github.com/mattn/go-runewidth"
1110 "github.com/vbauerster/mpb/v8"
1211 "github.com/vbauerster/mpb/v8/decor"
1312 )
1514 func main() {
1615 p := mpb.New()
1716
18 total := 100
19 msgCh := make(chan string)
20 resumeCh := make(chan struct{})
21 nextCh := make(chan struct{}, 1)
22 ew := &errorWrapper{}
17 total, numBars := 100, 3
18 err := new(errorWrapper)
2319 timer := time.AfterFunc(2*time.Second, func() {
24 ew.reset(errors.New("timeout"))
20 err.set(errors.New("timeout"), rand.Intn(numBars))
2521 })
2622 defer timer.Stop()
27 bar := p.AddBar(int64(total),
28 mpb.BarFillerMiddleware(func(base mpb.BarFiller) mpb.BarFiller {
29 var msg *string
30 var times int
31 return mpb.BarFillerFunc(func(w io.Writer, st decor.Statistics) error {
32 if msg == nil {
33 select {
34 case m := <-msgCh:
35 msg = &m
36 times = 10
37 nextCh <- struct{}{}
38 default:
39 }
40 return base.Fill(w, st)
23
24 for i := 0; i < numBars; i++ {
25 msgCh := make(chan string, 1)
26 bar := p.AddBar(int64(total),
27 mpb.PrependDecorators(newTitleDecorator(fmt.Sprintf("Bar#%d:", i), msgCh, 16)),
28 mpb.AppendDecorators(decor.Percentage(decor.WCSyncWidth)),
29 )
30 // simulating some work
31 barID := i
32 go func() {
33 max := 100 * time.Millisecond
34 for i := 0; i < total; i++ {
35 if err.check(barID) {
36 msgCh <- fmt.Sprintf("%s at %d, retrying...", err.Error(), i)
37 err.reset()
38 i--
39 bar.SetRefill(int64(i))
40 continue
4141 }
42 switch {
43 case times == 0, st.Completed, st.Aborted:
44 defer func() {
45 msg = nil
46 }()
47 resumeCh <- struct{}{}
48 default:
49 times--
50 }
51 _, err := io.WriteString(w, runewidth.Truncate(*msg, st.AvailableWidth, "…"))
52 nextCh <- struct{}{}
53 return err
54 })
55 }),
56 mpb.PrependDecorators(decor.Name("my bar:")),
57 mpb.AppendDecorators(newCustomPercentage(nextCh)),
58 )
59 // simulating some work
60 go func() {
61 rng := rand.New(rand.NewSource(time.Now().UnixNano()))
62 max := 100 * time.Millisecond
63 for i := 0; i < total; i++ {
64 time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10)
65 if ew.isErr() {
66 msgCh <- fmt.Sprintf("%s at %d, retrying...", ew.Error(), i)
67 i--
68 bar.SetRefill(int64(i))
69 ew.reset(nil)
70 <-resumeCh
71 continue
42 time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
43 bar.Increment()
7244 }
73 bar.Increment()
74 }
75 }()
45 }()
46 }
7647
7748 p.Wait()
7849 }
7950
8051 type errorWrapper struct {
8152 sync.RWMutex
82 err error
53 err error
54 barID int
8355 }
8456
8557 func (ew *errorWrapper) Error() string {
8860 return ew.err.Error()
8961 }
9062
91 func (ew *errorWrapper) isErr() bool {
63 func (ew *errorWrapper) check(barID int) bool {
9264 ew.RLock()
9365 defer ew.RUnlock()
94 return ew.err != nil
66 return ew.err != nil && ew.barID == barID
9567 }
9668
97 func (ew *errorWrapper) reset(err error) {
69 func (ew *errorWrapper) set(err error, barID int) {
9870 ew.Lock()
9971 ew.err = err
72 ew.barID = barID
10073 ew.Unlock()
10174 }
10275
103 type percentage struct {
104 decor.Decorator
105 suspend <-chan struct{}
76 func (ew *errorWrapper) reset() {
77 ew.Lock()
78 ew.err = nil
79 ew.Unlock()
10680 }
10781
108 func (d percentage) Decor(s decor.Statistics) (string, int) {
109 select {
110 case <-d.suspend:
111 return d.Format("")
112 default:
113 return d.Decorator.Decor(s)
82 type title struct {
83 decor.Decorator
84 name string
85 msgCh <-chan string
86 msg string
87 count int
88 limit int
89 }
90
91 func (d *title) Decor(stat decor.Statistics) (string, int) {
92 if d.count == 0 {
93 select {
94 case msg := <-d.msgCh:
95 d.count = d.limit
96 d.msg = msg
97 default:
98 return d.Decorator.Decor(stat)
99 }
100 }
101 d.count--
102 _, _ = d.Format("")
103 return fmt.Sprintf("%s %s", d.name, d.msg), math.MaxInt
104 }
105
106 func newTitleDecorator(name string, msgCh <-chan string, limit int) decor.Decorator {
107 return &title{
108 Decorator: decor.Name(name),
109 name: name,
110 msgCh: msgCh,
111 limit: limit,
114112 }
115113 }
116
117 func newCustomPercentage(nextCh <-chan struct{}) decor.Decorator {
118 return percentage{
119 Decorator: decor.Percentage(),
120 suspend: nextCh,
121 }
122 }
11
22 go 1.17
33
4 require github.com/vbauerster/mpb/v8 v8.6.1
4 require github.com/vbauerster/mpb/v8 v8.8.2
55
66 require (
77 github.com/VividCortex/ewma v1.2.0 // indirect
88 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.15 // indirect
10 github.com/rivo/uniseg v0.4.4 // indirect
11 golang.org/x/sys v0.11.0 // indirect
9 github.com/mattn/go-runewidth v0.0.16 // indirect
10 github.com/rivo/uniseg v0.4.7 // indirect
11 golang.org/x/sys v0.24.0 // indirect
1212 )
+293
-345
bar.go less more
1818 priority int // used by heap
1919 frameCh chan *renderFrame
2020 operateState chan func(*bState)
21 done chan struct{}
2221 container *Progress
2322 bs *bState
23 bsOk chan struct{}
24 ctx context.Context
2425 cancel func()
2526 }
2627
2728 type syncTable [2][]chan int
28 type extenderFunc func([]io.Reader, decor.Statistics) ([]io.Reader, error)
29 type extenderFunc func(decor.Statistics, ...io.Reader) ([]io.Reader, error)
2930
3031 // bState is actual bar's state.
3132 type bState struct {
32 id int
33 priority int
34 reqWidth int
35 shutdown int
36 total int64
37 current int64
38 refill int64
39 trimSpace bool
40 completed bool
41 aborted bool
42 triggerComplete bool
43 rmOnComplete bool
44 noPop bool
45 autoRefresh bool
46 aDecorators []decor.Decorator
47 pDecorators []decor.Decorator
48 averageDecorators []decor.AverageDecorator
49 ewmaDecorators []decor.EwmaDecorator
50 shutdownListeners []decor.ShutdownListener
51 buffers [3]*bytes.Buffer
52 filler BarFiller
53 extender extenderFunc
54 renderReq chan<- time.Time
55 waitBar *Bar // key for (*pState).queueBars
33 id int
34 priority int
35 reqWidth int
36 shutdown int
37 total int64
38 current int64
39 refill int64
40 trimSpace bool
41 aborted bool
42 triggerComplete bool
43 rmOnComplete bool
44 noPop bool
45 autoRefresh bool
46 buffers [3]*bytes.Buffer
47 decorators [2][]decor.Decorator
48 ewmaDecorators []decor.EwmaDecorator
49 filler BarFiller
50 extender extenderFunc
51 renderReq chan<- time.Time
52 waitBar *Bar // key for (*pState).queueBars
5653 }
5754
5855 type renderFrame struct {
6057 shutdown int
6158 rmOnComplete bool
6259 noPop bool
63 done bool
6460 err error
6561 }
6662
7167 priority: bs.priority,
7268 frameCh: make(chan *renderFrame, 1),
7369 operateState: make(chan func(*bState)),
74 done: make(chan struct{}),
70 bsOk: make(chan struct{}),
7571 container: container,
72 ctx: ctx,
7673 cancel: cancel,
7774 }
7875
7976 container.bwg.Add(1)
80 go bar.serve(ctx, bs)
77 go bar.serve(bs)
8178 return bar
8279 }
8380
84 // ProxyReader wraps io.Reader with metrics required for progress tracking.
85 // If `r` is 'unknown total/size' reader it's mandatory to call
86 // (*Bar).SetTotal(-1, true) method after (io.Reader).Read returns io.EOF.
87 // If bar is already completed or aborted, returns nil.
81 // ProxyReader wraps io.Reader with metrics required for progress
82 // tracking. If `r` is 'unknown total/size' reader it's mandatory
83 // to call `(*Bar).SetTotal(-1, true)` after the wrapper returns
84 // `io.EOF`. If bar is already completed or aborted, returns nil.
8885 // Panics if `r` is nil.
8986 func (b *Bar) ProxyReader(r io.Reader) io.ReadCloser {
9087 if r == nil {
9188 panic("expected non nil io.Reader")
9289 }
93 result := make(chan bool)
94 select {
95 case b.operateState <- func(s *bState) { result <- len(s.ewmaDecorators) != 0 }:
96 return newProxyReader(r, b, <-result)
97 case <-b.done:
90 result := make(chan io.ReadCloser)
91 select {
92 case b.operateState <- func(s *bState) {
93 result <- newProxyReader(r, b, len(s.ewmaDecorators) != 0)
94 }:
95 return <-result
96 case <-b.ctx.Done():
9897 return nil
9998 }
10099 }
106105 if w == nil {
107106 panic("expected non nil io.Writer")
108107 }
109 result := make(chan bool)
110 select {
111 case b.operateState <- func(s *bState) { result <- len(s.ewmaDecorators) != 0 }:
112 return newProxyWriter(w, b, <-result)
113 case <-b.done:
108 result := make(chan io.WriteCloser)
109 select {
110 case b.operateState <- func(s *bState) {
111 result <- newProxyWriter(w, b, len(s.ewmaDecorators) != 0)
112 }:
113 return <-result
114 case <-b.ctx.Done():
114115 return nil
115116 }
116117 }
121122 select {
122123 case b.operateState <- func(s *bState) { result <- s.id }:
123124 return <-result
124 case <-b.done:
125 case <-b.bsOk:
125126 return b.bs.id
126127 }
127128 }
132133 select {
133134 case b.operateState <- func(s *bState) { result <- s.current }:
134135 return <-result
135 case <-b.done:
136 case <-b.bsOk:
136137 return b.bs.current
137138 }
138139 }
150151 s.refill = s.current
151152 }
152153 }:
153 case <-b.done:
154 }
155 }
156
157 // TraverseDecorators traverses all available decorators and calls cb func on each.
154 case <-b.ctx.Done():
155 }
156 }
157
158 // TraverseDecorators traverses available decorators and calls cb func
159 // on each in a new goroutine. Decorators implementing decor.Wrapper
160 // interface are unwrapped first.
158161 func (b *Bar) TraverseDecorators(cb func(decor.Decorator)) {
159 iter := make(chan decor.Decorator)
160 select {
161 case b.operateState <- func(s *bState) {
162 for _, decorators := range [][]decor.Decorator{
163 s.pDecorators,
164 s.aDecorators,
165 } {
162 select {
163 case b.operateState <- func(s *bState) {
164 var wg sync.WaitGroup
165 for _, decorators := range s.decorators {
166 wg.Add(len(decorators))
166167 for _, d := range decorators {
167 iter <- d
168 d := d
169 go func() {
170 cb(unwrap(d))
171 wg.Done()
172 }()
168173 }
169174 }
170 close(iter)
171 }:
172 for d := range iter {
173 cb(unwrap(d))
174 }
175 case <-b.done:
176 }
177 }
178
179 // EnableTriggerComplete enables triggering complete event. It's
180 // effective only for bars which were constructed with `total <= 0` and
181 // after total has been set with (*Bar).SetTotal(int64, false). If bar
182 // has been incremented to the total, complete event is triggered right
183 // away.
175 wg.Wait()
176 }:
177 case <-b.ctx.Done():
178 }
179 }
180
181 // EnableTriggerComplete enables triggering complete event. It's effective
182 // only for bars which were constructed with `total <= 0`. If `curren >= total`
183 // at the moment of call, complete event is triggered right away.
184184 func (b *Bar) EnableTriggerComplete() {
185185 select {
186186 case b.operateState <- func(s *bState) {
187 if s.triggerComplete || s.total <= 0 {
187 if s.triggerComplete {
188188 return
189189 }
190190 if s.current >= s.total {
191191 s.current = s.total
192 s.completed = true
193 b.triggerCompletion(s)
192 s.triggerCompletion(b)
194193 } else {
195194 s.triggerComplete = true
196195 }
197196 }:
198 case <-b.done:
199 }
200 }
201
202 // SetTotal sets total to an arbitrary value. It's effective only for
203 // bar which was constructed with `total <= 0`. Setting total to negative
204 // value is equivalent to (*Bar).SetTotal((*Bar).Current(), bool) but faster.
205 // If triggerCompletion is true, total value is set to current and
206 // complete event is triggered right away.
207 func (b *Bar) SetTotal(total int64, triggerCompletion bool) {
197 case <-b.ctx.Done():
198 }
199 }
200
201 // SetTotal sets total to an arbitrary value. It's effective only for bar
202 // which was constructed with `total <= 0`. Setting total to negative value
203 // is equivalent to `(*Bar).SetTotal((*Bar).Current(), bool)` but faster.
204 // If `complete` is true complete event is triggered right away.
205 // Calling `(*Bar).EnableTriggerComplete` makes this one no operational.
206 func (b *Bar) SetTotal(total int64, complete bool) {
208207 select {
209208 case b.operateState <- func(s *bState) {
210209 if s.triggerComplete {
215214 } else {
216215 s.total = total
217216 }
218 if triggerCompletion {
217 if complete {
219218 s.current = s.total
220 s.completed = true
221 b.triggerCompletion(s)
222 }
223 }:
224 case <-b.done:
219 s.triggerCompletion(b)
220 }
221 }:
222 case <-b.ctx.Done():
225223 }
226224 }
227225
235233 s.current = current
236234 if s.triggerComplete && s.current >= s.total {
237235 s.current = s.total
238 s.completed = true
239 b.triggerCompletion(s)
240 }
241 }:
242 case <-b.done:
236 s.triggerCompletion(b)
237 }
238 }:
239 case <-b.ctx.Done():
240 }
241 }
242
243 // Increment is a shorthand for b.IncrInt64(1).
244 func (b *Bar) Increment() {
245 b.IncrInt64(1)
246 }
247
248 // IncrBy is a shorthand for b.IncrInt64(int64(n)).
249 func (b *Bar) IncrBy(n int) {
250 b.IncrInt64(int64(n))
251 }
252
253 // IncrInt64 increments progress by amount of n.
254 func (b *Bar) IncrInt64(n int64) {
255 select {
256 case b.operateState <- func(s *bState) {
257 s.current += n
258 if s.triggerComplete && s.current >= s.total {
259 s.current = s.total
260 s.triggerCompletion(b)
261 }
262 }:
263 case <-b.ctx.Done():
264 }
265 }
266
267 // EwmaIncrement is a shorthand for b.EwmaIncrInt64(1, iterDur).
268 func (b *Bar) EwmaIncrement(iterDur time.Duration) {
269 b.EwmaIncrInt64(1, iterDur)
270 }
271
272 // EwmaIncrBy is a shorthand for b.EwmaIncrInt64(int64(n), iterDur).
273 func (b *Bar) EwmaIncrBy(n int, iterDur time.Duration) {
274 b.EwmaIncrInt64(int64(n), iterDur)
275 }
276
277 // EwmaIncrInt64 increments progress by amount of n and updates EWMA based
278 // decorators by dur of a single iteration.
279 func (b *Bar) EwmaIncrInt64(n int64, iterDur time.Duration) {
280 select {
281 case b.operateState <- func(s *bState) {
282 var wg sync.WaitGroup
283 wg.Add(len(s.ewmaDecorators))
284 for _, d := range s.ewmaDecorators {
285 d := d
286 go func() {
287 d.EwmaUpdate(n, iterDur)
288 wg.Done()
289 }()
290 }
291 s.current += n
292 if s.triggerComplete && s.current >= s.total {
293 s.current = s.total
294 s.triggerCompletion(b)
295 }
296 wg.Wait()
297 }:
298 case <-b.ctx.Done():
243299 }
244300 }
245301
251307 }
252308 select {
253309 case b.operateState <- func(s *bState) {
254 if n := current - s.current; n > 0 {
255 s.decoratorEwmaUpdate(n, iterDur)
310 n := current - s.current
311 var wg sync.WaitGroup
312 wg.Add(len(s.ewmaDecorators))
313 for _, d := range s.ewmaDecorators {
314 d := d
315 go func() {
316 d.EwmaUpdate(n, iterDur)
317 wg.Done()
318 }()
256319 }
257320 s.current = current
258321 if s.triggerComplete && s.current >= s.total {
259322 s.current = s.total
260 s.completed = true
261 b.triggerCompletion(s)
262 }
263 }:
264 case <-b.done:
265 }
266 }
267
268 // Increment is a shorthand for b.IncrInt64(1).
269 func (b *Bar) Increment() {
270 b.IncrInt64(1)
271 }
272
273 // IncrBy is a shorthand for b.IncrInt64(int64(n)).
274 func (b *Bar) IncrBy(n int) {
275 b.IncrInt64(int64(n))
276 }
277
278 // IncrInt64 increments progress by amount of n.
279 func (b *Bar) IncrInt64(n int64) {
280 if n <= 0 {
281 return
282 }
283 select {
284 case b.operateState <- func(s *bState) {
285 s.current += n
286 if s.triggerComplete && s.current >= s.total {
287 s.current = s.total
288 s.completed = true
289 b.triggerCompletion(s)
290 }
291 }:
292 case <-b.done:
293 }
294 }
295
296 // EwmaIncrement is a shorthand for b.EwmaIncrInt64(1, iterDur).
297 func (b *Bar) EwmaIncrement(iterDur time.Duration) {
298 b.EwmaIncrInt64(1, iterDur)
299 }
300
301 // EwmaIncrBy is a shorthand for b.EwmaIncrInt64(int64(n), iterDur).
302 func (b *Bar) EwmaIncrBy(n int, iterDur time.Duration) {
303 b.EwmaIncrInt64(int64(n), iterDur)
304 }
305
306 // EwmaIncrInt64 increments progress by amount of n and updates EWMA based
307 // decorators by dur of a single iteration.
308 func (b *Bar) EwmaIncrInt64(n int64, iterDur time.Duration) {
309 if n <= 0 {
310 return
311 }
312 select {
313 case b.operateState <- func(s *bState) {
314 s.decoratorEwmaUpdate(n, iterDur)
315 s.current += n
316 if s.triggerComplete && s.current >= s.total {
317 s.current = s.total
318 s.completed = true
319 b.triggerCompletion(s)
320 }
321 }:
322 case <-b.done:
323 }
324 }
325
326 // DecoratorAverageAdjust adjusts all average based decorators. Call
327 // if you need to adjust start time of all average based decorators
328 // or after progress resume.
323 s.triggerCompletion(b)
324 }
325 wg.Wait()
326 }:
327 case <-b.ctx.Done():
328 }
329 }
330
331 // DecoratorAverageAdjust adjusts decorators implementing decor.AverageDecorator interface.
332 // Call if there is need to set start time after decorators have been constructed.
329333 func (b *Bar) DecoratorAverageAdjust(start time.Time) {
330 select {
331 case b.operateState <- func(s *bState) { s.decoratorAverageAdjust(start) }:
332 case <-b.done:
333 }
334 b.TraverseDecorators(func(d decor.Decorator) {
335 if d, ok := d.(decor.AverageDecorator); ok {
336 d.AverageAdjust(start)
337 }
338 })
334339 }
335340
336341 // SetPriority changes bar's order among multiple bars. Zero is highest
343348 // Abort interrupts bar's running goroutine. Abort won't be engaged
344349 // if bar is already in complete state. If drop is true bar will be
345350 // removed as well. To make sure that bar has been removed call
346 // (*Bar).Wait method.
351 // `(*Bar).Wait()` method.
347352 func (b *Bar) Abort(drop bool) {
348353 select {
349354 case b.operateState <- func(s *bState) {
350 if s.completed || s.aborted {
355 if s.aborted || s.completed() {
351356 return
352357 }
353358 s.aborted = true
354359 s.rmOnComplete = drop
355 b.triggerCompletion(s)
356 }:
357 case <-b.done:
360 s.triggerCompletion(b)
361 }:
362 case <-b.ctx.Done():
358363 }
359364 }
360365
364369 select {
365370 case b.operateState <- func(s *bState) { result <- s.aborted }:
366371 return <-result
367 case <-b.done:
372 case <-b.bsOk:
368373 return b.bs.aborted
369374 }
370375 }
373378 func (b *Bar) Completed() bool {
374379 result := make(chan bool)
375380 select {
376 case b.operateState <- func(s *bState) { result <- s.completed }:
381 case b.operateState <- func(s *bState) { result <- s.completed() }:
377382 return <-result
378 case <-b.done:
379 return b.bs.completed
380 }
381 }
382
383 // IsRunning reports whether the bar is running, i.e. not yet completed
384 // and not yet aborted.
383 case <-b.bsOk:
384 return b.bs.completed()
385 }
386 }
387
388 // IsRunning reports whether the bar is in running state.
385389 func (b *Bar) IsRunning() bool {
386 result := make(chan bool)
387 select {
388 case b.operateState <- func(s *bState) { result <- !s.completed && !s.aborted }:
389 return <-result
390 case <-b.done:
390 select {
391 case <-b.ctx.Done():
391392 return false
393 default:
394 return true
392395 }
393396 }
394397
395398 // Wait blocks until bar is completed or aborted.
396399 func (b *Bar) Wait() {
397 <-b.done
398 }
399
400 func (b *Bar) serve(ctx context.Context, bs *bState) {
401 defer b.container.bwg.Done()
400 <-b.bsOk
401 }
402
403 func (b *Bar) serve(bs *bState) {
404 decoratorsOnShutdown := func(decorators []decor.Decorator) {
405 for _, d := range decorators {
406 if d, ok := unwrap(d).(decor.ShutdownListener); ok {
407 b.container.bwg.Add(1)
408 go func() {
409 d.OnShutdown()
410 b.container.bwg.Done()
411 }()
412 }
413 }
414 }
402415 for {
403416 select {
404417 case op := <-b.operateState:
405418 op(bs)
406 case <-ctx.Done():
407 bs.aborted = !bs.completed
408 bs.decoratorShutdownNotify()
419 case <-b.ctx.Done():
420 decoratorsOnShutdown(bs.decorators[0])
421 decoratorsOnShutdown(bs.decorators[1])
422 // bar can be aborted by canceling parent ctx without calling b.Abort
423 bs.aborted = !bs.completed()
409424 b.bs = bs
410 close(b.done)
425 close(b.bsOk)
426 b.container.bwg.Done()
411427 return
412428 }
413429 }
414430 }
415431
416432 func (b *Bar) render(tw int) {
417 var done bool
418433 fn := func(s *bState) {
419 var rows []io.Reader
420 stat := newStatistics(tw, s)
434 frame := new(renderFrame)
435 stat := s.newStatistics(tw)
421436 r, err := s.draw(stat)
422437 if err != nil {
423 b.frameCh <- &renderFrame{err: err}
438 for _, buf := range s.buffers {
439 buf.Reset()
440 }
441 frame.err = err
442 b.frameCh <- frame
424443 return
425444 }
426 rows = append(rows, r)
427 if s.extender != nil {
428 rows, err = s.extender(rows, stat)
429 if err != nil {
430 b.frameCh <- &renderFrame{err: err}
431 return
432 }
433 }
434 frame := &renderFrame{
435 rows: rows,
436 shutdown: s.shutdown,
437 rmOnComplete: s.rmOnComplete,
438 noPop: s.noPop,
439 done: done,
440 }
441 if s.completed || s.aborted {
445 frame.rows, frame.err = s.extender(stat, r)
446 if s.aborted || s.completed() {
447 frame.shutdown = s.shutdown
448 frame.rmOnComplete = s.rmOnComplete
449 frame.noPop = s.noPop
442450 // post increment makes sure OnComplete decorators are rendered
443451 s.shutdown++
444452 }
446454 }
447455 select {
448456 case b.operateState <- fn:
449 case <-b.done:
450 done = true
457 case <-b.bsOk:
451458 fn(b.bs)
452459 }
453460 }
454461
455 func (b *Bar) triggerCompletion(s *bState) {
456 if s.autoRefresh {
457 // Technically this call isn't required, but if refresh rate is set to
458 // one hour for example and bar completes within a few minutes p.Wait()
459 // will wait for one hour. This call helps to avoid unnecessary waiting.
460 go b.tryEarlyRefresh(s.renderReq)
461 } else {
462 b.cancel()
463 }
464 }
465
466462 func (b *Bar) tryEarlyRefresh(renderReq chan<- time.Time) {
467 var anyOtherRunning bool
463 var otherRunning int
468464 b.container.traverseBars(func(bar *Bar) bool {
469 anyOtherRunning = b != bar && bar.IsRunning()
470 return anyOtherRunning
465 if b != bar && bar.IsRunning() {
466 otherRunning++
467 return false // stop traverse
468 }
469 return true // continue traverse
471470 })
472 if !anyOtherRunning {
471 if otherRunning == 0 {
473472 for {
474473 select {
475474 case renderReq <- time.Now():
476 case <-b.done:
475 case <-b.ctx.Done():
477476 return
478477 }
479478 }
485484 select {
486485 case b.operateState <- func(s *bState) { result <- s.wSyncTable() }:
487486 return <-result
488 case <-b.done:
487 case <-b.bsOk:
489488 return b.bs.wSyncTable()
490489 }
491490 }
492491
493 func (s *bState) draw(stat decor.Statistics) (io.Reader, error) {
494 r, err := s.drawImpl(stat)
495 if err != nil {
496 for _, b := range s.buffers {
497 b.Reset()
498 }
499 return nil, err
500 }
501 return io.MultiReader(r, strings.NewReader("\n")), nil
502 }
503
504 func (s *bState) drawImpl(stat decor.Statistics) (io.Reader, error) {
492 func (s *bState) draw(stat decor.Statistics) (_ io.Reader, err error) {
505493 decorFiller := func(buf *bytes.Buffer, decorators []decor.Decorator) (err error) {
506494 for _, d := range decorators {
507495 // need to call Decor in any case becase of width synchronization
521509 return err
522510 }
523511
524 bufP, bufB, bufA := s.buffers[0], s.buffers[1], s.buffers[2]
525
526 err := eitherError(decorFiller(bufP, s.pDecorators), decorFiller(bufA, s.aDecorators))
512 for i, buf := range s.buffers[:2] {
513 err = decorFiller(buf, s.decorators[i])
514 if err != nil {
515 return nil, err
516 }
517 }
518
519 spaces := []io.Reader{
520 strings.NewReader(" "),
521 strings.NewReader(" "),
522 }
523 if s.trimSpace || stat.AvailableWidth < 2 {
524 for _, r := range spaces {
525 _, _ = io.Copy(io.Discard, r)
526 }
527 } else {
528 stat.AvailableWidth -= 2
529 }
530
531 err = s.filler.Fill(s.buffers[2], stat)
527532 if err != nil {
528533 return nil, err
529534 }
530535
531 if !s.trimSpace && stat.AvailableWidth >= 2 {
532 stat.AvailableWidth -= 2
533 writeFiller := func(buf *bytes.Buffer) error {
534 return s.filler.Fill(buf, stat)
535 }
536 for _, fn := range []func(*bytes.Buffer) error{
537 writeSpace,
538 writeFiller,
539 writeSpace,
540 } {
541 if err := fn(bufB); err != nil {
542 return nil, err
543 }
544 }
545 } else {
546 err := s.filler.Fill(bufB, stat)
547 if err != nil {
548 return nil, err
549 }
550 }
551
552 return io.MultiReader(bufP, bufB, bufA), nil
536 return io.MultiReader(
537 s.buffers[0],
538 spaces[0],
539 s.buffers[2],
540 spaces[1],
541 s.buffers[1],
542 strings.NewReader("\n"),
543 ), nil
553544 }
554545
555546 func (s *bState) wSyncTable() (table syncTable) {
556547 var count int
557548 var row []chan int
558549
559 for i, decorators := range [][]decor.Decorator{
560 s.pDecorators,
561 s.aDecorators,
562 } {
550 for i, decorators := range s.decorators {
563551 for _, d := range decorators {
564552 if ch, ok := d.Sync(); ok {
565553 row = append(row, ch)
576564 return table
577565 }
578566
579 func (s bState) decoratorEwmaUpdate(n int64, dur time.Duration) {
580 var wg sync.WaitGroup
581 for i := 0; i < len(s.ewmaDecorators); i++ {
582 switch d := s.ewmaDecorators[i]; i {
583 case len(s.ewmaDecorators) - 1:
584 d.EwmaUpdate(n, dur)
585 default:
586 wg.Add(1)
587 go func() {
588 d.EwmaUpdate(n, dur)
589 wg.Done()
590 }()
591 }
592 }
593 wg.Wait()
594 }
595
596 func (s bState) decoratorAverageAdjust(start time.Time) {
597 var wg sync.WaitGroup
598 for i := 0; i < len(s.averageDecorators); i++ {
599 switch d := s.averageDecorators[i]; i {
600 case len(s.averageDecorators) - 1:
601 d.AverageAdjust(start)
602 default:
603 wg.Add(1)
604 go func() {
605 d.AverageAdjust(start)
606 wg.Done()
607 }()
608 }
609 }
610 wg.Wait()
611 }
612
613 func (s bState) decoratorShutdownNotify() {
614 var wg sync.WaitGroup
615 for i := 0; i < len(s.shutdownListeners); i++ {
616 switch d := s.shutdownListeners[i]; i {
617 case len(s.shutdownListeners) - 1:
618 d.OnShutdown()
619 default:
620 wg.Add(1)
621 go func() {
622 d.OnShutdown()
623 wg.Done()
624 }()
625 }
626 }
627 wg.Wait()
628 }
629
630 func newStatistics(tw int, s *bState) decor.Statistics {
567 func (s *bState) populateEwmaDecorators(decorators []decor.Decorator) {
568 for _, d := range decorators {
569 if d, ok := unwrap(d).(decor.EwmaDecorator); ok {
570 s.ewmaDecorators = append(s.ewmaDecorators, d)
571 }
572 }
573 }
574
575 func (s *bState) triggerCompletion(b *Bar) {
576 s.triggerComplete = true
577 if s.autoRefresh {
578 // Technically this call isn't required, but if refresh rate is set to
579 // one hour for example and bar completes within a few minutes p.Wait()
580 // will wait for one hour. This call helps to avoid unnecessary waiting.
581 go b.tryEarlyRefresh(s.renderReq)
582 } else {
583 b.cancel()
584 }
585 }
586
587 func (s bState) completed() bool {
588 return s.triggerComplete && s.current == s.total
589 }
590
591 func (s bState) newStatistics(tw int) decor.Statistics {
631592 return decor.Statistics{
632593 AvailableWidth: tw,
633594 RequestedWidth: s.reqWidth,
635596 Total: s.total,
636597 Current: s.current,
637598 Refill: s.refill,
638 Completed: s.completed,
599 Completed: s.completed(),
639600 Aborted: s.aborted,
640601 }
641602 }
646607 }
647608 return d
648609 }
649
650 func writeSpace(buf *bytes.Buffer) error {
651 return buf.WriteByte(' ')
652 }
653
654 func eitherError(errors ...error) error {
655 for _, err := range errors {
656 if err != nil {
657 return err
658 }
659 }
660 return nil
661 }
4949 }
5050
5151 type bFiller struct {
52 components [components]component
53 meta [components]func(io.Writer, []byte) error
54 flush func(io.Writer, ...flushSection) error
55 tipOnComplete bool
56 tip struct {
57 frames []component
58 count uint
52 components [components]component
53 meta [components]func(io.Writer, []byte) error
54 flush func(io.Writer, ...flushSection) error
55 tip struct {
56 onComplete bool
57 count uint
58 frames []component
5959 }
6060 }
6161
154154
155155 func (s barStyle) Build() BarFiller {
156156 bf := &bFiller{
157 meta: s.metaFuncs,
158 tipOnComplete: s.tipOnComplete,
157 meta: s.metaFuncs,
159158 }
160159 bf.components[iLbound] = component{
161160 width: runewidth.StringWidth(s.style[iLbound]),
177176 width: runewidth.StringWidth(s.style[iPadding]),
178177 bytes: []byte(s.style[iPadding]),
179178 }
179 bf.tip.onComplete = s.tipOnComplete
180180 bf.tip.frames = make([]component, len(s.tipFrames))
181181 for i, t := range s.tipFrames {
182182 bf.tip.frames[i] = component{
235235 curWidth := int(internal.PercentageRound(stat.Total, stat.Current, uint(width)))
236236
237237 if curWidth != 0 {
238 if !stat.Completed || s.tipOnComplete {
238 if !stat.Completed || s.tip.onComplete {
239239 tip = s.tip.frames[s.tip.count%uint(len(s.tip.frames))]
240240 s.tip.count++
241241 fillCount += tip.width
242242 }
243 if stat.Refill != 0 {
244 refWidth := int(internal.PercentageRound(stat.Total, stat.Refill, uint(width)))
243 switch refWidth := 0; {
244 case stat.Refill != 0:
245 refWidth = int(internal.PercentageRound(stat.Total, stat.Refill, uint(width)))
245246 curWidth -= refWidth
246247 refWidth += curWidth
248 fallthrough
249 default:
247250 for w := s.components[iFiller].width; curWidth-fillCount >= w; fillCount += w {
248251 filling = append(filling, s.components[iFiller].bytes...)
249252 }
250253 for w := s.components[iRefiller].width; refWidth-fillCount >= w; fillCount += w {
251254 refilling = append(refilling, s.components[iRefiller].bytes...)
252 }
253 } else {
254 for w := s.components[iFiller].width; curWidth-fillCount >= w; fillCount += w {
255 filling = append(filling, s.components[iFiller].bytes...)
256255 }
257256 }
258257 }
1919 return
2020 }
2121
22 // PrependDecorators let you inject decorators to the bar's left side.
23 func PrependDecorators(decorators ...decor.Decorator) BarOption {
24 decorators = inspect(decorators)
25 return func(s *bState) {
26 s.populateEwmaDecorators(decorators)
27 s.decorators[0] = decorators
28 }
29 }
30
2231 // AppendDecorators let you inject decorators to the bar's right side.
2332 func AppendDecorators(decorators ...decor.Decorator) BarOption {
2433 decorators = inspect(decorators)
2534 return func(s *bState) {
26 s.aDecorators = decorators
27 }
28 }
29
30 // PrependDecorators let you inject decorators to the bar's left side.
31 func PrependDecorators(decorators ...decor.Decorator) BarOption {
32 decorators = inspect(decorators)
33 return func(s *bState) {
34 s.pDecorators = decorators
35 s.populateEwmaDecorators(decorators)
36 s.decorators[1] = decorators
3537 }
3638 }
3739
111113 if filler == nil {
112114 return nil
113115 }
116 if f, ok := filler.(BarFillerFunc); ok && f == nil {
117 return nil
118 }
114119 fn := makeExtenderFunc(filler, rev)
115120 return func(s *bState) {
116121 s.extender = fn
119124
120125 func makeExtenderFunc(filler BarFiller, rev bool) extenderFunc {
121126 buf := new(bytes.Buffer)
122 base := func(rows []io.Reader, stat decor.Statistics) ([]io.Reader, error) {
127 base := func(stat decor.Statistics, rows ...io.Reader) ([]io.Reader, error) {
123128 err := filler.Fill(buf, stat)
124129 if err != nil {
125130 buf.Reset()
126131 return rows, err
127132 }
128133 for {
129 b, err := buf.ReadBytes('\n')
134 line, err := buf.ReadBytes('\n')
130135 if err != nil {
136 buf.Reset()
131137 break
132138 }
133 rows = append(rows, bytes.NewReader(b))
134 }
135 buf.Reset()
139 rows = append(rows, bytes.NewReader(line))
140 }
136141 return rows, err
137142 }
138
139143 if !rev {
140144 return base
141145 }
142 return func(rows []io.Reader, stat decor.Statistics) ([]io.Reader, error) {
143 rows, err := base(rows, stat)
146 return func(stat decor.Statistics, rows ...io.Reader) ([]io.Reader, error) {
147 rows, err := base(stat, rows...)
144148 if err != nil {
145149 return rows, err
146150 }
1919 bar := p.AddBar(int64(total))
2020
2121 if bar.Completed() {
22 t.Fail()
22 t.Error("expected bar not to complete")
2323 }
2424
2525 bar.IncrBy(total)
2626
2727 if !bar.Completed() {
28 t.Error("bar isn't completed after increment")
28 t.Error("expected bar to complete")
2929 }
3030
3131 p.Wait()
3737 bar := p.AddBar(int64(total))
3838
3939 if bar.Aborted() {
40 t.Fail()
40 t.Error("expected bar not to be aborted")
4141 }
4242
4343 bar.Abort(false)
4444
4545 if !bar.Aborted() {
46 t.Error("bar isn't aborted after abort call")
46 t.Error("expected bar to be aborted")
4747 }
4848
4949 p.Wait()
6666 p.Wait()
6767 }
6868
69 func TestBarEnableTriggerCompleteZeroBar(t *testing.T) {
70 p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(io.Discard))
71 bar := p.AddBar(0) // never complete bar
72
73 if bar.Completed() {
74 t.Error("expected bar not to complete")
75 }
76
77 // Calling bar.SetTotal(0, true) has same effect
78 // but this one is more concise and intuitive
79 bar.EnableTriggerComplete()
80
81 if !bar.Completed() {
82 t.Error("expected bar to complete")
83 }
84
85 p.Wait()
86 }
87
6988 func TestBarEnableTriggerCompleteAndIncrementBefore(t *testing.T) {
7089 p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(io.Discard))
7190 bar := p.AddBar(0) // never complete bar
91
92 targetTotal := int64(80)
7293
7394 for _, f := range []func(){
7495 func() { bar.SetTotal(40, false) },
7596 func() { bar.IncrBy(60) },
76 func() { bar.SetTotal(80, false) },
97 func() { bar.SetTotal(targetTotal, false) },
7798 func() { bar.IncrBy(20) },
7899 } {
79100 f()
80101 if bar.Completed() {
81 t.Fail()
102 t.Error("expected bar not to complete")
82103 }
83104 }
84105
85106 bar.EnableTriggerComplete()
86107
87108 if !bar.Completed() {
88 t.Fail()
109 t.Error("expected bar to complete")
110 }
111
112 if current := bar.Current(); current != targetTotal {
113 t.Errorf("Expected current: %d, got: %d", targetTotal, current)
89114 }
90115
91116 p.Wait()
94119 func TestBarEnableTriggerCompleteAndIncrementAfter(t *testing.T) {
95120 p := mpb.New(mpb.WithWidth(80), mpb.WithOutput(io.Discard))
96121 bar := p.AddBar(0) // never complete bar
122
123 targetTotal := int64(80)
97124
98125 for _, f := range []func(){
99126 func() { bar.SetTotal(40, false) },
100127 func() { bar.IncrBy(60) },
101 func() { bar.SetTotal(80, false) },
102 func() { bar.EnableTriggerComplete() },
128 func() { bar.SetTotal(targetTotal, false) },
129 func() { bar.EnableTriggerComplete() }, // disables any next SetTotal
130 func() { bar.SetTotal(100, true) }, // nop
103131 } {
104132 f()
105133 if bar.Completed() {
106 t.Fail()
134 t.Error("expected bar not to complete")
107135 }
108136 }
109137
110138 bar.IncrBy(20)
111139
112140 if !bar.Completed() {
113 t.Fail()
141 t.Error("expected bar to complete")
142 }
143
144 if current := bar.Current(); current != targetTotal {
145 t.Errorf("Expected current: %d, got: %d", targetTotal, current)
114146 }
115147
116148 p.Wait()
11
22 import (
33 "io"
4 "sync"
54 "testing"
65
76 "github.com/vbauerster/mpb/v8"
98
109 const total = 1000
1110
12 func BenchmarkNopStyle1Bar(b *testing.B) {
11 func BenchmarkNopStyleB1(b *testing.B) {
1312 bench(b, mpb.NopStyle(), false, 1)
1413 }
1514
16 func BenchmarkNopStyle1BarWithAutoRefresh(b *testing.B) {
15 func BenchmarkNopStyleWithAutoRefreshB1(b *testing.B) {
1716 bench(b, mpb.NopStyle(), true, 1)
1817 }
1918
20 func BenchmarkNopStyle2Bars(b *testing.B) {
19 func BenchmarkNopStylesB2(b *testing.B) {
2120 bench(b, mpb.NopStyle(), false, 2)
2221 }
2322
24 func BenchmarkNopStyle2BarsWithAutoRefresh(b *testing.B) {
23 func BenchmarkNopStylesWithAutoRefreshB2(b *testing.B) {
2524 bench(b, mpb.NopStyle(), true, 2)
2625 }
2726
28 func BenchmarkNopStyle3Bars(b *testing.B) {
27 func BenchmarkNopStylesB3(b *testing.B) {
2928 bench(b, mpb.NopStyle(), false, 3)
3029 }
3130
32 func BenchmarkNopStyle3BarsWithAutoRefresh(b *testing.B) {
31 func BenchmarkNopStylesWithAutoRefreshB3(b *testing.B) {
3332 bench(b, mpb.NopStyle(), true, 3)
3433 }
3534
36 func BenchmarkBarStyle1Bar(b *testing.B) {
35 func BenchmarkBarStyleB1(b *testing.B) {
3736 bench(b, mpb.BarStyle(), false, 1)
3837 }
3938
40 func BenchmarkBarStyle1BarWithAutoRefresh(b *testing.B) {
39 func BenchmarkBarStyleWithAutoRefreshB1(b *testing.B) {
4140 bench(b, mpb.BarStyle(), true, 1)
4241 }
4342
44 func BenchmarkBarStyle2Bars(b *testing.B) {
43 func BenchmarkBarStylesB2(b *testing.B) {
4544 bench(b, mpb.BarStyle(), false, 2)
4645 }
4746
48 func BenchmarkBarStyle2BarsWithAutoRefresh(b *testing.B) {
47 func BenchmarkBarStylesWithAutoRefreshB2(b *testing.B) {
4948 bench(b, mpb.BarStyle(), true, 2)
5049 }
5150
52 func BenchmarkBarStyle3Bars(b *testing.B) {
51 func BenchmarkBarStylesB3(b *testing.B) {
5352 bench(b, mpb.BarStyle(), false, 3)
5453 }
5554
56 func BenchmarkBarStyle3BarsWithAutoRefresh(b *testing.B) {
55 func BenchmarkBarStylesWithAutoRefreshB3(b *testing.B) {
5756 bench(b, mpb.BarStyle(), true, 3)
5857 }
5958
6059 func bench(b *testing.B, builder mpb.BarFillerBuilder, autoRefresh bool, n int) {
61 var wg sync.WaitGroup
6260 p := mpb.New(
6361 mpb.WithWidth(100),
6462 mpb.WithOutput(io.Discard),
6563 mpb.ContainerOptional(mpb.WithAutoRefresh(), autoRefresh),
6664 )
65 defer p.Wait()
6766 b.ResetTimer()
6867 for i := 0; i < b.N; i++ {
68 var bars []*mpb.Bar
6969 for j := 0; j < n; j++ {
70 bar := p.New(total, builder)
70 bars = append(bars, p.New(total, builder))
7171 switch j {
7272 case n - 1:
73 complete(b, bar)
73 complete(bars[j])
7474 default:
75 wg.Add(1)
76 go func() {
77 complete(b, bar)
78 wg.Done()
79 }()
75 go complete(bars[j])
8076 }
8177 }
82 wg.Wait()
78 for _, bar := range bars {
79 bar.Wait()
80 }
8381 }
84 p.Wait()
8582 }
8683
87 func complete(b *testing.B, bar *mpb.Bar) {
84 func complete(bar *mpb.Bar) {
8885 for i := 0; i < total; i++ {
8986 bar.Increment()
9087 }
91 bar.Wait()
9288 }
9292 }
9393 }
9494
95 // PopCompletedMode will pop completed bars to the top.
96 // To stop rendering bar after it has been popped, use
97 // mpb.BarRemoveOnComplete() option on that bar.
95 // PopCompletedMode pop completed bars out of progress container.
96 // In this mode completed bars get moved to the top and stop
97 // participating in rendering cycle.
9898 func PopCompletedMode() ContainerOption {
9999 return func(s *pState) {
100100 s.popCompleted = true
0 golang-github-vbauerster-mpb (8.8.2-1) experimental; urgency=medium
1
2 * Team upload
3 * New upstream version: v8.8.3
4
5 -- Reinhard Tartler <siretart@tauware.de> Sat, 09 Nov 2024 11:06:55 -0500
6
07 golang-github-vbauerster-mpb (8.6.1-3) unstable; urgency=medium
18
29 * Add golang-github-containers-image (<< 5.25)
77 )
88
99 const (
10 // DidentRight bit specifies identation direction.
10 // DindentRight sets indentation from right to left.
1111 //
12 // |foo |b | With DidentRight
13 // | foo| b| Without DidentRight
14 DidentRight = 1 << iota
12 // |foo |b | DindentRight is set
13 // | foo| b| DindentRight is not set
14 DindentRight = 1 << iota
1515
16 // DextraSpace bit adds extra space, makes sense with DSyncWidth only.
17 // When DidentRight bit set, the space will be added to the right,
18 // otherwise to the left.
16 // DextraSpace bit adds extra indentation space.
1917 DextraSpace
2018
2119 // DSyncWidth bit enables same column width synchronization.
2220 // Effective with multiple bars only.
2321 DSyncWidth
2422
25 // DSyncWidthR is shortcut for DSyncWidth|DidentRight
26 DSyncWidthR = DSyncWidth | DidentRight
23 // DSyncWidthR is shortcut for DSyncWidth|DindentRight
24 DSyncWidthR = DSyncWidth | DindentRight
2725
2826 // DSyncSpace is shortcut for DSyncWidth|DextraSpace
2927 DSyncSpace = DSyncWidth | DextraSpace
3028
31 // DSyncSpaceR is shortcut for DSyncWidth|DextraSpace|DidentRight
32 DSyncSpaceR = DSyncWidth | DextraSpace | DidentRight
29 // DSyncSpaceR is shortcut for DSyncWidth|DextraSpace|DindentRight
30 DSyncSpaceR = DSyncWidth | DextraSpace | DindentRight
3331 )
3432
3533 // TimeStyle enum.
8684 // in order to format string according to decor.WC settings.
8785 // No need to implement manually as long as decor.WC is embedded.
8886 type Formatter interface {
89 Format(string) (str string, viewWidth int)
87 Format(string) (_ string, width int)
9088 }
9189
9290 // Wrapper interface.
139137 // Format should be called by any Decorator implementation.
140138 // Returns formatted string and its view (visual) width.
141139 func (wc WC) Format(str string) (string, int) {
142 viewWidth := runewidth.StringWidth(str)
143 if wc.W > viewWidth {
144 viewWidth = wc.W
140 width := runewidth.StringWidth(str)
141 if wc.W > width {
142 width = wc.W
143 } else if (wc.C & DextraSpace) != 0 {
144 width++
145145 }
146146 if (wc.C & DSyncWidth) != 0 {
147 if (wc.C & DextraSpace) != 0 {
148 viewWidth++
149 }
150 wc.wsync <- viewWidth
151 viewWidth = <-wc.wsync
147 wc.wsync <- width
148 width = <-wc.wsync
152149 }
153 return wc.fill(str, viewWidth), viewWidth
150 return wc.fill(str, width), width
154151 }
155152
156153 // Init initializes width related config.
157154 func (wc *WC) Init() WC {
158 if (wc.C & DidentRight) != 0 {
155 if (wc.C & DindentRight) != 0 {
159156 wc.fill = runewidth.FillRight
160157 } else {
161158 wc.fill = runewidth.FillLeft
1616 //
1717 // `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS]
1818 //
19 // `startTime` start time
19 // `start` start time
2020 //
2121 // `wcc` optional WC config
22 func NewElapsed(style TimeStyle, startTime time.Time, wcc ...WC) Decorator {
22 func NewElapsed(style TimeStyle, start time.Time, wcc ...WC) Decorator {
2323 var msg string
2424 producer := chooseTimeProducer(style)
2525 fn := func(s Statistics) string {
26 if !s.Completed {
27 msg = producer(time.Since(startTime))
26 if !s.Completed && !s.Aborted {
27 msg = producer(time.Since(start))
2828 }
2929 return msg
3030 }
3232 // decorator to work correctly you have to measure each iteration's duration
3333 // and pass it to one of the (*Bar).EwmaIncr... family methods.
3434 func EwmaETA(style TimeStyle, age float64, wcc ...WC) Decorator {
35 return EwmaNormalizedETA(style, age, nil, wcc...)
36 }
37
38 // EwmaNormalizedETA same as EwmaETA but with TimeNormalizer option.
39 func EwmaNormalizedETA(style TimeStyle, age float64, normalizer TimeNormalizer, wcc ...WC) Decorator {
3540 var average ewma.MovingAverage
3641 if age == 0 {
3742 average = ewma.NewMovingAverage()
3843 } else {
3944 average = ewma.NewMovingAverage(age)
4045 }
41 return MovingAverageETA(style, NewThreadSafeMovingAverage(average), nil, wcc...)
46 return MovingAverageETA(style, average, normalizer, wcc...)
4247 }
4348
4449 // MovingAverageETA decorator relies on MovingAverage implementation to calculate its average.
5156 //
5257 // `wcc` optional WC config
5358 func MovingAverageETA(style TimeStyle, average ewma.MovingAverage, normalizer TimeNormalizer, wcc ...WC) Decorator {
59 if average == nil {
60 average = NewMedian()
61 }
5462 d := &movingAverageETA{
5563 WC: initWC(wcc...),
64 producer: chooseTimeProducer(style),
5665 average: average,
5766 normalizer: normalizer,
58 producer: chooseTimeProducer(style),
5967 }
6068 return d
6169 }
6270
6371 type movingAverageETA struct {
6472 WC
73 producer func(time.Duration) string
6574 average ewma.MovingAverage
6675 normalizer TimeNormalizer
67 producer func(time.Duration) string
76 zDur time.Duration
6877 }
6978
7079 func (d *movingAverageETA) Decor(s Statistics) (string, int) {
7786 }
7887
7988 func (d *movingAverageETA) EwmaUpdate(n int64, dur time.Duration) {
80 durPerItem := float64(dur) / float64(n)
89 if n <= 0 {
90 d.zDur += dur
91 return
92 }
93 durPerItem := float64(d.zDur+dur) / float64(n)
8194 if math.IsInf(durPerItem, 0) || math.IsNaN(durPerItem) {
95 d.zDur += dur
8296 return
8397 }
98 d.zDur = 0
8499 d.average.Add(durPerItem)
85100 }
86101
97112 //
98113 // `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS]
99114 //
100 // `startTime` start time
115 // `start` start time
101116 //
102117 // `normalizer` available implementations are [FixedIntervalTimeNormalizer|MaxTolerateTimeNormalizer]
103118 //
104119 // `wcc` optional WC config
105 func NewAverageETA(style TimeStyle, startTime time.Time, normalizer TimeNormalizer, wcc ...WC) Decorator {
120 func NewAverageETA(style TimeStyle, start time.Time, normalizer TimeNormalizer, wcc ...WC) Decorator {
106121 d := &averageETA{
107122 WC: initWC(wcc...),
108 startTime: startTime,
123 start: start,
109124 normalizer: normalizer,
110125 producer: chooseTimeProducer(style),
111126 }
114129
115130 type averageETA struct {
116131 WC
117 startTime time.Time
132 start time.Time
118133 normalizer TimeNormalizer
119134 producer func(time.Duration) string
120135 }
122137 func (d *averageETA) Decor(s Statistics) (string, int) {
123138 var remaining time.Duration
124139 if s.Current != 0 {
125 durPerItem := float64(time.Since(d.startTime)) / float64(s.Current)
140 durPerItem := float64(time.Since(d.start)) / float64(s.Current)
126141 durPerItem = math.Round(durPerItem)
127142 remaining = time.Duration((s.Total - s.Current) * int64(durPerItem))
128143 if d.normalizer != nil {
132147 return d.Format(d.producer(remaining))
133148 }
134149
135 func (d *averageETA) AverageAdjust(startTime time.Time) {
136 d.startTime = startTime
150 func (d *averageETA) AverageAdjust(start time.Time) {
151 d.start = start
137152 }
138153
139154 // MaxTolerateTimeNormalizer returns implementation of TimeNormalizer.
6969
7070 // NewMedian is fixed last 3 samples median MovingAverage.
7171 func NewMedian() ewma.MovingAverage {
72 return NewThreadSafeMovingAverage(new(medianWindow))
72 return new(medianWindow)
7373 }
5555 }
5656
5757 func (d onAbortMetaWrapper) Decor(s Statistics) (string, int) {
58 if s.Completed {
58 if s.Aborted {
5959 str, width := d.Decorator.Decor(s)
6060 return d.fn(str), width
6161 }
6060 format = "% d"
6161 }
6262 f := func(s Statistics) string {
63 p := internal.Percentage(s.Total, s.Current, 100)
63 p := internal.Percentage(uint(s.Total), uint(s.Current), 100)
6464 return fmt.Sprintf(format, percentageType(p))
6565 }
6666 return Any(f, wcc...)
5555 })
5656 }
5757 }
58
59 func TestPercentageDecor(t *testing.T) {
60 cases := []struct {
61 name string
62 fmt string
63 current int64
64 total int64
65 expected string
66 }{
67 {
68 name: "tot:100 cur:0 fmt:none",
69 fmt: "",
70 current: 0,
71 total: 100,
72 expected: "0 %",
73 },
74 {
75 name: "tot:100 cur:10 fmt:none",
76 fmt: "",
77 current: 10,
78 total: 100,
79 expected: "10 %",
80 },
81 {
82 name: "tot:100 cur:10 fmt:%.2f",
83 fmt: "%.2f",
84 current: 10,
85 total: 100,
86 expected: "10.00%",
87 },
88 {
89 name: "tot:99 cur:10 fmt:%.2f",
90 fmt: "%.2f",
91 current: 11,
92 total: 99,
93 expected: "11.11%",
94 },
95 }
96 for _, tc := range cases {
97 t.Run(tc.name, func(t *testing.T) {
98 decor := NewPercentage(tc.fmt)
99 stat := Statistics{
100 Total: tc.total,
101 Current: tc.current,
102 }
103 res, _ := decor.Decor(stat)
104 if res != tc.expected {
105 t.Fatalf("expected: %q, got: %q\n", tc.expected, res)
106 }
107 })
108 }
109 }
2020 //
2121 // fmt.Printf("%.1f", FmtAsSpeed(SizeB1024(2048)))
2222 func FmtAsSpeed(input fmt.Formatter) fmt.Formatter {
23 return speedFormatter{input}
23 return &speedFormatter{input}
2424 }
2525
2626 type speedFormatter struct {
2727 fmt.Formatter
2828 }
2929
30 func (self speedFormatter) Format(st fmt.State, verb rune) {
31 self.Formatter.Format(st, verb)
30 func (s *speedFormatter) Format(st fmt.State, verb rune) {
31 s.Formatter.Format(st, verb)
3232 _, err := io.WriteString(st, "/s")
3333 if err != nil {
3434 panic(err)
4545 } else {
4646 average = ewma.NewMovingAverage(age)
4747 }
48 return MovingAverageSpeed(unit, format, NewThreadSafeMovingAverage(average), wcc...)
48 return MovingAverageSpeed(unit, format, average, wcc...)
4949 }
5050
5151 // MovingAverageSpeed decorator relies on MovingAverage implementation
6868 func MovingAverageSpeed(unit interface{}, format string, average ewma.MovingAverage, wcc ...WC) Decorator {
6969 d := &movingAverageSpeed{
7070 WC: initWC(wcc...),
71 producer: chooseSpeedProducer(unit, format),
7172 average: average,
72 producer: chooseSpeedProducer(unit, format),
7373 }
7474 return d
7575 }
7878 WC
7979 producer func(float64) string
8080 average ewma.MovingAverage
81 msg string
81 zDur time.Duration
8282 }
8383
84 func (d *movingAverageSpeed) Decor(s Statistics) (string, int) {
85 if !s.Completed {
86 var speed float64
87 if v := d.average.Value(); v > 0 {
88 speed = 1 / v
89 }
90 d.msg = d.producer(speed * 1e9)
84 func (d *movingAverageSpeed) Decor(_ Statistics) (string, int) {
85 var str string
86 // ewma implementation may return 0 before accumulating certain number of samples
87 if v := d.average.Value(); v != 0 {
88 str = d.producer(1e9 / v)
89 } else {
90 str = d.producer(0)
9191 }
92 return d.Format(d.msg)
92 return d.Format(str)
9393 }
9494
9595 func (d *movingAverageSpeed) EwmaUpdate(n int64, dur time.Duration) {
96 durPerByte := float64(dur) / float64(n)
97 if math.IsInf(durPerByte, 0) || math.IsNaN(durPerByte) {
96 if n <= 0 {
97 d.zDur += dur
9898 return
9999 }
100 durPerByte := float64(d.zDur+dur) / float64(n)
101 if math.IsInf(durPerByte, 0) || math.IsNaN(durPerByte) {
102 d.zDur += dur
103 return
104 }
105 d.zDur = 0
100106 d.average.Add(durPerByte)
101107 }
102108
113119 //
114120 // `format` printf compatible verb for value, like "%f" or "%d"
115121 //
116 // `startTime` start time
122 // `start` start time
117123 //
118124 // `wcc` optional WC config
119125 //
123129 // unit=SizeB1024(0), format="% .1f" output: "1.0 MiB/s"
124130 // unit=SizeB1000(0), format="%.1f" output: "1.0MB/s"
125131 // unit=SizeB1000(0), format="% .1f" output: "1.0 MB/s"
126 func NewAverageSpeed(unit interface{}, format string, startTime time.Time, wcc ...WC) Decorator {
132 func NewAverageSpeed(unit interface{}, format string, start time.Time, wcc ...WC) Decorator {
127133 d := &averageSpeed{
128 WC: initWC(wcc...),
129 startTime: startTime,
130 producer: chooseSpeedProducer(unit, format),
134 WC: initWC(wcc...),
135 start: start,
136 producer: chooseSpeedProducer(unit, format),
131137 }
132138 return d
133139 }
134140
135141 type averageSpeed struct {
136142 WC
137 startTime time.Time
138 producer func(float64) string
139 msg string
143 start time.Time
144 producer func(float64) string
145 msg string
140146 }
141147
142148 func (d *averageSpeed) Decor(s Statistics) (string, int) {
143149 if !s.Completed {
144 speed := float64(s.Current) / float64(time.Since(d.startTime))
150 speed := float64(s.Current) / float64(time.Since(d.start))
145151 d.msg = d.producer(speed * 1e9)
146152 }
147153 return d.Format(d.msg)
148154 }
149155
150 func (d *averageSpeed) AverageAdjust(startTime time.Time) {
151 d.startTime = startTime
156 func (d *averageSpeed) AverageAdjust(start time.Time) {
157 d.start = start
152158 }
153159
154160 func chooseSpeedProducer(unit interface{}, format string) func(float64) string {
2424 want: " Test",
2525 },
2626 {
27 decorator: decor.Name("Test", decor.WC{W: 10, C: decor.DidentRight}),
27 decorator: decor.Name("Test", decor.WC{W: 10, C: decor.DindentRight}),
2828 want: "Test ",
2929 },
3030 }
8787 testDecoratorConcurrently(t, testCases)
8888 }
8989
90 func TestPercentageDwidthSyncDidentRight(t *testing.T) {
90 func TestPercentageDwidthSyncDindentRight(t *testing.T) {
9191
9292 testCases := [][]step{
9393 {
621621 want: " [>-----------------------------------------------------------------------------------------------] ",
622622 },
623623 {
624 style: BarStyle().Tip(""),
625 name: "t,c{100,1}empty_tip",
626 total: 100,
627 current: 1,
628 want: " [=-----------------------------------------------------------------------------------------------] ",
629 },
630 {
624631 style: BarStyle(),
625632 name: "t,c{100,1}trim",
626633 total: 100,
634641 total: 100,
635642 current: 99,
636643 want: " [==============================================================================================>-] ",
644 },
645 {
646 style: BarStyle().Tip(""),
647 name: "t,c{100,99}empty_tip",
648 total: 100,
649 current: 99,
650 want: " [===============================================================================================-] ",
637651 },
638652 {
639653 style: BarStyle(),
766780 var tmpBuf bytes.Buffer
767781 for tw, cases := range testSuite {
768782 for _, tc := range cases {
769 s := newTestState(tc.style.Build())
770 s.reqWidth = tc.barWidth
771 s.total = tc.total
783 ps := pState{reqWidth: tc.barWidth}
784 s := ps.makeBarState(tc.total, tc.style.Build())
772785 s.current = tc.current
773786 s.trimSpace = tc.trim
774787 s.refill = tc.refill
775 s.completed = tc.total > 0 && tc.current >= tc.total
788 r, err := s.draw(s.newStatistics(tw))
789 if err != nil {
790 t.Fatalf("tw: %d case %q draw error: %s", tw, tc.name, err.Error())
791 }
776792 tmpBuf.Reset()
777 r, err := s.draw(newStatistics(tw, s))
778 if err != nil {
779 t.FailNow()
780 }
781793 _, err = tmpBuf.ReadFrom(r)
782794 if err != nil {
783795 t.FailNow()
784796 }
785797 by := tmpBuf.Bytes()
786
787798 got := string(by[:len(by)-1])
788799 if !utf8.ValidString(got) {
789800 t.Fail()
12211232 var tmpBuf bytes.Buffer
12221233 for tw, cases := range testSuite {
12231234 for _, tc := range cases {
1224 s := newTestState(tc.style.Build())
1225 s.reqWidth = tc.barWidth
1226 s.total = tc.total
1235 ps := pState{reqWidth: tc.barWidth}
1236 s := ps.makeBarState(tc.total, tc.style.Build())
12271237 s.current = tc.current
12281238 s.trimSpace = tc.trim
12291239 s.refill = tc.refill
1230 s.completed = tc.total > 0 && tc.current >= tc.total
1240 r, err := s.draw(s.newStatistics(tw))
1241 if err != nil {
1242 t.Fatalf("tw: %d case %q draw error: %s", tw, tc.name, err.Error())
1243 }
12311244 tmpBuf.Reset()
1232 r, err := s.draw(newStatistics(tw, s))
1233 if err != nil {
1234 t.FailNow()
1235 }
12361245 _, err = tmpBuf.ReadFrom(r)
12371246 if err != nil {
12381247 t.FailNow()
13981407 var tmpBuf bytes.Buffer
13991408 for tw, cases := range testSuite {
14001409 for _, tc := range cases {
1401 s := newTestState(tc.style.Build())
1402 s.reqWidth = tc.barWidth
1403 s.total = tc.total
1410 ps := pState{reqWidth: tc.barWidth}
1411 s := ps.makeBarState(tc.total, tc.style.Build())
14041412 s.current = tc.current
14051413 s.trimSpace = tc.trim
14061414 s.refill = tc.refill
1407 s.completed = tc.total > 0 && tc.current >= tc.total
1415 r, err := s.draw(s.newStatistics(tw))
1416 if err != nil {
1417 t.Fatalf("tw: %d case %q draw error: %s", tw, tc.name, err.Error())
1418 }
14081419 tmpBuf.Reset()
1409 r, err := s.draw(newStatistics(tw, s))
1410 if err != nil {
1411 t.FailNow()
1412 }
14131420 _, err = tmpBuf.ReadFrom(r)
14141421 if err != nil {
14151422 t.FailNow()
14261433 }
14271434 }
14281435 }
1429
1430 func newTestState(filler BarFiller) *bState {
1431 bs := &bState{
1432 filler: filler,
1433 }
1434 for i := 0; i < len(bs.buffers); i++ {
1435 bs.buffers[i] = bytes.NewBuffer(make([]byte, 0, 512))
1436 }
1437 return bs
1438 }
2121 mpb.BarStyle().Lbound("╢").Filler("▌").Tip("▌").Padding("░").Rbound("╟"),
2222 mpb.PrependDecorators(
2323 // display our name with one space on the right
24 decor.Name(name, decor.WC{W: len(name) + 1, C: decor.DidentRight}),
24 decor.Name(name, decor.WC{C: decor.DindentRight | decor.DextraSpace}),
2525 // replace ETA decorator with "done" message, OnComplete event
26 decor.OnComplete(
27 decor.AverageETA(decor.ET_STYLE_GO, decor.WC{W: 4}), "done",
28 ),
26 decor.OnComplete(decor.AverageETA(decor.ET_STYLE_GO), "done"),
2927 ),
3028 mpb.AppendDecorators(decor.Percentage()),
3129 )
22 require (
33 github.com/VividCortex/ewma v1.2.0
44 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
5 github.com/mattn/go-runewidth v0.0.15
6 golang.org/x/sys v0.11.0
5 github.com/mattn/go-runewidth v0.0.16
6 golang.org/x/sys v0.24.0
77 )
88
9 require github.com/rivo/uniseg v0.4.4 // indirect
9 require github.com/rivo/uniseg v0.4.7 // indirect
1010
1111 go 1.17
11 github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
22 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
33 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
4 github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
5 github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
4 github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
5 github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
66 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
7 github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
8 github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
9 golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
10 golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
7 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
8 github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
9 golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
10 golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
22 import "math"
33
44 // Percentage is a helper function, to calculate percentage.
5 func Percentage(total, current int64, width uint) float64 {
6 if total <= 0 {
5 func Percentage(total, current, width uint) float64 {
6 if total == 0 {
77 return 0
88 }
99 if current >= total {
1010 return float64(width)
1111 }
12 return float64(int64(width)*current) / float64(total)
12 return float64(width*current) / float64(total)
1313 }
1414
1515 // PercentageRound same as Percentage but with math.Round.
1616 func PercentageRound(total, current int64, width uint) float64 {
17 return math.Round(Percentage(total, current, width))
17 if total < 0 || current < 0 {
18 return 0
19 }
20 return math.Round(Percentage(uint(total), uint(current), width))
1821 }
22 // CheckRequestedWidth checks that requested width doesn't overflow
33 // available width
44 func CheckRequestedWidth(requested, available int) int {
5 if requested < 1 || requested >= available {
5 if requested < 1 || requested > available {
66 return available
77 }
88 return requested
1313 "github.com/vbauerster/mpb/v8/decor"
1414 )
1515
16 const (
17 defaultRefreshRate = 150 * time.Millisecond
18 )
19
20 // DoneError represents an error when `*mpb.Progress` is done but its functionality is requested.
21 var DoneError = fmt.Errorf("%T instance can't be reused after it's done", (*Progress)(nil))
16 const defaultRefreshRate = 150 * time.Millisecond
17
18 // DoneError represents use after `(*Progress).Wait()` error.
19 var DoneError = fmt.Errorf("%T instance can't be reused after %[1]T.Wait()", (*Progress)(nil))
2220
2321 // Progress represents a container that renders one or more progress bars.
2422 type Progress struct {
5452 }
5553
5654 // New creates new Progress container instance. It's not possible to
57 // reuse instance after (*Progress).Wait method has been called.
55 // reuse instance after `(*Progress).Wait` method has been called.
5856 func New(options ...ContainerOption) *Progress {
5957 return NewWithContext(context.Background(), options...)
6058 }
6159
6260 // NewWithContext creates new Progress container instance with provided
63 // context. It's not possible to reuse instance after (*Progress).Wait
61 // context. It's not possible to reuse instance after `(*Progress).Wait`
6462 // method has been called.
6563 func NewWithContext(ctx context.Context, options ...ContainerOption) *Progress {
6664 if ctx == nil {
7371 dropS: make(chan struct{}),
7472 dropD: make(chan struct{}),
7573 renderReq: make(chan time.Time),
74 popPriority: math.MinInt32,
7675 refreshRate: defaultRefreshRate,
77 popPriority: math.MinInt32,
7876 queueBars: make(map[*Bar]*Bar),
7977 output: os.Stdout,
8078 debugOut: io.Discard,
127125
128126 // New creates a bar by calling `Build` method on provided `BarFillerBuilder`.
129127 func (p *Progress) New(total int64, builder BarFillerBuilder, options ...BarOption) *Bar {
128 if builder == nil {
129 return p.MustAdd(total, nil, options...)
130 }
130131 return p.MustAdd(total, builder.Build(), options...)
131132 }
132133
133134 // MustAdd creates a bar which renders itself by provided BarFiller.
134135 // If `total <= 0` triggering complete event by increment methods is
135 // disabled. Panics if *Progress instance is done, i.e. called after
136 // (*Progress).Wait().
136 // disabled. Panics if called after `(*Progress).Wait()`.
137137 func (p *Progress) MustAdd(total int64, filler BarFiller, options ...BarOption) *Bar {
138138 bar, err := p.Add(total, filler, options...)
139139 if err != nil {
144144
145145 // Add creates a bar which renders itself by provided BarFiller.
146146 // If `total <= 0` triggering complete event by increment methods
147 // is disabled. If *Progress instance is done, i.e. called after
148 // (*Progress).Wait(), return error == DoneError.
147 // is disabled. If called after `(*Progress).Wait()` then
148 // `(nil, DoneError)` is returned.
149149 func (p *Progress) Add(total int64, filler BarFiller, options ...BarOption) (*Bar, error) {
150150 if filler == nil {
151151 filler = NopStyle().Build()
152 }
153 type result struct {
154 bar *Bar
155 bs *bState
156 }
157 ch := make(chan result)
152 } else if f, ok := filler.(BarFillerFunc); ok && f == nil {
153 filler = NopStyle().Build()
154 }
155 ch := make(chan *Bar)
158156 select {
159157 case p.operateState <- func(ps *pState) {
160158 bs := ps.makeBarState(total, filler, options...)
165163 ps.hm.push(bar, true)
166164 }
167165 ps.idCount++
168 ch <- result{bar, bs}
166 ch <- bar
169167 }:
170 res := <-ch
171 bar, bs := res.bar, res.bs
172 bar.TraverseDecorators(func(d decor.Decorator) {
173 if d, ok := d.(decor.AverageDecorator); ok {
174 bs.averageDecorators = append(bs.averageDecorators, d)
175 }
176 if d, ok := d.(decor.EwmaDecorator); ok {
177 bs.ewmaDecorators = append(bs.ewmaDecorators, d)
178 }
179 if d, ok := d.(decor.ShutdownListener); ok {
180 bs.shutdownListeners = append(bs.shutdownListeners, d)
181 }
182 })
183 return bar, nil
168 return <-ch, nil
184169 case <-p.done:
185170 return nil, DoneError
186171 }
191176 select {
192177 case p.operateState <- func(s *pState) { s.hm.iter(iter, drop) }:
193178 for b := range iter {
194 if cb(b) {
179 if !cb(b) {
195180 close(drop)
196181 break
197182 }
202187
203188 // UpdateBarPriority either immediately or lazy.
204189 // With lazy flag order is updated after the next refresh cycle.
205 // If you don't care about laziness just use *Bar.SetPriority(int).
190 // If you don't care about laziness just use `(*Bar).SetPriority(int)`.
206191 func (p *Progress) UpdateBarPriority(b *Bar, priority int, lazy bool) {
207192 if b == nil {
208193 return
214199 }
215200
216201 // Write is implementation of io.Writer.
217 // Writing to `*mpb.Progress` will print lines above a running bar.
202 // Writing to `*Progress` will print lines above a running bar.
218203 // Writes aren't flushed immediately, but at next refresh cycle.
219 // If Write is called after `*mpb.Progress` is done, `mpb.DoneError`
204 // If called after `(*Progress).Wait()` then `(0, DoneError)`
220205 // is returned.
221206 func (p *Progress) Write(b []byte) (int, error) {
222207 type result struct {
237222 }
238223
239224 // Wait waits for all bars to complete and finally shutdowns container. After
240 // this method has been called, there is no way to reuse (*Progress) instance.
225 // this method has been called, there is no way to reuse `*Progress` instance.
241226 func (p *Progress) Wait() {
227 p.bwg.Wait()
228 p.Shutdown()
242229 // wait for user wg, if any
243230 if p.uwg != nil {
244231 p.uwg.Wait()
245232 }
246
247 p.bwg.Wait()
248 p.Shutdown()
249 }
250
251 // Shutdown cancels any running bar immediately and then shutdowns (*Progress)
233 }
234
235 // Shutdown cancels any running bar immediately and then shutdowns `*Progress`
252236 // instance. Normally this method shouldn't be called unless you know what you
253 // are doing. Proper way to shutdown is to call (*Progress).Wait() instead.
237 // are doing. Proper way to shutdown is to call `(*Progress).Wait()` instead.
254238 func (p *Progress) Shutdown() {
255239 p.cancel()
256240 p.pwg.Wait()
258242
259243 func (p *Progress) serve(s *pState, cw *cwriter.Writer) {
260244 defer p.pwg.Done()
261 render := func() error { return s.render(cw) }
262245 var err error
246 var w *cwriter.Writer
247 renderReq := s.renderReq
248 operateState := p.operateState
249 interceptIO := p.interceptIO
250
251 if s.delayRC != nil {
252 w = cwriter.New(io.Discard)
253 } else {
254 w, cw = cw, nil
255 }
263256
264257 for {
265258 select {
266 case op := <-p.operateState:
259 case <-s.delayRC:
260 w, cw = cw, nil
261 s.delayRC = nil
262 case op := <-operateState:
267263 op(s)
268 case fn := <-p.interceptIO:
269 fn(cw)
270 case <-s.renderReq:
271 e := render()
272 if e != nil {
264 case fn := <-interceptIO:
265 fn(w)
266 case <-renderReq:
267 err = s.render(w)
268 if err != nil {
269 // (*pState).(autoRefreshListener|manualRefreshListener) may block
270 // if not launching following short lived goroutine
271 go func() {
272 for {
273 select {
274 case <-s.renderReq:
275 case <-p.done:
276 return
277 }
278 }
279 }()
273280 p.cancel() // cancel all bars
274 render = func() error { return nil }
275 err = e
281 renderReq = nil
282 operateState = nil
283 interceptIO = nil
276284 }
277285 case <-p.done:
278 update := make(chan bool)
279 for s.autoRefresh && err == nil {
280 s.hm.state(update)
281 if <-update {
282 err = render()
283 } else {
284 break
285 }
286 }
287286 if err != nil {
288287 _, _ = fmt.Fprintln(s.debugOut, err.Error())
288 } else if s.autoRefresh {
289 update := make(chan bool)
290 for i := 0; i == 0 || <-update; i++ {
291 if err := s.render(w); err != nil {
292 _, _ = fmt.Fprintln(s.debugOut, err.Error())
293 break
294 }
295 s.hm.state(update)
296 }
289297 }
290298 s.hm.end(s.shutdownNotifier)
291299 return
293301 }
294302 }
295303
296 func (s pState) autoRefreshListener(done chan struct{}) {
297 if s.delayRC != nil {
298 <-s.delayRC
299 }
304 func (s *pState) autoRefreshListener(done chan struct{}) {
300305 ticker := time.NewTicker(s.refreshRate)
301306 defer ticker.Stop()
302307 for {
310315 }
311316 }
312317
313 func (s pState) manualRefreshListener(done chan struct{}) {
318 func (s *pState) manualRefreshListener(done chan struct{}) {
314319 for {
315320 select {
316321 case x := <-s.manualRC:
342347 if s.reqWidth > 0 {
343348 width = s.reqWidth
344349 } else {
345 width = 100
346 }
347 height = 100
350 width = 80
351 }
352 height = width
348353 }
349354
350355 for b := range iter {
356361
357362 func (s *pState) flush(cw *cwriter.Writer, height int) error {
358363 var wg sync.WaitGroup
359 defer wg.Wait() // waiting for all s.hm.push to complete
364 defer wg.Wait() // waiting for all s.push to complete
360365
361366 var popCount int
362367 var rows []io.Reader
380385 _, _ = io.Copy(io.Discard, row)
381386 }
382387 }
383 if frame.shutdown != 0 && !frame.done {
388
389 switch frame.shutdown {
390 case 1:
391 b.cancel()
384392 if qb, ok := s.queueBars[b]; ok {
385 b.cancel()
386393 delete(s.queueBars, b)
387394 qb.priority = b.priority
388395 wg.Add(1)
389 go func(b *Bar) {
390 s.hm.push(b, true)
391 wg.Done()
392 }(qb)
396 go s.push(&wg, qb, true)
397 } else if s.popCompleted && !frame.noPop {
398 b.priority = s.popPriority
399 s.popPriority++
400 wg.Add(1)
401 go s.push(&wg, b, false)
402 } else if !frame.rmOnComplete {
403 wg.Add(1)
404 go s.push(&wg, b, false)
405 }
406 case 2:
407 if s.popCompleted && !frame.noPop {
408 popCount += usedRows
393409 continue
394410 }
395 if s.popCompleted && !frame.noPop {
396 switch frame.shutdown {
397 case 1:
398 b.priority = s.popPriority
399 s.popPriority++
400 default:
401 b.cancel()
402 popCount += usedRows
403 continue
404 }
405 } else if frame.rmOnComplete {
406 b.cancel()
407 continue
408 } else {
409 b.cancel()
410 }
411 }
412 wg.Add(1)
413 go func(b *Bar) {
414 s.hm.push(b, false)
415 wg.Done()
416 }(b)
411 fallthrough
412 default:
413 wg.Add(1)
414 go s.push(&wg, b, false)
415 }
417416 }
418417
419418 for i := len(rows) - 1; i >= 0; i-- {
424423 }
425424
426425 return cw.Flush(len(rows) - popCount)
426 }
427
428 func (s *pState) push(wg *sync.WaitGroup, b *Bar, sync bool) {
429 s.hm.push(b, sync)
430 wg.Done()
427431 }
428432
429433 func (s pState) makeBarState(total int64, filler BarFiller, options ...BarOption) *bState {
435439 filler: filler,
436440 renderReq: s.renderReq,
437441 autoRefresh: s.autoRefresh,
442 extender: func(_ decor.Statistics, rows ...io.Reader) ([]io.Reader, error) {
443 return rows, nil
444 },
438445 }
439446
440447 if total > 0 {
447454 }
448455 }
449456
450 for i := 0; i < len(bs.buffers); i++ {
451 bs.buffers[i] = bytes.NewBuffer(make([]byte, 0, 512))
452 }
457 bs.buffers[0] = bytes.NewBuffer(make([]byte, 0, 128)) // prepend
458 bs.buffers[1] = bytes.NewBuffer(make([]byte, 0, 128)) // append
459 bs.buffers[2] = bytes.NewBuffer(make([]byte, 0, 256)) // filler
453460
454461 return bs
455462 }
6868 if rc, ok := r.(io.ReadCloser); ok {
6969 return rc
7070 }
71 return toNopReadCloser(r)
71 return io.NopCloser(r)
7272 }
73
74 func toNopReadCloser(r io.Reader) io.ReadCloser {
75 if _, ok := r.(io.WriterTo); ok {
76 return nopReadCloserWriterTo{r}
77 }
78 return nopReadCloser{r}
79 }
80
81 type nopReadCloser struct {
82 io.Reader
83 }
84
85 func (nopReadCloser) Close() error { return nil }
86
87 type nopReadCloserWriterTo struct {
88 io.Reader
89 }
90
91 func (nopReadCloserWriterTo) Close() error { return nil }
92
93 func (c nopReadCloserWriterTo) WriteTo(w io.Writer) (int64, error) {
94 return c.Reader.(io.WriterTo).WriteTo(w)
95 }