forked from mitchellh/ioprogress
-
Notifications
You must be signed in to change notification settings - Fork 0
/
draw.go
104 lines (87 loc) · 2.72 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
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 {
current := int64((float64(progress) / float64(total)) * float64(width))
return fmt.Sprintf(
"[%s%s]",
strings.Repeat("=", 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)
}