From 93889dfda6ff10a769bee9a0db26243277748c5d Mon Sep 17 00:00:00 2001 From: Vladimir Bauer Date: Sat, 11 Feb 2023 01:13:45 +0500 Subject: [PATCH] don't auto refresh if output is not terminal --- container_option.go | 3 --- cwriter/writer.go | 5 +++++ progress.go | 43 +++++++++++++++++++++++-------------------- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/container_option.go b/container_option.go index da0e9b1a..92bddba9 100644 --- a/container_option.go +++ b/container_option.go @@ -72,14 +72,11 @@ func WithShutdownNotifier(ch chan struct{}) ContainerOption { // will effectively disable auto refresh rate and discard any output, // useful if you want to disable progress bars with little overhead. func WithOutput(w io.Writer) ContainerOption { - var discarded bool if w == nil { w = io.Discard - discarded = true } return func(s *pState) { s.output = w - s.outputDiscarded = discarded } } diff --git a/cwriter/writer.go b/cwriter/writer.go index 35136de6..23a72d3e 100644 --- a/cwriter/writer.go +++ b/cwriter/writer.go @@ -40,6 +40,11 @@ func New(out io.Writer) *Writer { return w } +// IsTerminal tells whether underlying io.Writer is terminal. +func (w *Writer) IsTerminal() bool { + return w.terminal +} + // GetTermSize returns WxH of underlying terminal. func (w *Writer) GetTermSize() (width, height int, err error) { return w.termSize(w.fd) diff --git a/progress.go b/progress.go index 0782f415..83040237 100644 --- a/progress.go +++ b/progress.go @@ -43,12 +43,10 @@ type pState struct { reqWidth int popPriority int popCompleted bool - outputDiscarded bool disableAutoRefresh bool - ignoreNotTTY bool manualRefresh chan interface{} renderDelay <-chan struct{} - shutdownNotifier chan struct{} + shutdownNotifier chan<- interface{} queueBars map[*Bar]*Bar output io.Writer debugOut io.Writer @@ -90,16 +88,10 @@ func NewWithContext(ctx context.Context, options ...ContainerOption) *Progress { operateState: make(chan func(*pState)), interceptIo: make(chan func(io.Writer)), done: make(chan struct{}), + shutdown: make(chan struct{}), cancel: cancel, } - if s.shutdownNotifier != nil { - p.shutdown = s.shutdownNotifier - s.shutdownNotifier = nil - } else { - p.shutdown = make(chan struct{}) - } - go p.serve(s, cwriter.New(s.output)) return p } @@ -233,11 +225,11 @@ func (p *Progress) Shutdown() { <-p.shutdown } -func (p *Progress) newTicker(s *pState) chan time.Time { +func (p *Progress) newTicker(s *pState, isTerminal bool) chan time.Time { ch := make(chan time.Time) go func() { var autoRefresh <-chan time.Time - if !s.disableAutoRefresh && !s.outputDiscarded { + if isTerminal && !s.disableAutoRefresh { if s.renderDelay != nil { <-s.renderDelay } @@ -265,10 +257,13 @@ func (p *Progress) newTicker(s *pState) chan time.Time { } func (p *Progress) serve(s *pState, cw *cwriter.Writer) { + render := func() error { + return s.render(cw) + } go s.hm.run() - refreshCh := p.newTicker(s) + refreshCh := p.newTicker(s, cw.IsTerminal()) for { select { @@ -277,26 +272,34 @@ func (p *Progress) serve(s *pState, cw *cwriter.Writer) { case fn := <-p.interceptIo: fn(cw) case <-refreshCh: - err := s.render(cw) + err := render() if err != nil { - refreshCh = nil _, _ = fmt.Fprintln(s.debugOut, err.Error()) + render = func() error { return nil } p.cancel() // cancel all bars } case <-p.done: - close(s.hm) + if s.shutdownNotifier != nil { + go func() { + s.shutdownNotifier <- s.hm.end() + }() + } else { + close(s.hm) + } close(p.shutdown) return } } } -func (s *pState) render(cw *cwriter.Writer) error { - width, height, err := cw.GetTermSize() - if err != nil { - if !s.ignoreNotTTY { +func (s *pState) render(cw *cwriter.Writer) (err error) { + var width, height int + if cw.IsTerminal() { + width, height, err = cw.GetTermSize() + if err != nil { return err } + } else { width = s.reqWidth height = 100 }