1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
package uiprogress
import (
"fmt"
"io"
"os"
"sync"
"time"
"github.com/gosuri/uilive"
)
// Out is the default writer to render progress bars to
var Out = os.Stdout
// RefreshInterval in the default time duration to wait for refreshing the output
var RefreshInterval = time.Millisecond * 10
// defaultProgress is the default progress
var defaultProgress = New()
// Progress represents the container that renders progress bars
type Progress struct {
// Out is the writer to render progress bars to
Out io.Writer
// Width is the width of the progress bars
Width int
// Bars is the collection of progress bars
Bars []*Bar
// RefreshInterval in the time duration to wait for refreshing the output
RefreshInterval time.Duration
lw *uilive.Writer
ticker *time.Ticker
tdone chan bool
mtx *sync.RWMutex
}
// New returns a new progress bar with defaults
func New() *Progress {
lw := uilive.New()
lw.Out = Out
return &Progress{
Width: Width,
Out: Out,
Bars: make([]*Bar, 0),
RefreshInterval: RefreshInterval,
tdone: make(chan bool),
lw: uilive.New(),
mtx: &sync.RWMutex{},
}
}
// AddBar creates a new progress bar and adds it to the default progress container
func AddBar(total int) *Bar {
return defaultProgress.AddBar(total)
}
// Start starts the rendering the progress of progress bars using the DefaultProgress. It listens for updates using `bar.Set(n)` and new bars when added using `AddBar`
func Start() {
defaultProgress.Start()
}
// Stop stops listening
func Stop() {
defaultProgress.Stop()
}
// Listen listens for updates and renders the progress bars
func Listen() {
defaultProgress.Listen()
}
func (p *Progress) SetOut(o io.Writer) {
p.mtx.Lock()
defer p.mtx.Unlock()
p.Out = o
p.lw.Out = o
}
func (p *Progress) SetRefreshInterval(interval time.Duration) {
p.mtx.Lock()
defer p.mtx.Unlock()
p.RefreshInterval = interval
}
// AddBar creates a new progress bar and adds to the container
func (p *Progress) AddBar(total int) *Bar {
p.mtx.Lock()
defer p.mtx.Unlock()
bar := NewBar(total)
bar.Width = p.Width
p.Bars = append(p.Bars, bar)
return bar
}
// Listen listens for updates and renders the progress bars
func (p *Progress) Listen() {
for {
p.mtx.Lock()
interval := p.RefreshInterval
p.mtx.Unlock()
select {
case <-time.After(interval):
p.print()
case <-p.tdone:
p.print()
close(p.tdone)
return
}
}
}
func (p *Progress) print() {
p.mtx.Lock()
defer p.mtx.Unlock()
for _, bar := range p.Bars {
fmt.Fprintln(p.lw, bar.String())
}
p.lw.Flush()
}
// Start starts the rendering the progress of progress bars. It listens for updates using `bar.Set(n)` and new bars when added using `AddBar`
func (p *Progress) Start() {
go p.Listen()
}
// Stop stops listening
func (p *Progress) Stop() {
p.tdone <- true
<-p.tdone
}
// Bypass returns a writer which allows non-buffered data to be written to the underlying output
func (p *Progress) Bypass() io.Writer {
return p.lw.Bypass()
}
|