Codebase list golang-github-vbauerster-mpb / e99ce08
Move format to decor pkg Vladimir Bauer 9 years ago
7 changed file(s) with 73 addition(s) and 649 deletion(s). Raw diff Collapse all Expand all
88
99 const (
1010 // DidentRight specifies identation direction.
11 // |foo |b | With DidentRight
1112 // | foo| b| Without DidentRight
12 // |foo |b | With DidentRight
1313 DidentRight = 1 << iota
1414
1515 // DwidthSync will auto sync max width
1919 // When DidentRight bit set, the space will be added to the right,
2020 // otherwise to the left.
2121 DextraSpace
22
23 DSyncSpace = DwidthSync | DextraSpace
2224 )
2325
2426 // Statistics represents statistics of the progress bar.
22 import "fmt"
33
44 const (
5 _ = iota
6 bytesInKiB = 1 << (iota * 10)
7 bytesInMiB
8 bytesInGiB
9 bytesInTiB
5 _ = iota
6 KiB = 1 << (iota * 10)
7 MiB
8 GiB
9 TiB
1010 )
1111
1212 const (
13 bytesInKb = 1000
14 bytesInMB = bytesInKb * 1000
15 bytesInGB = bytesInMB * 1000
16 bytesInTB = bytesInGB * 1000
13 KB = 1000
14 MB = KB * 1000
15 GB = MB * 1000
16 TB = GB * 1000
1717 )
1818
1919 const (
20 _ = iota
2021 // Kibibyte = 1024 b
21 Unit_KiB = iota
22 Unit_KiB
2223 // Kilobyte = 1000 b
2324 Unit_kB
2425 )
5859
5960 func formatKiB(i int) (result string) {
6061 switch {
61 case i >= bytesInTiB:
62 result = fmt.Sprintf("%.1fTiB", float64(i)/bytesInTiB)
63 case i >= bytesInGiB:
64 result = fmt.Sprintf("%.1fGiB", float64(i)/bytesInGiB)
65 case i >= bytesInMiB:
66 result = fmt.Sprintf("%.1fMiB", float64(i)/bytesInMiB)
67 case i >= bytesInKiB:
68 result = fmt.Sprintf("%.1fKiB", float64(i)/bytesInKiB)
62 case i >= TiB:
63 result = fmt.Sprintf("%.1fTiB", float64(i)/TiB)
64 case i >= GiB:
65 result = fmt.Sprintf("%.1fGiB", float64(i)/GiB)
66 case i >= MiB:
67 result = fmt.Sprintf("%.1fMiB", float64(i)/MiB)
68 case i >= KiB:
69 result = fmt.Sprintf("%.1fKiB", float64(i)/KiB)
6970 default:
7071 result = fmt.Sprintf("%db", i)
7172 }
7475
7576 func formatKB(i int) (result string) {
7677 switch {
77 case i >= bytesInTB:
78 result = fmt.Sprintf("%.1fTB", float64(i)/bytesInTB)
79 case i >= bytesInGB:
80 result = fmt.Sprintf("%.1fGB", float64(i)/bytesInGB)
81 case i >= bytesInMB:
82 result = fmt.Sprintf("%.1fMB", float64(i)/bytesInMB)
83 case i >= bytesInKb:
84 result = fmt.Sprintf("%.1fkB", float64(i)/bytesInKb)
78 case i >= TB:
79 result = fmt.Sprintf("%.1fTB", float64(i)/TB)
80 case i >= GB:
81 result = fmt.Sprintf("%.1fGB", float64(i)/GB)
82 case i >= MB:
83 result = fmt.Sprintf("%.1fMB", float64(i)/MB)
84 case i >= KB:
85 result = fmt.Sprintf("%.1fkB", float64(i)/KB)
8586 default:
8687 result = fmt.Sprintf("%db", i)
8788 }
0 package decor_test
1
2 import (
3 "testing"
4
5 "github.com/vbauerster/mpb/decor"
6 )
7
8 func TestFormatNoUnits(t *testing.T) {
9 actual := decor.Format(1234567).String()
10 expected := "1234567"
11 if actual != expected {
12 t.Errorf("Expected %q but found %q", expected, actual)
13 }
14 }
15
16 func TestFormatWidth(t *testing.T) {
17 actual := decor.Format(1234567).Width(10).String()
18 expected := " 1234567"
19 if actual != expected {
20 t.Errorf("Expected %q but found %q", expected, actual)
21 }
22 }
23
24 func TestFormatToBytes(t *testing.T) {
25 inputs := []struct {
26 v int
27 e string
28 }{
29 {v: 1000, e: "1000b"},
30 {v: 1024, e: "1.0KiB"},
31 {v: 3*decor.MiB + 140*decor.KiB, e: "3.1MiB"},
32 {v: 2 * decor.GiB, e: "2.0GiB"},
33 {v: 4 * decor.TiB, e: "4.0TiB"},
34 }
35
36 for _, input := range inputs {
37 actual := decor.Format(input.v).To(decor.Unit_KiB).String()
38 if actual != input.e {
39 t.Errorf("Expected %q but found %q", input.e, actual)
40 }
41 }
42 }
+0
-126
decorators.go less more
0 package mpb
1
2 import (
3 "fmt"
4 "time"
5 "unicode/utf8"
6 )
7
8 const (
9 // DidentRight specifies identation direction.
10 // | foo| b| Without DidentRight
11 // |foo |b | With DidentRight
12 DidentRight = 1 << iota
13
14 // DwidthSync will auto sync max width
15 DwidthSync
16
17 // DextraSpace adds extra space, makes sence with DwidthSync only.
18 // When DidentRight bit set, the space will be added to the right,
19 // otherwise to the left.
20 DextraSpace
21 )
22
23 // DecoratorFunc is a function that can be prepended and appended to the progress bar
24 type DecoratorFunc func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string
25
26 func Name(name string, minWidth int, conf byte) DecoratorFunc {
27 format := "%%"
28 if (conf & DidentRight) != 0 {
29 format += "-"
30 }
31 format += "%ds"
32 return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
33 if (conf & DwidthSync) != 0 {
34 myWidth <- utf8.RuneCountInString(name)
35 max := <-maxWidth
36 if (conf & DextraSpace) != 0 {
37 max++
38 }
39 return fmt.Sprintf(fmt.Sprintf(format, max), name)
40 }
41 return fmt.Sprintf(fmt.Sprintf(format, minWidth), name)
42 }
43 }
44
45 func Counters(pairFormat string, unit Units, minWidth int, conf byte) DecoratorFunc {
46 format := "%%"
47 if (conf & DidentRight) != 0 {
48 format += "-"
49 }
50 format += "%ds"
51 return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
52 current := Format(s.Current).To(unit)
53 total := Format(s.Total).To(unit)
54 str := fmt.Sprintf(pairFormat, current, total)
55 if (conf & DwidthSync) != 0 {
56 myWidth <- utf8.RuneCountInString(str)
57 max := <-maxWidth
58 if (conf & DextraSpace) != 0 {
59 max++
60 }
61 return fmt.Sprintf(fmt.Sprintf(format, max), str)
62 }
63 return fmt.Sprintf(fmt.Sprintf(format, minWidth), str)
64 }
65 }
66
67 func ETA(minWidth int, conf byte) DecoratorFunc {
68 format := "%%"
69 if (conf & DidentRight) != 0 {
70 format += "-"
71 }
72 format += "%ds"
73 return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
74 str := fmt.Sprint(time.Duration(s.Eta().Seconds()) * time.Second)
75 if (conf & DwidthSync) != 0 {
76 myWidth <- utf8.RuneCountInString(str)
77 max := <-maxWidth
78 if (conf & DextraSpace) != 0 {
79 max++
80 }
81 return fmt.Sprintf(fmt.Sprintf(format, max), str)
82 }
83 return fmt.Sprintf(fmt.Sprintf(format, minWidth), str)
84 }
85 }
86
87 func (b *Bar) Elapsed(minWidth int, conf byte) DecoratorFunc {
88 format := "%%"
89 if (conf & DidentRight) != 0 {
90 format += "-"
91 }
92 format += "%ds"
93 return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
94 str := fmt.Sprint(time.Duration(s.TimeElapsed.Seconds()) * time.Second)
95 if (conf & DwidthSync) != 0 {
96 myWidth <- utf8.RuneCountInString(str)
97 max := <-maxWidth
98 if (conf & DextraSpace) != 0 {
99 max++
100 }
101 return fmt.Sprintf(fmt.Sprintf(format, max), str)
102 }
103 return fmt.Sprintf(fmt.Sprintf(format, minWidth), str)
104 }
105 }
106
107 func Percentage(minWidth int, conf byte) DecoratorFunc {
108 format := "%%"
109 if (conf & DidentRight) != 0 {
110 format += "-"
111 }
112 format += "%ds"
113 return func(s *Statistics, myWidth chan<- int, maxWidth <-chan int) string {
114 str := fmt.Sprintf("%d %%", percentage(s.Total, s.Current, 100))
115 if (conf & DwidthSync) != 0 {
116 myWidth <- utf8.RuneCountInString(str)
117 max := <-maxWidth
118 if (conf & DextraSpace) != 0 {
119 max++
120 }
121 return fmt.Sprintf(fmt.Sprintf(format, max), str)
122 }
123 return fmt.Sprintf(fmt.Sprintf(format, minWidth), str)
124 }
125 }
+0
-382
decorators_test.go less more
0 package mpb_test
1
2 import (
3 "bytes"
4 "fmt"
5 "io"
6 "io/ioutil"
7 "regexp"
8 "strings"
9 "testing"
10 "time"
11
12 "github.com/vbauerster/mpb"
13 )
14
15 func TestPrependName(t *testing.T) {
16 var buf bytes.Buffer
17 p := mpb.New().SetOut(&buf)
18 name := "TestBar"
19 bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace().
20 PrependName(name, 0, 0)
21 for i := 0; i < 100; i++ {
22 bar.Incr(1)
23 }
24
25 p.Stop()
26
27 want := name + "["
28 barOut := buf.String()
29 if !strings.Contains(barOut, want) {
30 t.Errorf("%q not found in bar: %s\n", want, barOut)
31 }
32 }
33
34 func TestPrependNameDindentRight(t *testing.T) {
35 var buf bytes.Buffer
36 p := mpb.New().SetOut(&buf)
37 name := "TestBar"
38 bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace().
39 PrependName(name, len(name)+1, mpb.DidentRight)
40 for i := 0; i < 100; i++ {
41 bar.Incr(1)
42 }
43
44 p.Stop()
45
46 want := name + " ["
47 barOut := buf.String()
48 if !strings.Contains(barOut, want) {
49 t.Errorf("%q not found in bar: %s\n", want, barOut)
50 }
51 }
52
53 func TestPrependCounters(t *testing.T) {
54 var buf bytes.Buffer
55 p := mpb.New().SetOut(&buf)
56
57 reader := strings.NewReader(content)
58
59 total := int64(len(content))
60 bar := p.AddBar(total).TrimLeftSpace().TrimRightSpace().
61 PrependCounters("%3s / %3s", mpb.UnitBytes, 0, 0)
62 preader := bar.ProxyReader(reader)
63
64 _, err := io.Copy(ioutil.Discard, preader)
65 if err != nil {
66 t.Errorf("Error copying from reader: %+v\n", err)
67 }
68
69 p.Stop()
70
71 barOut := buf.String()
72 want := fmt.Sprintf("%[1]db / %[1]db[", total)
73 if !strings.Contains(barOut, want) {
74 t.Errorf("%q not found in bar: %s\n", want, barOut)
75 }
76 }
77
78 func TestPrependCountersDindentRight(t *testing.T) {
79 var buf bytes.Buffer
80 p := mpb.New().SetOut(&buf)
81
82 reader := strings.NewReader(content)
83
84 total := int64(len(content))
85 bar := p.AddBar(total).TrimLeftSpace().TrimRightSpace().
86 PrependCounters("%3s / %3s", mpb.UnitBytes, 12, mpb.DidentRight)
87 preader := bar.ProxyReader(reader)
88
89 _, err := io.Copy(ioutil.Discard, preader)
90 if err != nil {
91 t.Errorf("Error copying from reader: %+v\n", err)
92 }
93
94 p.Stop()
95
96 barOut := buf.String()
97 want := fmt.Sprintf("%[1]db / %[1]db [", total)
98 if !strings.Contains(barOut, want) {
99 t.Errorf("%q not found in bar: %s\n", want, barOut)
100 }
101 }
102
103 func TestAppendPercentage(t *testing.T) {
104 var buf bytes.Buffer
105 p := mpb.New().SetOut(&buf)
106
107 bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace().
108 AppendPercentage(6, 0)
109
110 for i := 0; i < 100; i++ {
111 time.Sleep(10 * time.Millisecond)
112 bar.Incr(1)
113 }
114
115 p.Stop()
116
117 want := "] 100 %"
118 barOut := buf.String()
119 if !strings.Contains(barOut, want) {
120 t.Errorf("%q not found in bar: %s\n", want, barOut)
121 }
122 }
123
124 func TestAppendPercentageDindentRight(t *testing.T) {
125 var buf bytes.Buffer
126 p := mpb.New().SetOut(&buf)
127
128 bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace().
129 AppendPercentage(6, mpb.DidentRight)
130
131 for i := 0; i < 100; i++ {
132 time.Sleep(10 * time.Millisecond)
133 bar.Incr(1)
134 }
135
136 p.Stop()
137
138 want := "]100 % "
139 barOut := buf.String()
140 if !strings.Contains(barOut, want) {
141 t.Errorf("%q not found in bar: %s\n", want, barOut)
142 }
143 }
144
145 func TestPrependPercentage(t *testing.T) {
146 var buf bytes.Buffer
147 p := mpb.New().SetOut(&buf)
148
149 bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace().
150 PrependPercentage(6, 0)
151
152 for i := 0; i < 100; i++ {
153 time.Sleep(10 * time.Millisecond)
154 bar.Incr(1)
155 }
156
157 p.Stop()
158
159 want := " 100 %["
160 barOut := buf.String()
161 if !strings.Contains(barOut, want) {
162 t.Errorf("%q not found in bar: %s\n", want, barOut)
163 }
164 }
165
166 func TestPrependPercentageDindentRight(t *testing.T) {
167 var buf bytes.Buffer
168 p := mpb.New().SetOut(&buf)
169
170 bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace().
171 PrependPercentage(6, mpb.DidentRight)
172
173 for i := 0; i < 100; i++ {
174 time.Sleep(10 * time.Millisecond)
175 bar.Incr(1)
176 }
177
178 p.Stop()
179
180 want := "100 % ["
181 barOut := buf.String()
182 if !strings.Contains(barOut, want) {
183 t.Errorf("%q not found in bar: %s\n", want, barOut)
184 }
185 }
186
187 func TestPrependElapsed(t *testing.T) {
188 var buf bytes.Buffer
189 p := mpb.New().SetOut(&buf)
190
191 bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace().
192 PrependElapsed(0, 0)
193
194 for i := 0; i < 100; i++ {
195 time.Sleep(10 * time.Millisecond)
196 bar.Incr(1)
197 }
198
199 p.Stop()
200
201 want := "1s["
202 barOut := buf.String()
203 if !strings.Contains(barOut, want) {
204 t.Errorf("%q not found in bar: %s\n", want, barOut)
205 }
206 }
207
208 func TestPrependElapsedDindentRight(t *testing.T) {
209 var buf bytes.Buffer
210 p := mpb.New().SetOut(&buf)
211
212 bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace().
213 PrependElapsed(3, mpb.DidentRight)
214
215 for i := 0; i < 100; i++ {
216 time.Sleep(10 * time.Millisecond)
217 bar.Incr(1)
218 }
219
220 p.Stop()
221
222 want := "1s ["
223 barOut := buf.String()
224 if !strings.Contains(barOut, want) {
225 t.Errorf("%q not found in bar: %s\n", want, barOut)
226 }
227 }
228
229 func TestAppendElapsed(t *testing.T) {
230 var buf bytes.Buffer
231 p := mpb.New().SetOut(&buf)
232
233 bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace().
234 AppendElapsed(0, 0)
235
236 for i := 0; i < 100; i++ {
237 time.Sleep(10 * time.Millisecond)
238 bar.Incr(1)
239 }
240
241 p.Stop()
242
243 want := "]1s"
244 barOut := buf.String()
245 if !strings.Contains(barOut, want) {
246 t.Errorf("%q not found in bar: %s\n", want, barOut)
247 }
248 }
249
250 func TestAppendElapsedDindentRight(t *testing.T) {
251 var buf bytes.Buffer
252 p := mpb.New().SetOut(&buf)
253
254 bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace().
255 AppendElapsed(3, mpb.DidentRight)
256
257 for i := 0; i < 100; i++ {
258 time.Sleep(10 * time.Millisecond)
259 bar.Incr(1)
260 }
261
262 p.Stop()
263
264 want := "]1s "
265 barOut := buf.String()
266 if !strings.Contains(barOut, want) {
267 t.Errorf("%q not found in bar: %s\n", want, barOut)
268 }
269 }
270
271 func TestPrependETA(t *testing.T) {
272 var buf bytes.Buffer
273 p := mpb.New().SetOut(&buf)
274
275 bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace().
276 PrependETA(0, 0)
277
278 for i := 0; i < 100; i++ {
279 time.Sleep(10 * time.Millisecond)
280 bar.Incr(1)
281 }
282
283 p.Stop()
284
285 want := `0s?\[`
286 barOut := buf.String()
287
288 matched, err := regexp.MatchString(want, barOut)
289 if err != nil {
290 t.Logf("Regex %q err: %+v\n", want, err)
291 t.FailNow()
292 }
293
294 if !matched {
295 t.Errorf("%q not found in bar: %s\n", want, barOut)
296 }
297 }
298
299 func TestPrependETADindentRight(t *testing.T) {
300 var buf bytes.Buffer
301 p := mpb.New().SetOut(&buf)
302
303 bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace().
304 PrependETA(3, mpb.DidentRight)
305
306 for i := 0; i < 100; i++ {
307 time.Sleep(10 * time.Millisecond)
308 bar.Incr(1)
309 }
310
311 p.Stop()
312
313 want := `0s?\s+\[`
314 barOut := buf.String()
315
316 matched, err := regexp.MatchString(want, barOut)
317 if err != nil {
318 t.Logf("Regex %q err: %+v\n", want, err)
319 t.FailNow()
320 }
321
322 if !matched {
323 t.Errorf("%q not found in bar: %s\n", want, barOut)
324 }
325 }
326
327 func TestAppendETA(t *testing.T) {
328 var buf bytes.Buffer
329 p := mpb.New().SetOut(&buf)
330
331 bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace().
332 AppendETA(0, 0)
333
334 for i := 0; i < 100; i++ {
335 time.Sleep(10 * time.Millisecond)
336 bar.Incr(1)
337 }
338
339 p.Stop()
340
341 want := `\]0s?`
342 barOut := buf.String()
343
344 matched, err := regexp.MatchString(want, barOut)
345 if err != nil {
346 t.Logf("Regex %q err: %+v\n", want, err)
347 t.FailNow()
348 }
349
350 if !matched {
351 t.Errorf("%q not found in bar: %s\n", want, barOut)
352 }
353 }
354
355 func TestAppendETADindentRight(t *testing.T) {
356 var buf bytes.Buffer
357 p := mpb.New().SetOut(&buf)
358
359 bar := p.AddBar(100).TrimLeftSpace().TrimRightSpace().
360 AppendETA(3, mpb.DidentRight)
361
362 for i := 0; i < 100; i++ {
363 time.Sleep(10 * time.Millisecond)
364 bar.Incr(1)
365 }
366
367 p.Stop()
368
369 want := `\]0s? `
370 barOut := buf.String()
371
372 matched, err := regexp.MatchString(want, barOut)
373 if err != nil {
374 t.Logf("Regex %q err: %+v\n", want, err)
375 t.FailNow()
376 }
377
378 if !matched {
379 t.Errorf("%q not found in bar: %s\n", want, barOut)
380 }
381 }
+0
-63
format.go less more
0 package mpb
1
2 import "fmt"
3
4 const (
5 _ = iota
6 bytesInKiB = 1 << (iota * 10)
7 bytesInMiB
8 bytesInGiB
9 bytesInTiB
10 )
11
12 type Units uint
13
14 const (
15 _ = iota
16 UnitBytes
17 )
18
19 func Format(i int64) *formatter {
20 return &formatter{n: i}
21 }
22
23 type formatter struct {
24 n int64
25 unit Units
26 width int
27 }
28
29 func (f *formatter) To(unit Units) *formatter {
30 f.unit = unit
31 return f
32 }
33
34 func (f *formatter) Width(width int) *formatter {
35 f.width = width
36 return f
37 }
38
39 func (f *formatter) String() string {
40 switch f.unit {
41 case UnitBytes:
42 return formatBytes(f.n)
43 default:
44 return fmt.Sprintf(fmt.Sprintf("%%%dd", f.width), f.n)
45 }
46 }
47
48 func formatBytes(i int64) (result string) {
49 switch {
50 case i >= bytesInTiB:
51 result = fmt.Sprintf("%.1fTiB", float64(i)/bytesInTiB)
52 case i >= bytesInGiB:
53 result = fmt.Sprintf("%.1fGiB", float64(i)/bytesInGiB)
54 case i >= bytesInMiB:
55 result = fmt.Sprintf("%.1fMiB", float64(i)/bytesInMiB)
56 case i >= bytesInKiB:
57 result = fmt.Sprintf("%.1fKiB", float64(i)/bytesInKiB)
58 default:
59 result = fmt.Sprintf("%db", i)
60 }
61 return
62 }
+0
-51
format_test.go less more
0 package mpb_test
1
2 import (
3 "testing"
4
5 "github.com/vbauerster/mpb"
6 )
7
8 const (
9 _ = iota
10 KiB = 1 << (iota * 10)
11 MiB
12 GiB
13 TiB
14 )
15
16 func TestFormatNoUnits(t *testing.T) {
17 actual := mpb.Format(1234567).String()
18 expected := "1234567"
19 if actual != expected {
20 t.Errorf("Expected %q but found %q", expected, actual)
21 }
22 }
23
24 func TestFormatWidth(t *testing.T) {
25 actual := mpb.Format(1234567).Width(10).String()
26 expected := " 1234567"
27 if actual != expected {
28 t.Errorf("Expected %q but found %q", expected, actual)
29 }
30 }
31
32 func TestFormatToBytes(t *testing.T) {
33 inputs := []struct {
34 v int64
35 e string
36 }{
37 {v: 1000, e: "1000b"},
38 {v: 1024, e: "1.0KiB"},
39 {v: 3*MiB + 140*KiB, e: "3.1MiB"},
40 {v: 2 * GiB, e: "2.0GiB"},
41 {v: 4 * TiB, e: "4.0TiB"},
42 }
43
44 for _, input := range inputs {
45 actual := mpb.Format(input.v).To(mpb.UnitBytes).String()
46 if actual != input.e {
47 t.Errorf("Expected %q but found %q", input.e, actual)
48 }
49 }
50 }