diff --git a/options.go b/options.go new file mode 100644 index 0000000..63f5eeb --- /dev/null +++ b/options.go @@ -0,0 +1,70 @@ +package mpb + +import ( + "io" + "time" + "unicode/utf8" + + "github.com/vbauerster/mpb/cwriter" +) + +type ProgressOption func(*pConf) + +// WithWidth overrides default width 80 +func WithWidth(w int) ProgressOption { + return func(c *pConf) { + if w > 2 { + c.width = w + } + } +} + +// WithFormat overrides default bar format "[=>-]" +func WithFormat(format string) ProgressOption { + return func(c *pConf) { + if utf8.RuneCountInString(format) == numFmtRunes { + c.format = format + } + } +} + +// WithRefreshRate overrides default 100ms refresh rate +func WithRefreshRate(d time.Duration) ProgressOption { + return func(c *pConf) { + c.ticker.Stop() + c.ticker = time.NewTicker(d) + c.rr = d + } +} + +// WithBeforeRenderFunc provided BeforeRender func, +// will be called before each render cycle. +func WithBeforeRenderFunc(f BeforeRender) ProgressOption { + return func(c *pConf) { + c.beforeRender = f + } +} + +// WithCancel provide your cancel channel, +// which you plan to close at some point. +func WithCancel(ch <-chan struct{}) ProgressOption { + return func(c *pConf) { + c.cancel = ch + } +} + +// WithShutdownNotifier provided chanel will be closed, inside p.Stop() call +func WithShutdownNotifier(ch chan struct{}) ProgressOption { + return func(c *pConf) { + c.shutdownNotifier = ch + } +} + +// Output overrides default output os.Stdout +func Output(w io.Writer) ProgressOption { + return func(c *pConf) { + if w != nil { + c.cw = cwriter.New(w) + } + } +} diff --git a/options_go1.7.go b/options_go1.7.go new file mode 100644 index 0000000..2b5f67b --- /dev/null +++ b/options_go1.7.go @@ -0,0 +1,11 @@ +package mpb + +import "context" + +func WithContext(ctx context.Context) ProgressOption { + return func(c *pConf) { + if ctx != nil { + c.cancel = ctx.Done() + } + } +} diff --git a/progress.go b/progress.go index 460d891..b540d96 100644 --- a/progress.go +++ b/progress.go @@ -60,30 +60,34 @@ conf pConf } -// New creates new Progress instance, which will orchestrate bars rendering -// process. It acceepts context.Context, for cancellation. -// If you don't plan to cancel, it is safe to feed with nil -func New() *Progress { - p := &Progress{ - wg: new(sync.WaitGroup), - done: make(chan struct{}), - ops: make(chan func(*pConf)), - stopReqCh: make(chan struct{}), - } - go p.server(pConf{ +// New creates new Progress instance, which orchestrates bars rendering process. +// Accepts mpb.ProgressOption funcs for customization. +func New(options ...ProgressOption) *Progress { + // defaults + conf := pConf{ bars: make([]*Bar, 0, 3), width: pwidth, format: pformat, cw: cwriter.New(os.Stdout), rr: prr, ticker: time.NewTicker(prr), - }) + } + + for _, opt := range options { + opt(&conf) + } + + p := &Progress{ + wg: new(sync.WaitGroup), + done: make(chan struct{}), + ops: make(chan func(*pConf)), + stopReqCh: make(chan struct{}), + } + go p.server(conf) return p } -// WithCancel cancellation via channel. -// You have to call p.Stop() anyway, after cancel. -// Pancis, if nil channel is passed. +// WithCancel Deprecated, use mpb.WithCancel func (p *Progress) WithCancel(ch <-chan struct{}) *Progress { if ch == nil { panic("nil cancel channel") @@ -93,7 +97,7 @@ }) } -// SetWidth overrides default (80) width of bar(s). +// SetWidth Deprecated, use mpb.WithWidth func (p *Progress) SetWidth(width int) *Progress { if width < 2 { return p @@ -103,7 +107,7 @@ }) } -// SetOut sets underlying writer of progress. Default one is os.Stdout. +// SetOut Deprecated, use mpb.Output func (p *Progress) SetOut(w io.Writer) *Progress { if w == nil { return p @@ -114,19 +118,12 @@ }) } -// RefreshRate overrides default (100ms) refresh rate value +// RefreshRate Deprecated, use mpb.WithRefreshRate func (p *Progress) RefreshRate(d time.Duration) *Progress { return updateConf(p, func(c *pConf) { c.ticker.Stop() c.ticker = time.NewTicker(d) c.rr = d - }) -} - -// BeforeRenderFunc accepts a func, which gets called before render process. -func (p *Progress) BeforeRenderFunc(f BeforeRender) *Progress { - return updateConf(p, func(c *pConf) { - c.beforeRender = f }) } @@ -189,14 +186,7 @@ } } -// ShutdownNotify means to be notified when main rendering goroutine quits, usualy after p.Stop() call. -func (p *Progress) ShutdownNotify(ch chan struct{}) *Progress { - return updateConf(p, func(c *pConf) { - c.shutdownNotifier = ch - }) -} - -// Format sets custom format for underlying bar(s), default one is "[=>-]". +// Format Deprecated, use mpb.WithFormat func (p *Progress) Format(format string) *Progress { if utf8.RuneCountInString(format) != numFmtRunes { return p diff --git a/progress_go1.7.go b/progress_go1.7.go index 63d1dec..1f06bb3 100644 --- a/progress_go1.7.go +++ b/progress_go1.7.go @@ -4,9 +4,7 @@ import "context" -// WithContext cancellation via context. -// You have to call p.Stop() anyway, after cancel. -// Pancis, if nil context is passed +// WithContext Deprecated, use mpb.WithContext func (p *Progress) WithContext(ctx context.Context) *Progress { if ctx == nil { panic("nil context") diff --git a/progress_go1.7_test.go b/progress_go1.7_test.go index e709675..8baa443 100644 --- a/progress_go1.7_test.go +++ b/progress_go1.7_test.go @@ -16,7 +16,7 @@ func TestWithContext(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) shutdown := make(chan struct{}) - p := mpb.New().WithContext(ctx).ShutdownNotify(shutdown) + p := mpb.New(mpb.WithContext(ctx), mpb.WithShutdownNotifier(shutdown)) var wg sync.WaitGroup total := 100 diff --git a/progress_test.go b/progress_test.go index 45c2e32..d28c908 100644 --- a/progress_test.go +++ b/progress_test.go @@ -112,7 +112,7 @@ func TestWithCancel(t *testing.T) { cancel := make(chan struct{}) shutdown := make(chan struct{}) - p := mpb.New().WithCancel(cancel).ShutdownNotify(shutdown) + p := mpb.New(mpb.WithCancel(cancel), mpb.WithShutdownNotifier(shutdown)) var wg sync.WaitGroup total := 100