Codebase list golang-github-vbauerster-mpb / 60f06bd
refactoring bar.render Vladimir Bauer 7 years ago
4 changed file(s) with 90 addition(s) and 100 deletion(s). Raw diff Collapse all Expand all
3131
3232 // Bar represents a progress Bar.
3333 type Bar struct {
34 priority int
35 index int
36
37 cacheState *bState
38 operateState chan func(*bState)
39 bFrameCh chan *bFrame
40 syncTableCh chan [][]chan int
41 completed chan bool
42 forceRefresh chan<- time.Time
43
44 // done is closed by Bar's goroutine, after cacheState is written
34 priority int // used by heap
35 index int // used by heap
36
37 extendedLines int
38 toShutdown bool
39 dropOnComplete bool
40 operateState chan func(*bState)
41 frameCh chan io.Reader
42 syncTableCh chan [][]chan int
43 completed chan bool
44 forceRefresh chan<- time.Time
45
46 // shutdown is closed when bar completed and flushed
47 shutdown chan struct{}
48 // done is closed after cacheState is written
4549 done chan struct{}
46 // shutdown is closed from master Progress goroutine only
47 shutdown chan struct{}
50 // cacheState is populated, right after close(shutdown)
51 cacheState *bState
4852
4953 arbitraryCurrent struct {
5054 sync.Mutex
5458 dlogger *log.Logger
5559 }
5660
57 type (
58 bState struct {
59 filler Filler
60 extender Filler
61 id int
62 width int
63 total int64
64 current int64
65 trimSpace bool
66 toComplete bool
67 removeOnComplete bool
68 barClearOnComplete bool
69 completeFlushed bool
70 aDecorators []decor.Decorator
71 pDecorators []decor.Decorator
72 amountReceivers []decor.AmountReceiver
73 shutdownListeners []decor.ShutdownListener
74 bufP, bufB, bufA *bytes.Buffer
75 bufE *bytes.Buffer
76 panicMsg string
77
78 // priority overrides *Bar's priority, if set
79 priority int
80 // runningBar is a key for *pState.parkedBars
81 runningBar *Bar
82 }
83 bFrame struct {
84 rd io.Reader
85 extendedLines int
86 toShutdown bool
87 removeOnComplete bool
88 }
89 )
90
91 func newBar(
92 ctx context.Context,
93 wg *sync.WaitGroup,
94 forceRefresh chan<- time.Time,
95 bs *bState,
96 dlogger *log.Logger,
97 ) *Bar {
61 type bState struct {
62 filler Filler
63 extender Filler
64 id int
65 width int
66 total int64
67 current int64
68 trimSpace bool
69 toComplete bool
70 completeFlushed bool
71 noBufBOnComplete bool
72 aDecorators []decor.Decorator
73 pDecorators []decor.Decorator
74 amountReceivers []decor.AmountReceiver
75 shutdownListeners []decor.ShutdownListener
76 bufP, bufB, bufA *bytes.Buffer
77 bufE *bytes.Buffer
78 panicMsg string
79
80 // priority overrides *Bar's priority, if set
81 priority int
82 // dropOnComplete propagates to *Bar
83 dropOnComplete bool
84 // runningBar is a key for *pState.parkedBars
85 runningBar *Bar
86 }
87
88 func newBar(ctx context.Context, wg *sync.WaitGroup, bs *bState) *Bar {
9889
9990 bs.bufP = bytes.NewBuffer(make([]byte, 0, bs.width))
10091 bs.bufB = bytes.NewBuffer(make([]byte, 0, bs.width))
10495 }
10596
10697 bar := &Bar{
107 priority: bs.priority,
108 operateState: make(chan func(*bState)),
109 bFrameCh: make(chan *bFrame, 1),
110 syncTableCh: make(chan [][]chan int),
111 completed: make(chan bool),
112 done: make(chan struct{}),
113 shutdown: make(chan struct{}),
114 forceRefresh: forceRefresh,
115 dlogger: dlogger,
98 priority: bs.priority,
99 dropOnComplete: bs.dropOnComplete,
100 operateState: make(chan func(*bState)),
101 frameCh: make(chan io.Reader, 1),
102 syncTableCh: make(chan [][]chan int),
103 completed: make(chan bool),
104 done: make(chan struct{}),
105 shutdown: make(chan struct{}),
116106 }
117107
118108 go bar.serve(ctx, wg, bs)
282272 defer func() {
283273 // recovering if user defined decorator panics for example
284274 if p := recover(); p != nil {
275 b.dlogger.Println(p)
285276 s.panicMsg = fmt.Sprintf("panic: %v", p)
286 b.dlogger.Println(s.panicMsg)
287 b.bFrameCh <- &bFrame{
288 rd: strings.NewReader(fmt.Sprintf(fmt.Sprintf("%%.%ds\n", tw), s.panicMsg)),
289 toShutdown: true,
290 }
277 close(b.shutdown)
278 b.frameCh <- s.drawPanic(tw)
291279 }
292280 }()
293 frame := &bFrame{
294 rd: s.draw(tw),
295 toShutdown: s.toComplete && !s.completeFlushed,
296 removeOnComplete: s.removeOnComplete,
297 }
281
282 frame := s.draw(tw)
283 b.toShutdown = s.toComplete && !s.completeFlushed
284 s.completeFlushed = s.toComplete
285
298286 if s.extender != nil {
299287 s.extender.Fill(s.bufE, tw, newStatistics(s))
300 frame.extendedLines = countLines(s.bufE.Bytes())
301 frame.rd = io.MultiReader(frame.rd, s.bufE)
302 }
303 b.bFrameCh <- frame
304 s.completeFlushed = s.toComplete
288 b.extendedLines = countLines(s.bufE.Bytes())
289 frame = io.MultiReader(frame, s.bufE)
290 }
291 b.frameCh <- frame
305292 }:
306293 case <-b.done:
307294 s := b.cacheState
308 frame := &bFrame{
309 rd: s.draw(tw),
310 }
295 if s.panicMsg != "" {
296 b.frameCh <- s.drawPanic(tw)
297 return
298 }
299 frame := s.draw(tw)
311300 if s.extender != nil {
312301 s.extender.Fill(s.bufE, tw, newStatistics(s))
313 frame.extendedLines = countLines(s.bufE.Bytes())
314 frame.rd = io.MultiReader(frame.rd, s.bufE)
315 }
316 b.bFrameCh <- frame
317 }
302 b.extendedLines = countLines(s.bufE.Bytes())
303 frame = io.MultiReader(frame, s.bufE)
304 }
305 b.frameCh <- frame
306 }
307 }
308
309 func (s *bState) drawPanic(termWidth int) io.Reader {
310 return strings.NewReader(fmt.Sprintf(fmt.Sprintf("%%.%ds\n", termWidth), s.panicMsg))
318311 }
319312
320313 func (s *bState) draw(termWidth int) io.Reader {
321 if s.panicMsg != "" {
322 return strings.NewReader(fmt.Sprintf(fmt.Sprintf("%%.%ds\n", termWidth), s.panicMsg))
323 }
324314
325315 stat := newStatistics(s)
326316
332322 s.bufA.WriteString(d.Decor(stat))
333323 }
334324
335 if s.barClearOnComplete && s.completeFlushed {
325 if s.noBufBOnComplete && s.completeFlushed {
336326 s.bufA.WriteByte('\n')
337327 return io.MultiReader(s.bufP, s.bufA)
338328 }
5656 // gets removed completely.
5757 func BarRemoveOnComplete() BarOption {
5858 return func(s *bState) {
59 s.removeOnComplete = true
59 s.dropOnComplete = true
6060 }
6161 }
6262
8181 // BarRemoveOnComplete.
8282 func BarClearOnComplete() BarOption {
8383 return func(s *bState) {
84 s.barClearOnComplete = true
84 s.noBufBOnComplete = true
8585 }
8686 }
8787
131131
132132 p.Wait()
133133
134 wantPanic = fmt.Sprintf("panic: %s", wantPanic)
135134 debugStr := buf.String()
136135 if !strings.Contains(debugStr, wantPanic) {
137136 t.Errorf("%q doesn't contain %q\n", debugStr, wantPanic)
132132 opt(bs)
133133 }
134134 }
135 bar := newBar(p.ctx, p.bwg, bs)
136 bar.forceRefresh = p.forceRefresh
135137 prefix := fmt.Sprintf("%sbar#%02d ", p.dlogger.Prefix(), bs.id)
136 dlogger := log.New(ps.debugOut, prefix, log.Lshortfile)
137 bar := newBar(p.ctx, p.bwg, p.forceRefresh, bs, dlogger)
138 bar.dlogger = log.New(ps.debugOut, prefix, log.Lshortfile)
138139 if bs.runningBar != nil {
139140 if bar.priority == ps.idCounter {
140141 bar.priority = bs.runningBar.priority
261262 var lineCount int
262263 for s.bHeap.Len() > 0 {
263264 bar := heap.Pop(s.bHeap).(*Bar)
264 frame := <-bar.bFrameCh
265 frame := <-bar.frameCh
265266 defer func() {
266 if frame.toShutdown {
267 if bar.toShutdown {
267268 // shutdown at next flush, in other words decrement underlying WaitGroup
268269 // only after the bar with completed state has been flushed. this
269270 // ensures no bar ends up with less than 100% rendered.
273274 s.heapUpdated = true
274275 delete(s.parkedBars, bar)
275276 }
276 if frame.removeOnComplete {
277 if bar.dropOnComplete {
277278 s.heapUpdated = true
278279 return
279280 }
280281 }
281282 heap.Push(s.bHeap, bar)
282283 }()
283 cw.ReadFrom(frame.rd)
284 lineCount += frame.extendedLines + 1
284 cw.ReadFrom(frame)
285 lineCount += bar.extendedLines + 1
285286 }
286287
287288 for i := len(s.shutdownPending) - 1; i >= 0; i-- {