sync width
Vladimir Bauer
9 years ago
| 249 | 249 | ch := make(chan state, 1) |
| 250 | 250 | b.stateReqCh <- ch |
| 251 | 251 | return <-ch |
| 252 | } | |
| 253 | ||
| 254 | func (b *Bar) bytes(termWidth int) []byte { | |
| 255 | s := b.getState() | |
| 256 | return draw(&s, termWidth) | |
| 257 | 252 | } |
| 258 | 253 | |
| 259 | 254 | func (b *Bar) server(ctx context.Context, wg *sync.WaitGroup, id int, total int64, width int, format string) { |
| 356 | 351 | } |
| 357 | 352 | } |
| 358 | 353 | |
| 359 | func draw(s *state, termWidth int) []byte { | |
| 354 | func (b *Bar) bytes(termWidth int, ws *widthSync) []byte { | |
| 355 | s := b.getState() | |
| 356 | return draw(&s, termWidth, ws) | |
| 357 | } | |
| 358 | ||
| 359 | func draw(s *state, termWidth int, ws *widthSync) []byte { | |
| 360 | 360 | if termWidth <= 0 { |
| 361 | 361 | termWidth = s.width |
| 362 | 362 | } |
| 366 | 366 | // render append functions to the right of the bar |
| 367 | 367 | var appendBlock []byte |
| 368 | 368 | for _, f := range s.appendFuncs { |
| 369 | appendBlock = append(appendBlock, []byte(f(stat))...) | |
| 369 | appendBlock = append(appendBlock, []byte(f(stat, nil, nil))...) | |
| 370 | 370 | } |
| 371 | 371 | |
| 372 | 372 | // render prepend functions to the left of the bar |
| 373 | 373 | var prependBlock []byte |
| 374 | for _, f := range s.prependFuncs { | |
| 375 | prependBlock = append(prependBlock, []byte(f(stat))...) | |
| 374 | for i, f := range s.prependFuncs { | |
| 375 | prependBlock = append(prependBlock, []byte(f(stat, ws.listen[i], ws.result[i]))...) | |
| 376 | 376 | } |
| 377 | 377 | |
| 378 | 378 | prependCount := utf8.RuneCount(prependBlock) |
| 15 | 15 | ) |
| 16 | 16 | |
| 17 | 17 | // DecoratorFunc is a function that can be prepended and appended to the progress bar |
| 18 | type DecoratorFunc func(s *Statistics) string | |
| 18 | type DecoratorFunc func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string | |
| 19 | 19 | |
| 20 | 20 | type decorator struct { |
| 21 | 21 | kind decoratorFuncType |
| 24 | 24 | |
| 25 | 25 | func (b *Bar) PrependName(name string, padding int) *Bar { |
| 26 | 26 | layout := "%" + strconv.Itoa(padding) + "s" |
| 27 | b.PrependFunc(func(s *Statistics) string { | |
| 27 | b.PrependFunc(func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string { | |
| 28 | 28 | return fmt.Sprintf(layout, name) |
| 29 | 29 | }) |
| 30 | 30 | return b |
| 32 | 32 | |
| 33 | 33 | func (b *Bar) PrependCounters(unit Units, padding int) *Bar { |
| 34 | 34 | layout := "%" + strconv.Itoa(padding) + "s" |
| 35 | b.PrependFunc(func(s *Statistics) string { | |
| 35 | b.PrependFunc(func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string { | |
| 36 | 36 | current := Format(s.Current).To(unit) |
| 37 | 37 | total := Format(s.Total).To(unit) |
| 38 | 38 | str := fmt.Sprintf("%s / %s", current, total) |
| 43 | 43 | |
| 44 | 44 | func (b *Bar) PrependETA(padding int) *Bar { |
| 45 | 45 | layout := "ETA%" + strconv.Itoa(padding) + "s" |
| 46 | b.PrependFunc(func(s *Statistics) string { | |
| 46 | b.PrependFunc(func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string { | |
| 47 | 47 | return fmt.Sprintf(layout, time.Duration(s.Eta().Seconds())*time.Second) |
| 48 | 48 | }) |
| 49 | 49 | return b |
| 51 | 51 | |
| 52 | 52 | func (b *Bar) AppendETA(padding int) *Bar { |
| 53 | 53 | layout := "ETA %" + strconv.Itoa(padding) + "s" |
| 54 | b.AppendFunc(func(s *Statistics) string { | |
| 54 | b.AppendFunc(func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string { | |
| 55 | 55 | return fmt.Sprintf(layout, time.Duration(s.Eta().Seconds())*time.Second) |
| 56 | 56 | }) |
| 57 | 57 | return b |
| 59 | 59 | |
| 60 | 60 | func (b *Bar) PrependElapsed(padding int) *Bar { |
| 61 | 61 | layout := "%" + strconv.Itoa(padding) + "s" |
| 62 | b.PrependFunc(func(s *Statistics) string { | |
| 62 | b.PrependFunc(func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string { | |
| 63 | 63 | return fmt.Sprintf(layout, time.Duration(s.TimeElapsed.Seconds())*time.Second) |
| 64 | 64 | }) |
| 65 | 65 | return b |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | 68 | func (b *Bar) AppendElapsed() *Bar { |
| 69 | b.AppendFunc(func(s *Statistics) string { | |
| 69 | b.AppendFunc(func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string { | |
| 70 | 70 | return fmt.Sprint(time.Duration(s.TimeElapsed.Seconds()) * time.Second) |
| 71 | 71 | }) |
| 72 | 72 | return b |
| 73 | 73 | } |
| 74 | 74 | |
| 75 | 75 | func (b *Bar) AppendPercentage() *Bar { |
| 76 | b.AppendFunc(func(s *Statistics) string { | |
| 76 | b.AppendFunc(func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string { | |
| 77 | 77 | completed := percentage(s.Total, s.Current, 100) |
| 78 | 78 | return fmt.Sprintf("%3d %%", completed) |
| 79 | 79 | }) |
| 82 | 82 | |
| 83 | 83 | func (b *Bar) PrependPercentage(padding int) *Bar { |
| 84 | 84 | layout := "%" + strconv.Itoa(padding) + "d %%" |
| 85 | b.PrependFunc(func(s *Statistics) string { | |
| 85 | b.PrependFunc(func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string { | |
| 86 | 86 | completed := percentage(s.Total, s.Current, 100) |
| 87 | 87 | return fmt.Sprintf(layout, completed) |
| 88 | 88 | }) |
| 176 | 176 | if isClosed(p.done) { |
| 177 | 177 | panic(ErrCallAfterStop) |
| 178 | 178 | } |
| 179 | respCh := make(chan int) | |
| 179 | respCh := make(chan int, 1) | |
| 180 | 180 | p.barCountReqCh <- respCh |
| 181 | 181 | return <-respCh |
| 182 | 182 | } |
| 198 | 198 | return |
| 199 | 199 | } |
| 200 | 200 | close(p.operationCh) |
| 201 | } | |
| 202 | ||
| 203 | type widthSync struct { | |
| 204 | listen []chan int | |
| 205 | result []chan int | |
| 201 | 206 | } |
| 202 | 207 | |
| 203 | 208 | // server monitors underlying channels and renders any progress bars |
| 218 | 223 | } |
| 219 | 224 | wg.Done() |
| 220 | 225 | } |
| 226 | var numPrependers int | |
| 227 | // var numAppenders int | |
| 221 | 228 | for { |
| 222 | 229 | select { |
| 223 | 230 | case w := <-p.outChangeReqCh: |
| 243 | 250 | } |
| 244 | 251 | op.result <- ok |
| 245 | 252 | } |
| 253 | if len(bars) > 0 { | |
| 254 | numPrependers = len(bars[0].GetPrependers()) | |
| 255 | // numAppenders = len(bars[0].GetAppenders()) | |
| 256 | } | |
| 246 | 257 | case respCh := <-p.barCountReqCh: |
| 247 | 258 | respCh <- len(bars) |
| 248 | 259 | case beforeRender = <-p.brCh: |
| 255 | 266 | |
| 256 | 267 | if beforeRender != nil { |
| 257 | 268 | beforeRender(bars) |
| 269 | } | |
| 270 | ||
| 271 | prepWidthSync := &widthSync{ | |
| 272 | listen: make([]chan int, numPrependers), | |
| 273 | result: make([]chan int, numPrependers), | |
| 274 | } | |
| 275 | for i := 0; i < numPrependers; i++ { | |
| 276 | prepWidthSync.listen[i] = make(chan int, numBars) | |
| 277 | prepWidthSync.result[i] = make(chan int, numBars) | |
| 278 | } | |
| 279 | stopWidthListen := make(chan struct{}) | |
| 280 | for i, listenCh := range prepWidthSync.listen { | |
| 281 | go func(listenCh <-chan int, resultCh chan<- int) { | |
| 282 | widths := make([]int, 0, numBars) | |
| 283 | loop: | |
| 284 | for { | |
| 285 | select { | |
| 286 | case w := <-listenCh: | |
| 287 | widths = append(widths, w) | |
| 288 | if len(widths) == numBars { | |
| 289 | break loop | |
| 290 | } | |
| 291 | case <-stopWidthListen: | |
| 292 | return | |
| 293 | } | |
| 294 | } | |
| 295 | result := max(widths) | |
| 296 | for i := 0; i < numBars; i++ { | |
| 297 | resultCh <- result | |
| 298 | } | |
| 299 | // close(resultCh) | |
| 300 | }(listenCh, prepWidthSync.result[i]) | |
| 258 | 301 | } |
| 259 | 302 | |
| 260 | 303 | width, _, _ := cwriter.GetTermSize() |
| 264 | 307 | for i := 0; i < numBars; i++ { |
| 265 | 308 | go func() { |
| 266 | 309 | defer recoverIfPanic() |
| 267 | drawer(ibars, ibbCh) | |
| 310 | drawer(ibars, ibbCh, prepWidthSync) | |
| 268 | 311 | }() |
| 269 | 312 | } |
| 270 | 313 | go func() { |
| 271 | 314 | wg.Wait() |
| 272 | 315 | close(ibbCh) |
| 316 | close(stopWidthListen) | |
| 317 | for _, ch := range prepWidthSync.result { | |
| 318 | close(ch) | |
| 319 | } | |
| 320 | for _, ch := range prepWidthSync.listen { | |
| 321 | close(ch) | |
| 322 | } | |
| 273 | 323 | }() |
| 274 | 324 | |
| 275 | 325 | m := make(map[int][]byte, len(bars)) |
| 276 | for r := range ibbCh { | |
| 277 | m[r.index] = r.buf | |
| 326 | for ibb := range ibbCh { | |
| 327 | m[ibb.index] = ibb.buf | |
| 278 | 328 | } |
| 279 | 329 | for i := 0; i < len(bars); i++ { |
| 280 | 330 | cw.Write(m[i]) |
| 296 | 346 | |
| 297 | 347 | func drawer(ibars <-chan indexedBar, ibbCh chan<- indexedBarBuffer) { |
| 298 | 348 | for b := range ibars { |
| 299 | buf := b.bar.bytes(b.termWidth) | |
| 349 | buf := b.bar.bytes(b.termWidth, ws) | |
| 300 | 350 | buf = append(buf, '\n') |
| 301 | 351 | ibbCh <- indexedBarBuffer{b.index, buf} |
| 302 | 352 | } |
| 323 | 373 | return false |
| 324 | 374 | } |
| 325 | 375 | } |
| 376 | ||
| 377 | func max(slice []int) int { | |
| 378 | max := slice[0] | |
| 379 | ||
| 380 | for i := 1; i < len(slice); i++ { | |
| 381 | if slice[i] > max { | |
| 382 | max = slice[i] | |
| 383 | } | |
| 384 | } | |
| 385 | ||
| 386 | return max | |
| 387 | } | |