diff --git a/bar.go b/bar.go index 9ce775b..7ac5bdd 100644 --- a/bar.go +++ b/bar.go @@ -1,8 +1,10 @@ package mpb import ( + "fmt" "io" "math" + "os" "sync" "time" "unicode/utf8" @@ -21,9 +23,9 @@ // Bar represents a progress Bar type Bar struct { - stateReqCh chan state - incrCh chan incrReq - dCommandCh chan *dCommandData + stateReqCh chan state + incrCh chan incrReq + // dCommandCh chan *dCommandData flushedCh chan struct{} removeReqCh chan struct{} completedCh chan struct{} @@ -84,10 +86,10 @@ func newBar(id int, total int64, wg *sync.WaitGroup, conf *userConf) *Bar { b := &Bar{ - width: conf.width, - stateReqCh: make(chan state), - incrCh: make(chan incrReq), - dCommandCh: make(chan *dCommandData), + width: conf.width, + stateReqCh: make(chan state), + incrCh: make(chan incrReq), + // dCommandCh: make(chan *dCommandData), flushedCh: make(chan struct{}), removeReqCh: make(chan struct{}), completedCh: make(chan struct{}), @@ -114,47 +116,39 @@ // SetWidth overrides width of individual bar func (b *Bar) SetWidth(n int) *Bar { - if n < 2 || isClosed(b.done) { + if n < 2 { return b } - s := <-b.stateReqCh - s.width = n - b.stateReqCh <- s + b.updateState(func(s *state) { + s.width = n + }) return b } // TrimLeftSpace removes space befor LeftEnd charater func (b *Bar) TrimLeftSpace() *Bar { - if isClosed(b.done) { - return b - } - // b.trimLeftCh <- true - s := <-b.stateReqCh - s.trimLeftSpace = true - b.stateReqCh <- s + b.updateState(func(s *state) { + s.trimLeftSpace = true + }) return b } // TrimRightSpace removes space after RightEnd charater func (b *Bar) TrimRightSpace() *Bar { - if isClosed(b.done) { - return b - } - // b.trimRightCh <- true - s := <-b.stateReqCh - s.trimRightSpace = true - b.stateReqCh <- s + b.updateState(func(s *state) { + s.trimRightSpace = true + }) return b } // Format overrides format of individual bar func (b *Bar) Format(format string) *Bar { - if utf8.RuneCountInString(format) != numFmtRunes || isClosed(b.done) { + if utf8.RuneCountInString(format) != numFmtRunes { return b } - s := <-b.stateReqCh - s.updateFormat(format) - b.stateReqCh <- s + b.updateState(func(s *state) { + s.updateFormat(format) + }) return b } @@ -162,13 +156,40 @@ // Defaults to 0.25 // Normally you shouldn't touch this func (b *Bar) SetEtaAlpha(a float64) *Bar { - if isClosed(b.done) { - return b - } - s := <-b.stateReqCh - s.etaAlpha = a - b.stateReqCh <- s - return b + b.updateState(func(s *state) { + s.etaAlpha = a + }) + return b +} + +// PrependFunc prepends DecoratorFunc +func (b *Bar) PrependFunc(f DecoratorFunc) *Bar { + b.updateState(func(s *state) { + s.prependFuncs = append(s.prependFuncs, f) + }) + return b +} + +// AppendFunc appends DecoratorFunc +func (b *Bar) AppendFunc(f DecoratorFunc) *Bar { + b.updateState(func(s *state) { + s.appendFuncs = append(s.appendFuncs, f) + }) + return b +} + +// RemoveAllPrependers removes all prepend functions +func (b *Bar) RemoveAllPrependers() { + b.updateState(func(s *state) { + s.prependFuncs = nil + }) +} + +// RemoveAllAppenders removes all append functions +func (b *Bar) RemoveAllAppenders() { + b.updateState(func(s *state) { + s.appendFuncs = nil + }) } // ProxyReader wrapper for io operations, like io.Copy @@ -229,40 +250,6 @@ // Can be used as condition in for loop func (b *Bar) InProgress() bool { return !isClosed(b.done) -} - -// PrependFunc prepends DecoratorFunc -func (b *Bar) PrependFunc(f DecoratorFunc) *Bar { - if isClosed(b.done) { - return b - } - b.dCommandCh <- &dCommandData{dPrepend, f} - return b -} - -// RemoveAllPrependers removes all prepend functions -func (b *Bar) RemoveAllPrependers() { - if isClosed(b.done) { - return - } - b.dCommandCh <- &dCommandData{dPrependZero, nil} -} - -// AppendFunc appends DecoratorFunc -func (b *Bar) AppendFunc(f DecoratorFunc) *Bar { - if isClosed(b.done) { - return b - } - b.dCommandCh <- &dCommandData{dAppend, f} - return b -} - -// RemoveAllAppenders removes all append functions -func (b *Bar) RemoveAllAppenders() { - if isClosed(b.done) { - return - } - b.dCommandCh <- &dCommandData{dAppendZero, nil} } // Completed signals to the bar, that process has been completed. @@ -276,6 +263,23 @@ } } +func (b *Bar) flushed() { + select { + case b.flushedCh <- struct{}{}: + case <-b.done: + fmt.Fprintf(os.Stderr, "flushedCh abort: %d\n", b.state.id) + return + } +} + +func (b *Bar) remove() { + select { + case b.removeReqCh <- struct{}{}: + case <-b.done: + return + } +} + func (b *Bar) getState() state { select { case s := <-b.stateReqCh: @@ -285,14 +289,24 @@ } } +func (b *Bar) updateState(cb func(s *state)) { + s := b.getState() + cb(&s) + select { + case b.stateReqCh <- s: + case <-b.done: + return + } +} + func (b *Bar) server(wg *sync.WaitGroup, s state) { var incrStartTime time.Time defer func() { b.state = s wg.Done() - // fmt.Printf("Exited bar %d\n", s.id) close(b.done) + fmt.Fprintf(os.Stderr, "Exited bar %d\n", s.id) }() for { @@ -318,19 +332,9 @@ s.current = n s.refill = r.refill incrStartTime = time.Now() - case data := <-b.dCommandCh: - switch data.action { - case dAppend: - s.appendFuncs = append(s.appendFuncs, data.f) - case dAppendZero: - s.appendFuncs = nil - case dPrepend: - s.prependFuncs = append(s.prependFuncs, data.f) - case dPrependZero: - s.prependFuncs = nil - } case <-b.flushedCh: if s.completed { + fmt.Fprintln(os.Stderr, "completed") return } case <-b.completedCh: @@ -341,22 +345,6 @@ case <-b.cancel: return } - } -} - -func (b *Bar) flushed() { - select { - case b.flushedCh <- struct{}{}: - case <-b.done: - return - } -} - -func (b *Bar) remove() { - select { - case b.removeReqCh <- struct{}{}: - case <-b.done: - return } } diff --git a/decorators.go b/decorators.go index 5f006f5..5fd4607 100644 --- a/decorators.go +++ b/decorators.go @@ -21,22 +21,22 @@ DextraSpace ) -type decoratorAction uint - -const ( - dAppend decoratorAction = iota - dPrepend - dAppendZero - dPrependZero -) +// type decoratorAction uint + +// const ( +// dAppend decoratorAction = iota +// dPrepend +// dAppendZero +// dPrependZero +// ) // DecoratorFunc is a function that can be prepended and appended to the progress bar type DecoratorFunc func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string -type dCommandData struct { - action decoratorAction - f DecoratorFunc -} +// type dCommandData struct { +// action decoratorAction +// f DecoratorFunc +// } // PrependName prepends name argument to the bar. // The conf argument defines the formatting properties diff --git a/progress.go b/progress.go index f52593d..ce0b7cf 100644 --- a/progress.go +++ b/progress.go @@ -72,7 +72,7 @@ userConf chan userConf bCommandCh chan *bCommandData barCountReqCh chan chan int - beforeStop chan struct{} + beforeStopCh chan struct{} } // New creates new Progress instance, which will orchestrate bars rendering @@ -85,7 +85,7 @@ userConf: make(chan userConf), bCommandCh: make(chan *bCommandData), barCountReqCh: make(chan chan int), - beforeStop: make(chan struct{}), + beforeStopCh: make(chan struct{}), } go p.server(userConf{ width: pwidth, @@ -248,20 +248,26 @@ if isClosed(p.done) { return } - p.beforeStop <- struct{}{} + // fmt.Println("inside p.Stop") p.wg.Wait() - close(p.bCommandCh) + + p.beforeStopCh <- struct{}{} + fmt.Println("signal sent to p.beforeStopCh") + <-p.done + fmt.Println("p.done closed") } // server monitors underlying channels and renders any progress bars func (p *Progress) server(conf userConf) { defer func() { - conf.ticker.Stop() - close(p.done) + // fmt.Println("exiting p.server") + // conf.ticker.Stop() if conf.shutdownNotifier != nil { close(conf.shutdownNotifier) } + // fmt.Println("about to close(p.done)") + close(p.done) }() recoverFn := func(ch chan []byte) { @@ -280,10 +286,7 @@ select { case p.userConf <- conf: case conf = <-p.userConf: - case data, ok := <-p.bCommandCh: - if !ok { - return - } + case data := <-p.bCommandCh: switch data.action { case bAdd: bars = append(bars, data.bar) @@ -303,8 +306,12 @@ case respCh := <-p.barCountReqCh: respCh <- len(bars) case <-conf.ticker.C: + if conf.cancel != nil && isClosed(conf.cancel) { + conf.ticker.Stop() + break + } + numBars := len(bars) - if numBars == 0 { break } @@ -340,13 +347,15 @@ for _, b := range bars { b.flushed() } - case <-p.beforeStop: + case <-p.beforeStopCh: + // fmt.Println("case beforeStopCh") for _, b := range bars { if b.GetStatistics().Total <= 0 { + fmt.Println("completing the bar: ", b) b.Completed() } } - case <-conf.cancel: + conf.ticker.Stop() return } }