Codebase list golang-github-vbauerster-mpb / c0272e6
address issue #105 Vladimir Bauer 3 years ago
3 changed file(s) with 123 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
0 module github.com/vbauerster/mpb/_examples/progressAsWriter
1
2 go 1.17
3
4 require github.com/vbauerster/mpb/v8 v8.0.0
5
6 require (
7 github.com/VividCortex/ewma v1.2.0 // indirect
8 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
9 github.com/mattn/go-runewidth v0.0.13 // indirect
10 github.com/rivo/uniseg v0.2.0 // indirect
11 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
12 )
0 package main
1
2 import (
3 "fmt"
4 "log"
5 "math/rand"
6 "sync"
7 "time"
8
9 "github.com/vbauerster/mpb/v8"
10 "github.com/vbauerster/mpb/v8/decor"
11 )
12
13 func main() {
14 total, numBars := 100, 2
15 var wg sync.WaitGroup
16 wg.Add(numBars)
17 done := make(chan struct{})
18 p := mpb.New(
19 mpb.WithWidth(64),
20 mpb.WithWaitGroup(&wg),
21 mpb.WithShutdownNotifier(done),
22 )
23
24 log.SetOutput(p)
25
26 for i := 0; i < numBars; i++ {
27 name := fmt.Sprintf("Bar#%d:", i)
28 bar := p.AddBar(int64(total),
29 mpb.PrependDecorators(
30 decor.Name(name),
31 decor.Percentage(decor.WCSyncSpace),
32 ),
33 mpb.AppendDecorators(
34 decor.OnComplete(
35 decor.EwmaETA(decor.ET_STYLE_GO, 60, decor.WCSyncWidth), "done",
36 ),
37 ),
38 )
39 // simulating some work
40 go func() {
41 defer wg.Done()
42 rng := rand.New(rand.NewSource(time.Now().UnixNano()))
43 max := 100 * time.Millisecond
44 for i := 0; i < total; i++ {
45 // start variable is solely for EWMA calculation
46 // EWMA's unit of measure is an iteration's duration
47 start := time.Now()
48 time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10)
49 bar.Increment()
50 // we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract
51 bar.DecoratorEwmaUpdate(time.Since(start))
52 }
53 log.Println(name, "done")
54 }()
55 }
56
57 var qwg sync.WaitGroup
58 qwg.Add(1)
59 go func() {
60 quit:
61 for {
62 select {
63 case <-done:
64 // after done, underlying io.Writer returns mpb.DoneError
65 // so following isn't printed
66 log.Println("all done")
67 break quit
68 default:
69 log.Println("waiting for done")
70 time.Sleep(100 * time.Millisecond)
71 }
72 }
73 qwg.Done()
74 }()
75
76 p.Wait()
77 qwg.Wait()
78 }
1717 prr = 150 * time.Millisecond // default RefreshRate
1818 )
1919
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))
22
2023 // Progress represents a container that renders one or more progress bars.
2124 type Progress struct {
2225 ctx context.Context
2427 cwg *sync.WaitGroup
2528 bwg *sync.WaitGroup
2629 operateState chan func(*pState)
30 interceptIo chan func(io.Writer)
2731 done chan struct{}
2832 refreshCh chan time.Time
2933 once sync.Once
8286 cwg: new(sync.WaitGroup),
8387 bwg: new(sync.WaitGroup),
8488 operateState: make(chan func(*pState)),
89 interceptIo: make(chan func(io.Writer)),
8590 done: make(chan struct{}),
8691 }
8792
131136 return bar
132137 case <-p.done:
133138 p.bwg.Done()
134 panic(fmt.Sprintf("%T instance can't be reused after it's done!", p))
139 panic(DoneError)
135140 }
136141 }
137142
177182 }
178183 }
179184
185 // Write is implementation of io.Writer.
186 // Writing to `*mpb.Progress` will print lines above a running bar.
187 // Writes aren't flushed immediatly, but at next refresh cycle.
188 // If Write is called after `*mpb.Progress` is done, `mpb.DoneError`
189 // is returned.
190 func (p *Progress) Write(b []byte) (int, error) {
191 type result struct {
192 n int
193 err error
194 }
195 ch := make(chan *result)
196 select {
197 case p.interceptIo <- func(w io.Writer) {
198 n, err := w.Write(b)
199 ch <- &result{n, err}
200 }:
201 res := <-ch
202 return res.n, res.err
203 case <-p.done:
204 return 0, DoneError
205 }
206 }
207
180208 // Wait waits for all bars to complete and finally shutdowns container.
181209 // After this method has been called, there is no way to reuse *Progress
182210 // instance.
220248 select {
221249 case op := <-p.operateState:
222250 op(s)
251 case fn := <-p.interceptIo:
252 fn(cw)
223253 case <-p.refreshCh:
224254 render(s.debugOut)
225255 case <-s.shutdownNotifier: