Codebase list golang-github-vbauerster-mpb / cca4f27
initial ci Vladimir Bauer 9 years ago
2 changed file(s) with 313 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 package uiprogress
1
2 import (
3 "bytes"
4 "errors"
5 "fmt"
6 "sync"
7 "time"
8
9 "github.com/gosuri/uiprogress/util/strutil"
10 )
11
12 var (
13 // Fill is the default character representing completed progress
14 Fill byte = '='
15
16 // Head is the default character that moves when progress is updated
17 Head byte = '>'
18
19 // Empty is the default character that represents the empty progress
20 Empty byte = '-'
21
22 // LeftEnd is the default character in the left most part of the progress indicator
23 LeftEnd byte = '['
24
25 // RightEnd is the default character in the right most part of the progress indicator
26 RightEnd byte = ']'
27
28 // Width is the default width of the progress bar
29 Width = 70
30
31 // ErrMaxCurrentReached is error when trying to set current value that exceeds the total value
32 ErrMaxCurrentReached = errors.New("errors: current value is greater total value")
33 )
34
35 // Bar represents a progress bar
36 type Bar struct {
37 // Total of the total for the progress bar
38 Total int
39
40 // LeftEnd is character in the left most part of the progress indicator. Defaults to '['
41 LeftEnd byte
42
43 // RightEnd is character in the right most part of the progress indicator. Defaults to ']'
44 RightEnd byte
45
46 // Fill is the character representing completed progress. Defaults to '='
47 Fill byte
48
49 // Head is the character that moves when progress is updated. Defaults to '>'
50 Head byte
51
52 // Empty is the character that represents the empty progress. Default is '-'
53 Empty byte
54
55 // TimeStated is time progress began
56 TimeStarted time.Time
57
58 // Width is the width of the progress bar
59 Width int
60
61 // timeElased is the time elapsed for the progress
62 timeElapsed time.Duration
63 current int
64
65 mtx *sync.RWMutex
66
67 appendFuncs []DecoratorFunc
68 prependFuncs []DecoratorFunc
69 }
70
71 // DecoratorFunc is a function that can be prepended and appended to the progress bar
72 type DecoratorFunc func(b *Bar) string
73
74 // NewBar returns a new progress bar
75 func NewBar(total int) *Bar {
76 return &Bar{
77 Total: total,
78 Width: Width,
79 LeftEnd: LeftEnd,
80 RightEnd: RightEnd,
81 Head: Head,
82 Fill: Fill,
83 Empty: Empty,
84
85 mtx: &sync.RWMutex{},
86 }
87 }
88
89 // Set the current count of the bar. It returns ErrMaxCurrentReached when trying n exceeds the total value. This is atomic operation and concurancy safe.
90 func (b *Bar) Set(n int) error {
91 b.mtx.Lock()
92 defer b.mtx.Unlock()
93
94 if n > b.Total {
95 return ErrMaxCurrentReached
96 }
97 b.current = n
98 return nil
99 }
100
101 // Incr increments the current value by 1, time elapsed to current time and returns true. It returns false if the cursor has reached or exceeds total value.
102 func (b *Bar) Incr() bool {
103 b.mtx.Lock()
104 defer b.mtx.Unlock()
105
106 n := b.current + 1
107 if n > b.Total {
108 return false
109 }
110 var t time.Time
111 if b.TimeStarted == t {
112 b.TimeStarted = time.Now()
113 }
114 b.timeElapsed = time.Since(b.TimeStarted)
115 b.current = n
116 return true
117 }
118
119 // Current returns the current progress of the bar
120 func (b *Bar) Current() int {
121 b.mtx.RLock()
122 defer b.mtx.RUnlock()
123 return b.current
124 }
125
126 // AppendFunc runs the decorator function and renders the output on the right of the progress bar
127 func (b *Bar) AppendFunc(f DecoratorFunc) *Bar {
128 b.mtx.Lock()
129 defer b.mtx.Unlock()
130 b.appendFuncs = append(b.appendFuncs, f)
131 return b
132 }
133
134 // AppendCompleted appends the completion percent to the progress bar
135 func (b *Bar) AppendCompleted() *Bar {
136 b.AppendFunc(func(b *Bar) string {
137 return b.CompletedPercentString()
138 })
139 return b
140 }
141
142 // AppendElapsed appends the time elapsed the be progress bar
143 func (b *Bar) AppendElapsed() *Bar {
144 b.AppendFunc(func(b *Bar) string {
145 return strutil.PadLeft(b.TimeElapsedString(), 5, ' ')
146 })
147 return b
148 }
149
150 // PrependFunc runs decorator function and render the output left the progress bar
151 func (b *Bar) PrependFunc(f DecoratorFunc) *Bar {
152 b.mtx.Lock()
153 defer b.mtx.Unlock()
154 b.prependFuncs = append(b.prependFuncs, f)
155 return b
156 }
157
158 // PrependCompleted prepends the precent completed to the progress bar
159 func (b *Bar) PrependCompleted() *Bar {
160 b.PrependFunc(func(b *Bar) string {
161 return b.CompletedPercentString()
162 })
163 return b
164 }
165
166 // PrependElapsed prepends the time elapsed to the begining of the bar
167 func (b *Bar) PrependElapsed() *Bar {
168 b.PrependFunc(func(b *Bar) string {
169 return strutil.PadLeft(b.TimeElapsedString(), 5, ' ')
170 })
171 return b
172 }
173
174 // Bytes returns the byte presentation of the progress bar
175 func (b *Bar) Bytes() []byte {
176 completedWidth := int(float64(b.Width) * (b.CompletedPercent() / 100.00))
177
178 // add fill and empty bits
179 var buf bytes.Buffer
180 for i := 0; i < completedWidth; i++ {
181 buf.WriteByte(b.Fill)
182 }
183 for i := 0; i < b.Width-completedWidth; i++ {
184 buf.WriteByte(b.Empty)
185 }
186
187 // set head bit
188 pb := buf.Bytes()
189 if completedWidth > 0 && completedWidth < b.Width {
190 pb[completedWidth-1] = b.Head
191 }
192
193 // set left and right ends bits
194 pb[0], pb[len(pb)-1] = b.LeftEnd, b.RightEnd
195
196 // render append functions to the right of the bar
197 for _, f := range b.appendFuncs {
198 pb = append(pb, ' ')
199 pb = append(pb, []byte(f(b))...)
200 }
201
202 // render prepend functions to the left of the bar
203 for _, f := range b.prependFuncs {
204 args := []byte(f(b))
205 args = append(args, ' ')
206 pb = append(args, pb...)
207 }
208 return pb
209 }
210
211 // String returns the string representation of the bar
212 func (b *Bar) String() string {
213 return string(b.Bytes())
214 }
215
216 // CompletedPercent return the percent completed
217 func (b *Bar) CompletedPercent() float64 {
218 return (float64(b.Current()) / float64(b.Total)) * 100.00
219 }
220
221 // CompletedPercentString returns the formatted string representation of the completed percent
222 func (b *Bar) CompletedPercentString() string {
223 return fmt.Sprintf("%3.f%%", b.CompletedPercent())
224 }
225
226 // TimeElapsed returns the time elapsed
227 func (b *Bar) TimeElapsed() time.Duration {
228 b.mtx.RLock()
229 defer b.mtx.RUnlock()
230 return b.timeElapsed
231 }
232
233 // TimeElapsedString returns the formatted string represenation of the time elapsed
234 func (b *Bar) TimeElapsedString() string {
235 return strutil.PrettyTime(b.TimeElapsed())
236 }
0 package uiprogress
1
2 import (
3 "fmt"
4 "io"
5 "os"
6 "time"
7
8 "github.com/gosuri/uilive"
9 )
10
11 // Out is the default writer to render progress bars to
12 var Out = os.Stdout
13
14 // RefreshInterval in the default time duration to wait for refreshing the output
15 var RefreshInterval = time.Millisecond * 10
16
17 // Progress represents the container that renders progress bars
18 type Progress struct {
19 // Out is the writer to render progress bars to
20 Out io.Writer
21
22 // Width is the width of the progress bars
23 Width int
24
25 // Bars is the collection of progress bars
26 // Bars []*Bar
27
28 // RefreshInterval in the time duration to wait for refreshing the output
29 RefreshInterval time.Duration
30
31 lw *uilive.Writer
32 stopChan chan struct{}
33 // mtx *sync.RWMutex
34 bars chan Bar
35 ticker *time.Ticker
36 }
37
38 // New returns a new progress bar with defaults
39 func New() *Progress {
40 return &Progress{
41 Width: Width,
42 Out: Out,
43 RefreshInterval: RefreshInterval,
44
45 lw: uilive.New(),
46 stopChan: make(chan struct{}),
47 bars: make(chan Bar),
48 }
49 }
50
51 // Listen listens for updates and renders the progress bars
52 func (p *Progress) Listen() {
53 bars := make([]Bar, 0)
54 p.lw.Out = p.Out
55 loop:
56 for {
57 select {
58 case <-p.stopChan: // interrupt
59 return
60 case bar, ok := <-p.bars:
61 if !ok {
62 break loop
63 }
64 bars = append(bars, bar)
65 default:
66 time.Sleep(p.RefreshInterval)
67 p.mtx.RLock()
68 for _, bar := range p.Bars {
69 fmt.Fprintln(p.lw, bar.String())
70 }
71 p.lw.Flush()
72 p.mtx.RUnlock()
73 }
74 }
75 }