Refactoring: pConf to pState, state to bState
Vladimir Bauer
8 years ago
| 32 | 32 | quit chan struct{} |
| 33 | 33 | // done channel is receiveable after b.server has been quit |
| 34 | 34 | done chan struct{} |
| 35 | ops chan func(*state) | |
| 35 | ops chan func(*bState) | |
| 36 | 36 | |
| 37 | 37 | // following are used after b.done is receiveable |
| 38 | cacheState state | |
| 38 | cacheState bState | |
| 39 | 39 | |
| 40 | 40 | once sync.Once |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | 43 | type ( |
| 44 | state struct { | |
| 44 | bState struct { | |
| 45 | 45 | id int |
| 46 | 46 | width int |
| 47 | 47 | format fmtRunes |
| 79 | 79 | total = time.Now().Unix() |
| 80 | 80 | } |
| 81 | 81 | |
| 82 | s := state{ | |
| 82 | s := bState{ | |
| 83 | 83 | id: ID, |
| 84 | 84 | total: total, |
| 85 | 85 | etaAlpha: etaAlpha, |
| 97 | 97 | b := &Bar{ |
| 98 | 98 | quit: make(chan struct{}), |
| 99 | 99 | done: make(chan struct{}), |
| 100 | ops: make(chan func(*state)), | |
| 100 | ops: make(chan func(*bState)), | |
| 101 | 101 | } |
| 102 | 102 | |
| 103 | 103 | go b.server(s, wg, cancel) |
| 107 | 107 | // RemoveAllPrependers removes all prepend functions |
| 108 | 108 | func (b *Bar) RemoveAllPrependers() { |
| 109 | 109 | select { |
| 110 | case b.ops <- func(s *state) { | |
| 110 | case b.ops <- func(s *bState) { | |
| 111 | 111 | s.prependFuncs = nil |
| 112 | 112 | }: |
| 113 | 113 | case <-b.quit: |
| 117 | 117 | // RemoveAllAppenders removes all append functions |
| 118 | 118 | func (b *Bar) RemoveAllAppenders() { |
| 119 | 119 | select { |
| 120 | case b.ops <- func(s *state) { | |
| 120 | case b.ops <- func(s *bState) { | |
| 121 | 121 | s.appendFuncs = nil |
| 122 | 122 | }: |
| 123 | 123 | case <-b.quit: |
| 140 | 140 | return |
| 141 | 141 | } |
| 142 | 142 | select { |
| 143 | case b.ops <- func(s *state) { | |
| 143 | case b.ops <- func(s *bState) { | |
| 144 | 144 | next := time.Now() |
| 145 | 145 | if s.current == 0 { |
| 146 | 146 | s.startTime = next |
| 171 | 171 | return |
| 172 | 172 | } |
| 173 | 173 | select { |
| 174 | case b.ops <- func(s *state) { | |
| 174 | case b.ops <- func(s *bState) { | |
| 175 | 175 | s.refill = &refill{r, till} |
| 176 | 176 | }: |
| 177 | 177 | case <-b.quit: |
| 181 | 181 | func (b *Bar) NumOfAppenders() int { |
| 182 | 182 | result := make(chan int, 1) |
| 183 | 183 | select { |
| 184 | case b.ops <- func(s *state) { result <- len(s.appendFuncs) }: | |
| 184 | case b.ops <- func(s *bState) { result <- len(s.appendFuncs) }: | |
| 185 | 185 | return <-result |
| 186 | 186 | case <-b.done: |
| 187 | 187 | return len(b.cacheState.appendFuncs) |
| 191 | 191 | func (b *Bar) NumOfPrependers() int { |
| 192 | 192 | result := make(chan int, 1) |
| 193 | 193 | select { |
| 194 | case b.ops <- func(s *state) { result <- len(s.prependFuncs) }: | |
| 194 | case b.ops <- func(s *bState) { result <- len(s.prependFuncs) }: | |
| 195 | 195 | return <-result |
| 196 | 196 | case <-b.done: |
| 197 | 197 | return len(b.cacheState.prependFuncs) |
| 202 | 202 | func (b *Bar) ID() int { |
| 203 | 203 | result := make(chan int, 1) |
| 204 | 204 | select { |
| 205 | case b.ops <- func(s *state) { result <- s.id }: | |
| 205 | case b.ops <- func(s *bState) { result <- s.id }: | |
| 206 | 206 | return <-result |
| 207 | 207 | case <-b.done: |
| 208 | 208 | return b.cacheState.id |
| 212 | 212 | func (b *Bar) Current() int64 { |
| 213 | 213 | result := make(chan int64, 1) |
| 214 | 214 | select { |
| 215 | case b.ops <- func(s *state) { result <- s.current }: | |
| 215 | case b.ops <- func(s *bState) { result <- s.current }: | |
| 216 | 216 | return <-result |
| 217 | 217 | case <-b.done: |
| 218 | 218 | return b.cacheState.current |
| 222 | 222 | func (b *Bar) Total() int64 { |
| 223 | 223 | result := make(chan int64, 1) |
| 224 | 224 | select { |
| 225 | case b.ops <- func(s *state) { result <- s.total }: | |
| 225 | case b.ops <- func(s *bState) { result <- s.total }: | |
| 226 | 226 | return <-result |
| 227 | 227 | case <-b.done: |
| 228 | 228 | return b.cacheState.total |
| 234 | 234 | // Also you may consider providing your drop ratio via BarDropRatio BarOption func. |
| 235 | 235 | func (b *Bar) SetTotal(total int64, final bool) { |
| 236 | 236 | select { |
| 237 | case b.ops <- func(s *state) { | |
| 237 | case b.ops <- func(s *bState) { | |
| 238 | 238 | s.total = total |
| 239 | 239 | s.dynamic = !final |
| 240 | 240 | }: |
| 265 | 265 | close(b.quit) |
| 266 | 266 | } |
| 267 | 267 | |
| 268 | func (b *Bar) server(s state, wg *sync.WaitGroup, cancel <-chan struct{}) { | |
| 268 | func (b *Bar) server(s bState, wg *sync.WaitGroup, cancel <-chan struct{}) { | |
| 269 | 269 | defer func() { |
| 270 | 270 | b.cacheState = s |
| 271 | 271 | close(b.done) |
| 291 | 291 | |
| 292 | 292 | go func() { |
| 293 | 293 | select { |
| 294 | case b.ops <- func(s *state) { | |
| 294 | case b.ops <- func(s *bState) { | |
| 295 | 295 | defer func() { |
| 296 | 296 | // recovering if external decorators panic |
| 297 | 297 | if p := recover(); p != nil { |
| 323 | 323 | return ch |
| 324 | 324 | } |
| 325 | 325 | |
| 326 | func (s *state) updateTimePerItemEstimate(amount int, now, next time.Time) { | |
| 326 | func (s *bState) updateTimePerItemEstimate(amount int, now, next time.Time) { | |
| 327 | 327 | lastBlockTime := now.Sub(s.blockStartTime) |
| 328 | 328 | lastItemEstimate := float64(lastBlockTime) / float64(amount) |
| 329 | 329 | s.timePerItem = time.Duration((s.etaAlpha * lastItemEstimate) + (1-s.etaAlpha)*float64(s.timePerItem)) |
| 330 | 330 | s.blockStartTime = next |
| 331 | 331 | } |
| 332 | 332 | |
| 333 | func (s *state) draw(termWidth int, prependWs, appendWs *widthSync) { | |
| 333 | func (s *bState) draw(termWidth int, prependWs, appendWs *widthSync) { | |
| 334 | 334 | if termWidth <= 0 { |
| 335 | 335 | termWidth = s.width |
| 336 | 336 | } |
| 373 | 373 | s.bufA.WriteByte('\n') |
| 374 | 374 | } |
| 375 | 375 | |
| 376 | func (s *state) fillBar(width int) { | |
| 376 | func (s *bState) fillBar(width int) { | |
| 377 | 377 | s.bufB.Reset() |
| 378 | 378 | s.bufB.WriteRune(s.format[rLeft]) |
| 379 | 379 | if width <= 2 { |
| 414 | 414 | s.bufB.WriteRune(s.format[rRight]) |
| 415 | 415 | } |
| 416 | 416 | |
| 417 | func newStatistics(s *state) *decor.Statistics { | |
| 417 | func newStatistics(s *bState) *decor.Statistics { | |
| 418 | 418 | return &decor.Statistics{ |
| 419 | 419 | ID: s.id, |
| 420 | 420 | Completed: s.completed, |
| 427 | 427 | } |
| 428 | 428 | } |
| 429 | 429 | |
| 430 | func (s *state) updateFormat(format string) { | |
| 430 | func (s *bState) updateFormat(format string) { | |
| 431 | 431 | for i, n := 0, 0; len(format) > 0; i++ { |
| 432 | 432 | s.format[i], n = utf8.DecodeRuneInString(format) |
| 433 | 433 | format = format[n:] |
| 3 | 3 | |
| 4 | 4 | // BarOption is a function option which changes the default behavior of a bar, |
| 5 | 5 | // if passed to p.AddBar(int64, ...BarOption) |
| 6 | type BarOption func(*state) | |
| 6 | type BarOption func(*bState) | |
| 7 | 7 | |
| 8 | 8 | // AppendDecorators let you inject decorators to the bar's right side |
| 9 | 9 | func AppendDecorators(appenders ...decor.DecoratorFunc) BarOption { |
| 10 | return func(bs *state) { | |
| 11 | bs.appendFuncs = append(bs.appendFuncs, appenders...) | |
| 10 | return func(s *bState) { | |
| 11 | s.appendFuncs = append(s.appendFuncs, appenders...) | |
| 12 | 12 | } |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | 15 | // PrependDecorators let you inject decorators to the bar's left side |
| 16 | 16 | func PrependDecorators(prependers ...decor.DecoratorFunc) BarOption { |
| 17 | return func(bs *state) { | |
| 18 | bs.prependFuncs = append(bs.prependFuncs, prependers...) | |
| 17 | return func(s *bState) { | |
| 18 | s.prependFuncs = append(s.prependFuncs, prependers...) | |
| 19 | 19 | } |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | 22 | // BarTrimLeft trims left side space of the bar |
| 23 | 23 | func BarTrimLeft() BarOption { |
| 24 | return func(bs *state) { | |
| 25 | bs.trimLeftSpace = true | |
| 24 | return func(s *bState) { | |
| 25 | s.trimLeftSpace = true | |
| 26 | 26 | } |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | 29 | // BarTrimRight trims right space of the bar |
| 30 | 30 | func BarTrimRight() BarOption { |
| 31 | return func(bs *state) { | |
| 32 | bs.trimRightSpace = true | |
| 31 | return func(s *bState) { | |
| 32 | s.trimRightSpace = true | |
| 33 | 33 | } |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | 36 | // BarTirm trims both left and right spaces of the bar |
| 37 | 37 | func BarTrim() BarOption { |
| 38 | return func(bs *state) { | |
| 39 | bs.trimLeftSpace = true | |
| 40 | bs.trimRightSpace = true | |
| 38 | return func(s *bState) { | |
| 39 | s.trimLeftSpace = true | |
| 40 | s.trimRightSpace = true | |
| 41 | 41 | } |
| 42 | 42 | } |
| 43 | 43 | |
| 44 | 44 | // BarID overwrites internal bar id |
| 45 | 45 | func BarID(id int) BarOption { |
| 46 | return func(bs *state) { | |
| 47 | bs.id = id | |
| 46 | return func(s *bState) { | |
| 47 | s.id = id | |
| 48 | 48 | } |
| 49 | 49 | } |
| 50 | 50 | |
| 52 | 52 | // You can play with it, if you're not satisfied with default behavior. |
| 53 | 53 | // Default value is 0.25. |
| 54 | 54 | func BarEtaAlpha(a float64) BarOption { |
| 55 | return func(bs *state) { | |
| 56 | bs.etaAlpha = a | |
| 55 | return func(s *bState) { | |
| 56 | s.etaAlpha = a | |
| 57 | 57 | } |
| 58 | 58 | } |
| 59 | 59 | |
| 61 | 61 | // If progress tip reaches total, but total is not final value yet, tip will be |
| 62 | 62 | // dropped by specified ratio. |
| 63 | 63 | func BarDropRatio(ratio int64) BarOption { |
| 64 | return func(bs *state) { | |
| 65 | bs.dropRatio = ratio | |
| 64 | return func(s *bState) { | |
| 65 | s.dropRatio = ratio | |
| 66 | 66 | } |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | 69 | func barWidth(w int) BarOption { |
| 70 | return func(bs *state) { | |
| 71 | bs.width = w | |
| 70 | return func(s *bState) { | |
| 71 | s.width = w | |
| 72 | 72 | } |
| 73 | 73 | } |
| 74 | 74 | |
| 75 | 75 | func barFormat(format string) BarOption { |
| 76 | return func(bs *state) { | |
| 77 | bs.updateFormat(format) | |
| 76 | return func(s *bState) { | |
| 77 | s.updateFormat(format) | |
| 78 | 78 | } |
| 79 | 79 | } |
| 116 | 116 | } |
| 117 | 117 | } |
| 118 | 118 | |
| 119 | func newTestState() *state { | |
| 120 | s := &state{ | |
| 119 | func newTestState() *bState { | |
| 120 | s := &bState{ | |
| 121 | 121 | trimLeftSpace: true, |
| 122 | 122 | trimRightSpace: true, |
| 123 | 123 | bufP: new(bytes.Buffer), |
| 11 | 11 | |
| 12 | 12 | // ProgressOption is a function option which changes the default behavior of |
| 13 | 13 | // progress pool, if passed to mpb.New(...ProgressOption) |
| 14 | type ProgressOption func(*pConf) | |
| 14 | type ProgressOption func(*pState) | |
| 15 | 15 | |
| 16 | 16 | // WithWaitGroup provides means to have a single joint point. |
| 17 | 17 | // If *sync.WaitGroup is provided, you can safely call just p.Stop() |
| 18 | 18 | // without calling Wait() on provided *sync.WaitGroup. |
| 19 | 19 | // Makes sense when there are more than one bar to render. |
| 20 | 20 | func WithWaitGroup(wg *sync.WaitGroup) ProgressOption { |
| 21 | return func(c *pConf) { | |
| 22 | c.ewg = wg | |
| 21 | return func(s *pState) { | |
| 22 | s.ewg = wg | |
| 23 | 23 | } |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | 26 | // WithWidth overrides default width 80 |
| 27 | 27 | func WithWidth(w int) ProgressOption { |
| 28 | return func(c *pConf) { | |
| 28 | return func(s *pState) { | |
| 29 | 29 | if w >= 0 { |
| 30 | c.width = w | |
| 30 | s.width = w | |
| 31 | 31 | } |
| 32 | 32 | } |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | 35 | // WithFormat overrides default bar format "[=>-]" |
| 36 | 36 | func WithFormat(format string) ProgressOption { |
| 37 | return func(c *pConf) { | |
| 37 | return func(s *pState) { | |
| 38 | 38 | if utf8.RuneCountInString(format) == formatLen { |
| 39 | c.format = format | |
| 39 | s.format = format | |
| 40 | 40 | } |
| 41 | 41 | } |
| 42 | 42 | } |
| 43 | 43 | |
| 44 | 44 | // WithRefreshRate overrides default 100ms refresh rate |
| 45 | 45 | func WithRefreshRate(d time.Duration) ProgressOption { |
| 46 | return func(c *pConf) { | |
| 47 | c.ticker.Stop() | |
| 48 | c.ticker = time.NewTicker(d) | |
| 49 | c.rr = d | |
| 46 | return func(s *pState) { | |
| 47 | s.ticker.Stop() | |
| 48 | s.ticker = time.NewTicker(d) | |
| 49 | s.rr = d | |
| 50 | 50 | } |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | 53 | // WithBeforeRenderFunc provided BeforeRender func, |
| 54 | 54 | // will be called before each render cycle. |
| 55 | 55 | func WithBeforeRenderFunc(f BeforeRender) ProgressOption { |
| 56 | return func(c *pConf) { | |
| 57 | c.beforeRender = f | |
| 56 | return func(s *pState) { | |
| 57 | s.beforeRender = f | |
| 58 | 58 | } |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | 61 | // WithCancel provide your cancel channel, |
| 62 | 62 | // which you plan to close at some point. |
| 63 | 63 | func WithCancel(ch <-chan struct{}) ProgressOption { |
| 64 | return func(c *pConf) { | |
| 65 | c.cancel = ch | |
| 64 | return func(s *pState) { | |
| 65 | s.cancel = ch | |
| 66 | 66 | } |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | 69 | // WithShutdownNotifier provided chanel will be closed, inside p.Stop() call |
| 70 | 70 | func WithShutdownNotifier(ch chan struct{}) ProgressOption { |
| 71 | return func(c *pConf) { | |
| 72 | c.shutdownNotifier = ch | |
| 71 | return func(s *pState) { | |
| 72 | s.shutdownNotifier = ch | |
| 73 | 73 | } |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | 76 | // Output overrides default output os.Stdout |
| 77 | 77 | func Output(w io.Writer) ProgressOption { |
| 78 | return func(c *pConf) { | |
| 78 | return func(s *pState) { | |
| 79 | 79 | if w == nil { |
| 80 | 80 | w = ioutil.Discard |
| 81 | 81 | } |
| 82 | c.cw = cwriter.New(w) | |
| 82 | s.cw = cwriter.New(w) | |
| 83 | 83 | } |
| 84 | 84 | } |
| 85 | 85 | |
| 87 | 87 | // writer. Could be useful if you want to output something below the bars, while |
| 88 | 88 | // they're rendering. |
| 89 | 89 | func OutputInterceptors(interseptors ...func(io.Writer)) ProgressOption { |
| 90 | return func(c *pConf) { | |
| 91 | c.interceptors = interseptors | |
| 90 | return func(s *pState) { | |
| 91 | s.interceptors = interseptors | |
| 92 | 92 | } |
| 93 | 93 | } |
| 4 | 4 | import "context" |
| 5 | 5 | |
| 6 | 6 | func WithContext(ctx context.Context) ProgressOption { |
| 7 | return func(c *pConf) { | |
| 7 | return func(s *pState) { | |
| 8 | 8 | if ctx != nil { |
| 9 | c.cancel = ctx.Done() | |
| 9 | s.cancel = ctx.Done() | |
| 10 | 10 | } |
| 11 | 11 | } |
| 12 | 12 | } |
| 17 | 17 | Result []chan int |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | // progress config, fields are adjustable by user indirectly | |
| 21 | pConf struct { | |
| 20 | // progress state, which may contain several bars | |
| 21 | pState struct { | |
| 22 | 22 | bars []*Bar |
| 23 | 23 | |
| 24 | 24 | idCounter int |
| 56 | 56 | quit chan struct{} |
| 57 | 57 | // done channel is receiveable after p.server has been quit |
| 58 | 58 | done chan struct{} |
| 59 | ops chan func(*pConf) | |
| 59 | ops chan func(*pState) | |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | 62 | // New creates new Progress instance, which orchestrates bars rendering process. |
| 63 | 63 | // Accepts mpb.ProgressOption funcs for customization. |
| 64 | 64 | func New(options ...ProgressOption) *Progress { |
| 65 | 65 | // defaults |
| 66 | conf := pConf{ | |
| 66 | conf := pState{ | |
| 67 | 67 | bars: make([]*Bar, 0, 3), |
| 68 | 68 | width: pwidth, |
| 69 | 69 | format: pformat, |
| 81 | 81 | ewg: conf.ewg, |
| 82 | 82 | wg: new(sync.WaitGroup), |
| 83 | 83 | done: make(chan struct{}), |
| 84 | ops: make(chan func(*pConf)), | |
| 84 | ops: make(chan func(*pState)), | |
| 85 | 85 | quit: make(chan struct{}), |
| 86 | 86 | } |
| 87 | 87 | go p.server(conf) |
| 93 | 93 | p.wg.Add(1) |
| 94 | 94 | result := make(chan *Bar, 1) |
| 95 | 95 | select { |
| 96 | case p.ops <- func(c *pConf) { | |
| 96 | case p.ops <- func(c *pState) { | |
| 97 | 97 | options = append(options, barWidth(c.width), barFormat(c.format)) |
| 98 | 98 | b := newBar(c.idCounter, total, p.wg, c.cancel, options...) |
| 99 | 99 | c.bars = append(c.bars, b) |
| 110 | 110 | func (p *Progress) RemoveBar(b *Bar) bool { |
| 111 | 111 | result := make(chan bool, 1) |
| 112 | 112 | select { |
| 113 | case p.ops <- func(c *pConf) { | |
| 113 | case p.ops <- func(c *pState) { | |
| 114 | 114 | var ok bool |
| 115 | 115 | for i, bar := range c.bars { |
| 116 | 116 | if bar == b { |
| 132 | 132 | func (p *Progress) BarCount() int { |
| 133 | 133 | result := make(chan int, 1) |
| 134 | 134 | select { |
| 135 | case p.ops <- func(c *pConf) { | |
| 135 | case p.ops <- func(c *pState) { | |
| 136 | 136 | result <- len(c.bars) |
| 137 | 137 | }: |
| 138 | 138 | return <-result |
| 207 | 207 | return ws |
| 208 | 208 | } |
| 209 | 209 | |
| 210 | func (p *pConf) writeAndFlush(tw, numP, numA int) (err error) { | |
| 210 | func (s *pState) writeAndFlush(tw, numP, numA int) (err error) { | |
| 211 | 211 | if numP < 0 && numA < 0 { |
| 212 | 212 | return |
| 213 | 213 | } |
| 214 | if p.beforeRender != nil { | |
| 215 | p.beforeRender(p.bars) | |
| 214 | if s.beforeRender != nil { | |
| 215 | s.beforeRender(s.bars) | |
| 216 | 216 | } |
| 217 | 217 | |
| 218 | 218 | wSyncTimeout := make(chan struct{}) |
| 219 | time.AfterFunc(p.rr, func() { | |
| 219 | time.AfterFunc(s.rr, func() { | |
| 220 | 220 | close(wSyncTimeout) |
| 221 | 221 | }) |
| 222 | 222 | |
| 223 | prependWs := newWidthSync(wSyncTimeout, len(p.bars), numP) | |
| 224 | appendWs := newWidthSync(wSyncTimeout, len(p.bars), numA) | |
| 225 | ||
| 226 | sequence := make([]<-chan *bufReader, len(p.bars)) | |
| 227 | for i, b := range p.bars { | |
| 223 | prependWs := newWidthSync(wSyncTimeout, len(s.bars), numP) | |
| 224 | appendWs := newWidthSync(wSyncTimeout, len(s.bars), numA) | |
| 225 | ||
| 226 | sequence := make([]<-chan *bufReader, len(s.bars)) | |
| 227 | for i, b := range s.bars { | |
| 228 | 228 | sequence[i] = b.render(tw, prependWs, appendWs) |
| 229 | 229 | } |
| 230 | 230 | |
| 231 | 231 | var i int |
| 232 | 232 | for r := range fanIn(sequence...) { |
| 233 | _, err = p.cw.ReadFrom(r) | |
| 233 | _, err = s.cw.ReadFrom(r) | |
| 234 | 234 | defer func(bar *Bar, complete bool) { |
| 235 | 235 | if complete { |
| 236 | 236 | bar.Complete() |
| 237 | 237 | } |
| 238 | }(p.bars[i], r.complete) | |
| 238 | }(s.bars[i], r.complete) | |
| 239 | 239 | i++ |
| 240 | 240 | } |
| 241 | 241 | |
| 242 | for _, interceptor := range p.interceptors { | |
| 243 | interceptor(p.cw) | |
| 244 | } | |
| 245 | ||
| 246 | if e := p.cw.Flush(); err == nil { | |
| 242 | for _, interceptor := range s.interceptors { | |
| 243 | interceptor(s.cw) | |
| 244 | } | |
| 245 | ||
| 246 | if e := s.cw.Flush(); err == nil { | |
| 247 | 247 | err = e |
| 248 | 248 | } |
| 249 | 249 | return |
| 12 | 12 | "github.com/vbauerster/mpb/cwriter" |
| 13 | 13 | ) |
| 14 | 14 | |
| 15 | func (p *Progress) server(conf pConf) { | |
| 15 | func (p *Progress) server(s pState) { | |
| 16 | 16 | winch := make(chan os.Signal, 1) |
| 17 | 17 | signal.Notify(winch, syscall.SIGWINCH) |
| 18 | 18 | |
| 19 | 19 | defer func() { |
| 20 | if conf.shutdownNotifier != nil { | |
| 21 | close(conf.shutdownNotifier) | |
| 20 | if s.shutdownNotifier != nil { | |
| 21 | close(s.shutdownNotifier) | |
| 22 | 22 | } |
| 23 | 23 | signal.Stop(winch) |
| 24 | 24 | close(p.done) |
| 33 | 33 | for { |
| 34 | 34 | select { |
| 35 | 35 | case op := <-p.ops: |
| 36 | op(&conf) | |
| 37 | case <-conf.ticker.C: | |
| 38 | if len(conf.bars) == 0 { | |
| 36 | op(&s) | |
| 37 | case <-s.ticker.C: | |
| 38 | if len(s.bars) == 0 { | |
| 39 | 39 | runtime.Gosched() |
| 40 | 40 | break |
| 41 | 41 | } |
| 42 | b0 := conf.bars[0] | |
| 42 | b0 := s.bars[0] | |
| 43 | 43 | if numP == -1 { |
| 44 | 44 | numP = b0.NumOfPrependers() |
| 45 | 45 | } |
| 47 | 47 | numA = b0.NumOfAppenders() |
| 48 | 48 | } |
| 49 | 49 | tw, _, _ := cwriter.TermSize() |
| 50 | err := conf.writeAndFlush(tw, numP, numA) | |
| 50 | err := s.writeAndFlush(tw, numP, numA) | |
| 51 | 51 | if err != nil { |
| 52 | 52 | fmt.Fprintln(os.Stderr, err) |
| 53 | 53 | } |
| 54 | 54 | case <-winch: |
| 55 | 55 | tw, _, _ := cwriter.TermSize() |
| 56 | err := conf.writeAndFlush(tw-tw/8, numP, numA) | |
| 56 | err := s.writeAndFlush(tw-tw/8, numP, numA) | |
| 57 | 57 | if err != nil { |
| 58 | 58 | fmt.Fprintln(os.Stderr, err) |
| 59 | 59 | } |
| 60 | 60 | if timer != nil && timer.Reset(resumeDelay) { |
| 61 | 61 | break |
| 62 | 62 | } |
| 63 | conf.ticker.Stop() | |
| 63 | s.ticker.Stop() | |
| 64 | 64 | timer = time.NewTimer(resumeDelay) |
| 65 | 65 | resumeTicker = timer.C |
| 66 | 66 | case <-resumeTicker: |
| 67 | conf.ticker = time.NewTicker(conf.rr) | |
| 67 | s.ticker = time.NewTicker(s.rr) | |
| 68 | 68 | resumeTicker = nil |
| 69 | case <-conf.cancel: | |
| 70 | conf.ticker.Stop() | |
| 71 | conf.cancel = nil | |
| 69 | case <-s.cancel: | |
| 70 | s.ticker.Stop() | |
| 71 | s.cancel = nil | |
| 72 | 72 | case <-p.quit: |
| 73 | if conf.cancel != nil { | |
| 74 | conf.ticker.Stop() | |
| 73 | if s.cancel != nil { | |
| 74 | s.ticker.Stop() | |
| 75 | 75 | } |
| 76 | 76 | return |
| 77 | 77 | } |
| 9 | 9 | "github.com/vbauerster/mpb/cwriter" |
| 10 | 10 | ) |
| 11 | 11 | |
| 12 | func (p *Progress) server(conf pConf) { | |
| 12 | func (p *Progress) server(s pState) { | |
| 13 | 13 | defer func() { |
| 14 | if conf.shutdownNotifier != nil { | |
| 15 | close(conf.shutdownNotifier) | |
| 14 | if s.shutdownNotifier != nil { | |
| 15 | close(s.shutdownNotifier) | |
| 16 | 16 | } |
| 17 | 17 | close(p.done) |
| 18 | 18 | }() |
| 22 | 22 | for { |
| 23 | 23 | select { |
| 24 | 24 | case op := <-p.ops: |
| 25 | op(&conf) | |
| 26 | case <-conf.ticker.C: | |
| 27 | if len(conf.bars) == 0 { | |
| 25 | op(&s) | |
| 26 | case <-s.ticker.C: | |
| 27 | if len(s.bars) == 0 { | |
| 28 | 28 | runtime.Gosched() |
| 29 | 29 | break |
| 30 | 30 | } |
| 31 | b0 := conf.bars[0] | |
| 31 | b0 := s.bars[0] | |
| 32 | 32 | if numP == -1 { |
| 33 | 33 | numP = b0.NumOfPrependers() |
| 34 | 34 | } |
| 36 | 36 | numA = b0.NumOfAppenders() |
| 37 | 37 | } |
| 38 | 38 | tw, _, _ := cwriter.TermSize() |
| 39 | err := conf.writeAndFlush(tw, numP, numA) | |
| 39 | err := s.writeAndFlush(tw, numP, numA) | |
| 40 | 40 | if err != nil { |
| 41 | 41 | fmt.Fprintln(os.Stderr, err) |
| 42 | 42 | } |
| 43 | case <-conf.cancel: | |
| 44 | conf.ticker.Stop() | |
| 45 | conf.cancel = nil | |
| 43 | case <-s.cancel: | |
| 44 | s.ticker.Stop() | |
| 45 | s.cancel = nil | |
| 46 | 46 | case <-p.quit: |
| 47 | if conf.cancel != nil { | |
| 48 | conf.ticker.Stop() | |
| 47 | if s.cancel != nil { | |
| 48 | s.ticker.Stop() | |
| 49 | 49 | } |
| 50 | 50 | return |
| 51 | 51 | } |