progress bar deferred done and cleanup

This commit is contained in:
Luke K 2020-05-29 03:03:22 +00:00
parent 5ec4ac644a
commit a784445333
No known key found for this signature in database
GPG Key ID: 4896F75BAF2E1966
2 changed files with 41 additions and 19 deletions

View File

@ -86,8 +86,12 @@ type ProgressListener interface {
// Increment to the next step with the given message.
Increment(message string)
// Complete marks the overall task as complete with the given message.
// Complete signals completion, which is expected to be somewhat different than a step increment.
Complete(message string)
// Done signals a cessation of progress updates. Should be called in a defer statement to ensure
// the progress listener can stop any outstanding tasks such as synchronous user updates.
Done()
}
type Subscription struct {
@ -257,6 +261,8 @@ func WithDomainSearchLimit(limit int) Option {
// Root is defaulted to the current working directory.
func (c *Client) Create(language, name, root string) (err error) {
c.progressListener.SetTotal(5)
c.progressListener.Increment("Initializing")
defer c.progressListener.Done()
// Create an instance of a function representation at the given root.
f, err := NewFunction(root)
@ -265,7 +271,6 @@ func (c *Client) Create(language, name, root string) (err error) {
}
// Initialize, writing out a template implementation and a config file.
c.progressListener.Increment("Initializing")
err = f.Initialize(language, name, c.domainSearchLimit, c.initializer)
if err != nil {
return
@ -489,3 +494,4 @@ type noopProgressListener struct{}
func (p *noopProgressListener) SetTotal(i int) {}
func (p *noopProgressListener) Increment(m string) {}
func (p *noopProgressListener) Complete(m string) {}
func (p *noopProgressListener) Done() {}

View File

@ -9,6 +9,15 @@ import (
)
// Bar - a simple, unobtrusive progress indicator
// Usage:
// bar := New()
// bar.SetTotal(3)
// defer bar.Done()
// bar.Increment("Step 1")
// bar.Increment("Step 2")
// bar.Increment("Step 3")
// bar.Complete("Done")
//
// Instantiation creates a progress bar consisiting of an optional spinner
// prefix followed by an indicator of the current step, the total steps, and a
// trailing message The behavior differs substantially if verbosity is enbled
@ -27,10 +36,10 @@ import (
// Format:
// [spinner] i/n t
type Bar struct {
out io.Writer
i int // Current step index
n int // Total steps
t string // Current display text
out io.Writer
index int // Current step index
total int // Total steps
text string // Current display text
sync.Mutex
// verbose mode disables progress spinner and line overwrites, instead
@ -82,17 +91,17 @@ func New(options ...Option) *Bar {
// SetTotal number of steps.
func (b *Bar) SetTotal(n int) {
b.n = n
b.total = n
}
// Increment the currenly active step, including beginning printing on first call.
func (b *Bar) Increment(text string) {
b.Lock()
defer b.Unlock()
if b.i < b.n {
b.i++
if b.index < b.total {
b.index++
}
b.t = text
b.text = text
// If this is not an interactive terminal, only print if explicitly set to
// print while headless, and even then, only a simple line write.
@ -116,16 +125,15 @@ func (b *Bar) Increment(text string) {
}
}
// Complete the spinner by advancing to the last step and printing the final
// text.
// Complete the spinner by advancing to the last step, printing the final text and stopping the write loop.
func (b *Bar) Complete(text string) {
b.Lock()
defer b.Unlock()
if !interactiveTerminal() && !b.printWhileHeadless {
return
}
b.i = b.n // Skip to last step
b.t = text
b.index = b.total // Skip to last step
b.text = text
// If this is not an interactive terminal, only print if explicitly set to
// print while headless, and even then, only a simple line write.
@ -143,9 +151,18 @@ func (b *Bar) Complete(text string) {
}
// If there is an animated line-overwriting progress indicator running,
// stop its updating by closing the channel it's listeining on.
// explicitly stop and then unindent by writing without a spinner prefix.
if b.ticker != nil {
b.Done()
b.overwrite("")
}
}
// Done cancels the write loop if being used.
// Call in a defer statement after creation to ensure that the bar stops if a
// return is encountered prior to calling the Complete step.
func (b *Bar) Done() {
if b.ticker != nil {
// close(b.ticker)
b.ticker.Stop()
b.overwrite("")
}
@ -153,7 +170,7 @@ func (b *Bar) Complete(text string) {
// Write a simple line status update.
func (b *Bar) write() {
fmt.Fprintf(b.out, "%v/%v %v\n", b.i, b.n, b.t)
fmt.Fprintf(b.out, "%v/%v %v\n", b.index, b.total, b.text)
}
// interactiveTerminal returns whether or not the currently attached process
@ -187,6 +204,5 @@ func (b *Bar) overwrite(prefix string) {
up = "\033[1A"
clear = "\033[K"
)
fmt.Fprintf(b.out, "\r%v%v%v%v/%v %v\n", up, clear, prefix, b.i, b.n, b.t)
// fmt.Fprintf(b.out, "\r%v%v/%v %v\033[K", prefix, b.i, b.n, b.t)
fmt.Fprintf(b.out, "\r%v%v%v%v/%v %v\n", up, clear, prefix, b.index, b.total, b.text)
}