| 0 | 0 |
package mpb
|
| 1 | 1 |
|
| 2 | 2 |
import (
|
| 3 | |
"context"
|
| 4 | 3 |
"errors"
|
| 5 | 4 |
"io"
|
| 6 | 5 |
"log"
|
|
| 64 | 63 |
// Progress represents the container that renders Progress bars
|
| 65 | 64 |
type Progress struct {
|
| 66 | 65 |
// Context for canceling bars rendering
|
| 67 | |
ctx context.Context
|
|
66 |
// ctx context.Context
|
| 68 | 67 |
// WaitGroup for internal rendering sync
|
| 69 | 68 |
wg *sync.WaitGroup
|
| 70 | 69 |
|
|
| 78 | 77 |
barCountReqCh chan chan int
|
| 79 | 78 |
brCh chan BeforeRender
|
| 80 | 79 |
done chan struct{}
|
|
80 |
cancel <-chan struct{}
|
| 81 | 81 |
}
|
| 82 | 82 |
|
| 83 | 83 |
// New creates new Progress instance, which will orchestrate bars rendering
|
| 84 | 84 |
// process. It acceepts context.Context, for cancellation.
|
| 85 | 85 |
// If you don't plan to cancel, it is safe to feed with nil
|
| 86 | |
func New(ctx context.Context) *Progress {
|
| 87 | |
if ctx == nil {
|
| 88 | |
ctx = context.Background()
|
| 89 | |
}
|
|
86 |
func New() *Progress {
|
| 90 | 87 |
p := &Progress{
|
| 91 | 88 |
width: pwidth,
|
| 92 | 89 |
operationCh: make(chan *operation),
|
|
| 96 | 93 |
brCh: make(chan BeforeRender),
|
| 97 | 94 |
done: make(chan struct{}),
|
| 98 | 95 |
wg: new(sync.WaitGroup),
|
| 99 | |
ctx: ctx,
|
| 100 | 96 |
}
|
| 101 | 97 |
go p.server(cwriter.New(os.Stdout), time.NewTicker(rr*time.Millisecond))
|
| 102 | 98 |
return p
|
| 103 | 99 |
}
|
| 104 | 100 |
|
|
101 |
// WithCancel cancellation via channel
|
|
102 |
func (p *Progress) WithCancel(ch <-chan struct{}) *Progress {
|
|
103 |
if ch == nil {
|
|
104 |
panic("nil cancel channel")
|
|
105 |
}
|
|
106 |
p2 := new(Progress)
|
|
107 |
*p2 = *p
|
|
108 |
p2.cancel = ch
|
|
109 |
return p2
|
|
110 |
}
|
|
111 |
|
| 105 | 112 |
// SetWidth overrides default (70) width of bar(s)
|
| 106 | 113 |
func (p *Progress) SetWidth(n int) *Progress {
|
| 107 | |
if n <= 0 {
|
| 108 | |
return p
|
| 109 | |
}
|
| 110 | |
p.width = n
|
| 111 | |
return p
|
|
114 |
if n < 0 {
|
|
115 |
panic("negative width")
|
|
116 |
}
|
|
117 |
p2 := new(Progress)
|
|
118 |
*p2 = *p
|
|
119 |
p2.width = n
|
|
120 |
return p2
|
| 112 | 121 |
}
|
| 113 | 122 |
|
| 114 | 123 |
// SetOut sets underlying writer of progress. Default is os.Stdout
|
|
| 156 | 165 |
panic(ErrCallAfterStop)
|
| 157 | 166 |
}
|
| 158 | 167 |
result := make(chan bool)
|
| 159 | |
bar := newBar(p.ctx, p.wg, id, total, p.width, p.format)
|
|
168 |
bar := newBar(id, total, p.width, p.format, p.wg, p.cancel)
|
| 160 | 169 |
p.operationCh <- &operation{barAdd, bar, result}
|
| 161 | 170 |
if <-result {
|
| 162 | 171 |
p.wg.Add(1)
|
|
| 196 | 205 |
return p
|
| 197 | 206 |
}
|
| 198 | 207 |
|
| 199 | |
// Stop waits for bars to finish rendering and stops the rendering goroutine
|
|
208 |
// Stop shutdowns Progress' goroutine
|
|
209 |
// Should be called only after each bor's work done, i.e. bar has reached its
|
|
210 |
// 100 %. It is NOT for concelation. Use WithContext or WithCancel for
|
|
211 |
// cancelation purposes.
|
| 200 | 212 |
func (p *Progress) Stop() {
|
| 201 | 213 |
p.wg.Wait()
|
| 202 | 214 |
if isClosed(p.done) {
|
|
| 304 | 316 |
case d := <-p.rrChangeReqCh:
|
| 305 | 317 |
t.Stop()
|
| 306 | 318 |
t = time.NewTicker(d)
|
| 307 | |
case <-p.ctx.Done():
|
|
319 |
case <-p.cancel:
|
| 308 | 320 |
return
|
| 309 | 321 |
}
|
| 310 | 322 |
}
|