| 36 | 36 |
width int
|
| 37 | 37 |
format string
|
| 38 | 38 |
rr time.Duration
|
| 39 | |
cw *cwriter.Writer
|
| 40 | 39 |
pMatrix map[int][]chan int
|
| 41 | 40 |
aMatrix map[int][]chan int
|
| 42 | 41 |
forceRefreshCh chan time.Time
|
|
42 |
output io.Writer
|
| 43 | 43 |
|
| 44 | 44 |
// following are provided/overrided by user
|
| 45 | 45 |
ctx context.Context
|
|
| 55 | 55 |
func New(options ...ContainerOption) *Progress {
|
| 56 | 56 |
pq := make(priorityQueue, 0)
|
| 57 | 57 |
heap.Init(&pq)
|
|
58 |
|
| 58 | 59 |
s := &pState{
|
| 59 | 60 |
ctx: context.Background(),
|
| 60 | 61 |
bHeap: &pq,
|
| 61 | 62 |
width: pwidth,
|
| 62 | |
cw: cwriter.New(os.Stdout),
|
| 63 | 63 |
rr: prr,
|
| 64 | 64 |
waitBars: make(map[*Bar]*Bar),
|
| 65 | 65 |
debugOut: ioutil.Discard,
|
| 66 | 66 |
forceRefreshCh: make(chan time.Time),
|
|
67 |
output: os.Stdout,
|
| 67 | 68 |
}
|
| 68 | 69 |
|
| 69 | 70 |
for _, opt := range options {
|
|
| 80 | 81 |
done: make(chan struct{}),
|
| 81 | 82 |
}
|
| 82 | 83 |
p.cwg.Add(1)
|
| 83 | |
go p.serve(s)
|
|
84 |
go p.serve(s, cwriter.New(s.output))
|
| 84 | 85 |
return p
|
| 85 | 86 |
}
|
| 86 | 87 |
|
|
| 178 | 179 |
p.cwg.Wait()
|
| 179 | 180 |
}
|
| 180 | 181 |
|
| 181 | |
func (p *Progress) serve(s *pState) {
|
|
182 |
func (p *Progress) serve(s *pState, cw *cwriter.Writer) {
|
| 182 | 183 |
defer p.cwg.Done()
|
| 183 | 184 |
|
| 184 | 185 |
manualOrTickCh, cleanUp := s.manualOrTick()
|
|
| 197 | 198 |
}
|
| 198 | 199 |
return
|
| 199 | 200 |
}
|
| 200 | |
tw, err := s.cw.GetWidth()
|
| 201 | |
if err != nil {
|
| 202 | |
tw = s.width
|
| 203 | |
}
|
| 204 | |
s.render(p.done, tw)
|
| 205 | |
}
|
| 206 | |
}
|
| 207 | |
}
|
| 208 | |
|
| 209 | |
func (s *pState) render(done <-chan struct{}, tw int) {
|
|
201 |
if err := s.render(p.done, cw); err != nil {
|
|
202 |
fmt.Fprintf(s.debugOut, "[mpb] %s %v\n", time.Now(), err)
|
|
203 |
}
|
|
204 |
}
|
|
205 |
}
|
|
206 |
}
|
|
207 |
|
|
208 |
func (s *pState) render(done <-chan struct{}, cw *cwriter.Writer) error {
|
| 210 | 209 |
if s.heapUpdated {
|
| 211 | 210 |
s.updateSyncMatrix()
|
| 212 | 211 |
s.heapUpdated = false
|
|
| 214 | 213 |
syncWidth(s.pMatrix)
|
| 215 | 214 |
syncWidth(s.aMatrix)
|
| 216 | 215 |
|
|
216 |
tw, err := cw.GetWidth()
|
|
217 |
if err != nil {
|
|
218 |
tw = s.width
|
|
219 |
}
|
| 217 | 220 |
for i := 0; i < s.bHeap.Len(); i++ {
|
| 218 | 221 |
bar := (*s.bHeap)[i]
|
| 219 | 222 |
go bar.render(s.debugOut, tw)
|
| 220 | 223 |
}
|
| 221 | 224 |
|
| 222 | |
if err := s.flush(done, s.bHeap.Len()); err != nil {
|
| 223 | |
fmt.Fprintf(s.debugOut, "%s %s %v\n", "[mpb]", time.Now(), err)
|
| 224 | |
}
|
| 225 | |
}
|
| 226 | |
|
| 227 | |
func (s *pState) flush(done <-chan struct{}, lineCount int) error {
|
|
225 |
return s.flush(done, cw)
|
|
226 |
}
|
|
227 |
|
|
228 |
func (s *pState) flush(done <-chan struct{}, cw *cwriter.Writer) error {
|
|
229 |
var lineCount int
|
| 228 | 230 |
for s.bHeap.Len() > 0 {
|
| 229 | 231 |
bar := heap.Pop(s.bHeap).(*Bar)
|
| 230 | 232 |
frameReader := <-bar.frameReaderCh
|
|
| 254 | 256 |
}
|
| 255 | 257 |
heap.Push(s.bHeap, bar)
|
| 256 | 258 |
}()
|
| 257 | |
s.cw.ReadFrom(frameReader)
|
| 258 | |
lineCount += frameReader.extendedLines
|
|
259 |
cw.ReadFrom(frameReader)
|
|
260 |
lineCount += frameReader.extendedLines + 1
|
| 259 | 261 |
}
|
| 260 | 262 |
|
| 261 | 263 |
for i := len(s.shutdownPending) - 1; i >= 0; i-- {
|
|
| 263 | 265 |
s.shutdownPending = s.shutdownPending[:i]
|
| 264 | 266 |
}
|
| 265 | 267 |
|
| 266 | |
return s.cw.Flush(lineCount)
|
|
268 |
return cw.Flush(lineCount)
|
| 267 | 269 |
}
|
| 268 | 270 |
|
| 269 | 271 |
func (s *pState) manualOrTick() (<-chan time.Time, func()) {
|