forked from mitchellh/ioprogress
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdraw.go
127 lines (107 loc) · 3.25 KB
/
draw.go
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
package ioprogress
import (
"fmt"
"io"
"os"
"strings"
)
// DrawFunc is the callback type for drawing progress.
type DrawFunc func(int64, int64) error
// DrawTextFormatFunc is a callback used by DrawFuncs that draw text in
// order to format the text into some more human friendly format.
type DrawTextFormatFunc func(int64, int64) string
var defaultDrawFunc DrawFunc
func init() {
defaultDrawFunc = DrawTerminal(os.Stdout)
}
// DrawTerminal returns a DrawFunc that draws a progress bar to an io.Writer
// that is assumed to be a terminal (and therefore respects carriage returns).
func DrawTerminal(w io.Writer) DrawFunc {
return DrawTerminalf(w, func(progress, total int64) string {
return fmt.Sprintf("%d/%d", progress, total)
})
}
// DrawTerminalf returns a DrawFunc that draws a progress bar to an io.Writer
// that is formatted with the given formatting function.
func DrawTerminalf(w io.Writer, f DrawTextFormatFunc) DrawFunc {
var maxLength int
return func(progress, total int64) error {
if progress == -1 && total == -1 {
_, err := fmt.Fprintf(w, "\n")
return err
}
// Make sure we pad it to the max length we've ever drawn so that
// we don't have trailing characters.
line := f(progress, total)
if len(line) < maxLength {
line = fmt.Sprintf(
"%s%s",
line,
strings.Repeat(" ", maxLength-len(line)))
}
maxLength = len(line)
_, err := fmt.Fprint(w, line+"\r")
return err
}
}
var byteUnits = []string{"B", "KB", "MB", "GB", "TB", "PB"}
// DrawTextFormatBytes is a DrawTextFormatFunc that formats the progress
// and total into human-friendly byte formats.
func DrawTextFormatBytes(progress, total int64) string {
return fmt.Sprintf("%s/%s", byteUnitStr(progress), byteUnitStr(total))
}
// DrawTextFormatBar returns a DrawTextFormatFunc that draws a progress
// bar with the given width (in characters). This can be used in conjunction
// with another DrawTextFormatFunc to create a progress bar with bytes, for
// example:
//
// bar := DrawTextFormatBar(20)
// func(progress, total int64) string {
// return fmt.Sprintf(
// "%s %s",
// bar(progress, total),
// DrawTextFormatBytes(progress, total))
// }
//
func DrawTextFormatBar(width int64) DrawTextFormatFunc {
width -= 2
return func(progress, total int64) string {
progress = max(progress, 1)
total = max(total, progress)
current := int64((float64(progress) / float64(total)) * float64(width))
return fmt.Sprintf(
"[%s%s]",
strings.Repeat("=", int(current)),
strings.Repeat(" ", int(width-current)))
}
}
func DrawTextFormatBarWithIndicator(width int64, indicator rune) DrawTextFormatFunc {
width -= 2
return func(progress, total int64) string {
progress = max(progress, 1)
total = max(total, progress)
current := int64((float64(progress) / float64(total)) * float64(width))
return fmt.Sprintf(
"[%s%s]",
strings.Repeat(string(indicator), int(current)),
strings.Repeat(" ", int(width-current)))
}
}
func byteUnitStr(n int64) string {
var unit string
size := float64(n)
for i := 1; i < len(byteUnits); i++ {
if size < 1000 {
unit = byteUnits[i-1]
break
}
size = size / 1000
}
return fmt.Sprintf("%.3g %s", size, unit)
}
func max(x, y int64) int64 {
if x > y {
return x
}
return y
}