Codebase list golang-github-vbauerster-mpb / d3c1c83
BarNewLineExtend Vladimir Bauer 7 years ago
5 changed file(s) with 104 addition(s) and 36 deletion(s). Raw diff Collapse all Expand all
4242 operateState chan func(*bState)
4343 cmdValue chan int
4444 frameReaderCh chan io.Reader
45 bufNL *bytes.Buffer
4546
4647 // done is closed by Bar's goroutine, after cacheState is written
4748 done chan struct{}
6970 refill *refill
7071 bufP, bufB, bufA *bytes.Buffer
7172 panicMsg string
73 newLineExtendFn func(bool, io.Writer)
7274
7375 // following options are assigned to the *Bar
7476 priority int
118120
119121 if b.runningBar != nil {
120122 b.priority = b.runningBar.priority
123 }
124
125 if s.newLineExtendFn != nil {
126 b.bufNL = bytes.NewBuffer(make([]byte, 0, s.width))
121127 }
122128
123129 go b.serve(wg, s, cancel)
282288 }
283289
284290 func (b *Bar) render(debugOut io.Writer, tw int, pSyncer, aSyncer *widthSyncer) {
285 var r io.Reader
286291 select {
287292 case b.operateState <- func(s *bState) {
288293 defer func() {
289 // recovering if external decorators panic
294 // recovering if user defined decorator panics for example
290295 if p := recover(); p != nil {
291296 s.panicMsg = fmt.Sprintf("panic: %v", p)
292 s.pDecorators = nil
293 s.aDecorators = nil
294 s.toComplete = true
295 // truncate panic msg to one tw line, if necessary
296 r = strings.NewReader(fmt.Sprintf(fmt.Sprintf("%%.%ds\n", tw), s.panicMsg))
297297 fmt.Fprintf(debugOut, "%s %s bar id %02d %v\n", "[mpb]", time.Now(), s.id, s.panicMsg)
298 b.frameReaderCh <- &frameReader{
299 Reader: strings.NewReader(fmt.Sprintf(fmt.Sprintf("%%.%ds\n", tw), s.panicMsg)),
300 toShutdown: true,
301 }
298302 }
299 b.frameReaderCh <- &frameReader{
300 Reader: r,
301 toShutdown: s.toComplete && !s.completeFlushed,
302 removeOnComplete: s.removeOnComplete,
303 }
304 s.completeFlushed = s.toComplete
305303 }()
306 r = s.draw(tw, pSyncer, aSyncer)
304 r := s.draw(tw, pSyncer, aSyncer)
305 if s.newLineExtendFn != nil {
306 b.bufNL.Reset()
307 s.newLineExtendFn(s.completeFlushed, b.bufNL)
308 r = io.MultiReader(r, b.bufNL)
309 }
310 b.frameReaderCh <- &frameReader{
311 Reader: r,
312 toShutdown: s.toComplete && !s.completeFlushed,
313 removeOnComplete: s.removeOnComplete,
314 }
315 s.completeFlushed = s.toComplete
307316 }:
308317 case <-b.done:
309318 s := b.cacheState
310 if s.panicMsg != "" {
311 r = strings.NewReader(fmt.Sprintf(fmt.Sprintf("%%.%ds\n", tw), s.panicMsg))
312 } else {
313 r = s.draw(tw, pSyncer, aSyncer)
314 }
315 b.frameReaderCh <- &frameReader{
316 Reader: r,
317 }
319 r := s.draw(tw, pSyncer, aSyncer)
320 if s.newLineExtendFn != nil {
321 b.bufNL.Reset()
322 s.newLineExtendFn(s.completeFlushed, b.bufNL)
323 r = io.MultiReader(r, b.bufNL)
324 }
325 b.frameReaderCh <- &frameReader{Reader: r}
318326 }
319327 }
320328
323331
324332 if termWidth <= 0 {
325333 termWidth = s.width
334 }
335
336 if s.panicMsg != "" {
337 return strings.NewReader(fmt.Sprintf(fmt.Sprintf("%%.%ds\n", termWidth), s.panicMsg))
326338 }
327339
328340 stat := newStatistics(s)
00 package mpb
11
22 import (
3 "io"
4
35 "github.com/vbauerster/mpb/decor"
46 )
57
100102 }
101103 }
102104
105 // BarNewLineExtend takes user defined efn, which is called each render cycle.
106 // Any write to provided writer w of efn, will appear on new line of respective bar.
107 func BarNewLineExtend(efn func(completed bool, w io.Writer)) BarOption {
108 return func(s *bState) {
109 s.newLineExtendFn = efn
110 }
111 }
112
103113 func barWidth(w int) BarOption {
104114 return func(s *bState) {
105115 s.width = w
0 package main
1
2 import (
3 "fmt"
4 "io"
5 "math/rand"
6 "sync"
7 "time"
8
9 "github.com/vbauerster/mpb"
10 "github.com/vbauerster/mpb/decor"
11 )
12
13 func init() {
14 rand.Seed(time.Now().UnixNano())
15 }
16
17 func main() {
18 var wg sync.WaitGroup
19 p := mpb.New(mpb.WithWaitGroup(&wg))
20 total, numBars := 100, 3
21 wg.Add(numBars)
22
23 for i := 0; i < numBars; i++ {
24 name := fmt.Sprintf("Bar#%d:", i)
25 efn := func(completed bool, w io.Writer) {
26 if completed {
27 io.WriteString(w, name+" is completed!\n")
28 }
29 }
30 bar := p.AddBar(int64(total), mpb.BarNewLineExtend(efn),
31 mpb.PrependDecorators(
32 // simple name decorator
33 decor.Name(name),
34 // decor.DSyncWidth bit enables column width synchronization
35 decor.Percentage(decor.WCSyncSpace),
36 ),
37 mpb.AppendDecorators(
38 // replace ETA decorator with "done" message, OnComplete event
39 decor.OnComplete(
40 // ETA decorator with ewma age of 60
41 decor.EwmaETA(decor.ET_STYLE_GO, 60), "done",
42 ),
43 ),
44 )
45 // simulating some work
46 go func() {
47 defer wg.Done()
48 max := 100 * time.Millisecond
49 for i := 0; i < total; i++ {
50 start := time.Now()
51 time.Sleep(time.Duration(rand.Intn(10)+1) * max / 10)
52 // ewma based decorators require work duration measurement
53 bar.IncrBy(1, time.Since(start))
54 }
55 }()
56 }
57 // wait for all bars to complete and flush
58 p.Wait()
59 }
8686 s.debugOut = w
8787 }
8888 }
89
90 // WithInterceptors provides a way to write to the underlying progress pool's
91 // writer. Could be useful if you want to output something below the bars, while
92 // they're rendering.
93 func WithInterceptors(interseptors ...func(io.Writer)) ProgressOption {
94 return func(s *pState) {
95 s.interceptors = interseptors
96 }
97 }
4646 uwg *sync.WaitGroup
4747 cancel <-chan struct{}
4848 shutdownNotifier chan struct{}
49 interceptors []func(io.Writer)
5049 waitBars map[*Bar]*Bar
5150 debugOut io.Writer
5251 }
249248 }()
250249 }
251250
252 for _, interceptor := range s.interceptors {
253 interceptor(s.cw)
254 }
255
256251 if e := s.cw.Flush(); err == nil {
257252 err = e
258253 }