Skip to content

Commit

Permalink
Merge pull request #167 from edigaryev/fix-humanize-bytes
Browse files Browse the repository at this point in the history
Fix SI units calculation and introduce OptionUseIECUnits()
  • Loading branch information
schollz committed Nov 6, 2023
2 parents e232cbc + ba1eaf1 commit c4499b7
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 9 deletions.
33 changes: 26 additions & 7 deletions progressbar.go
Expand Up @@ -113,6 +113,9 @@ type config struct {
// whether the render function should make use of ANSI codes to reduce console I/O
useANSICodes bool

// whether to use the IEC units (e.g. MiB) instead of the default SI units (e.g. MB)
useIECUnits bool

// showDescriptionAtLineEnd specifies whether description should be written at line end instead of line start
showDescriptionAtLineEnd bool
}
Expand Down Expand Up @@ -284,6 +287,14 @@ func OptionUseANSICodes(val bool) Option {
}
}

// OptionUseIECUnits will enable IEC units (e.g. MiB) instead of the default
// SI units (e.g. MB).
func OptionUseIECUnits(val bool) Option {
return func(p *ProgressBar) {
p.config.useIECUnits = val
}
}

// OptionShowDescriptionAtLineEnd defines whether description should be written at line end instead of line start
func OptionShowDescriptionAtLineEnd() Option {
return func(p *ProgressBar) {
Expand Down Expand Up @@ -331,7 +342,8 @@ func NewOptions64(max int64, options ...Option) *ProgressBar {
b.config.predictTime = false
}

b.config.maxHumanized, b.config.maxHumanizedSuffix = humanizeBytes(float64(b.config.max))
b.config.maxHumanized, b.config.maxHumanizedSuffix = humanizeBytes(float64(b.config.max),
b.config.useIECUnits)

if b.config.renderWithBlankState {
b.RenderBlank()
Expand Down Expand Up @@ -620,7 +632,8 @@ func (p *ProgressBar) ChangeMax64(newMax int64) {
p.config.max = newMax

if p.config.showBytes {
p.config.maxHumanized, p.config.maxHumanizedSuffix = humanizeBytes(float64(p.config.max))
p.config.maxHumanized, p.config.maxHumanizedSuffix = humanizeBytes(float64(p.config.max),
p.config.useIECUnits)
}

p.Add(0) // re-render
Expand Down Expand Up @@ -750,7 +763,7 @@ func renderProgressBar(c config, s *state) (int, error) {
}
if !c.ignoreLength {
if c.showBytes {
currentHumanize, currentSuffix := humanizeBytes(s.currentBytes)
currentHumanize, currentSuffix := humanizeBytes(s.currentBytes, c.useIECUnits)
if currentSuffix == c.maxHumanizedSuffix {
sb.WriteString(fmt.Sprintf("%s/%s%s",
currentHumanize, c.maxHumanized, c.maxHumanizedSuffix))
Expand All @@ -763,7 +776,7 @@ func renderProgressBar(c config, s *state) (int, error) {
}
} else {
if c.showBytes {
currentHumanize, currentSuffix := humanizeBytes(s.currentBytes)
currentHumanize, currentSuffix := humanizeBytes(s.currentBytes, c.useIECUnits)
sb.WriteString(fmt.Sprintf("%s%s", currentHumanize, currentSuffix))
} else {
sb.WriteString(fmt.Sprintf("%.0f/%s", s.currentBytes, "-"))
Expand All @@ -778,7 +791,7 @@ func renderProgressBar(c config, s *state) (int, error) {
} else {
sb.WriteString(", ")
}
currentHumanize, currentSuffix := humanizeBytes(averageRate)
currentHumanize, currentSuffix := humanizeBytes(averageRate, c.useIECUnits)
sb.WriteString(fmt.Sprintf("%s%s/s", currentHumanize, currentSuffix))
}

Expand Down Expand Up @@ -1065,9 +1078,15 @@ func average(xs []float64) float64 {
return total / float64(len(xs))
}

func humanizeBytes(s float64) (string, string) {
func humanizeBytes(s float64, iec bool) (string, string) {
sizes := []string{" B", " kB", " MB", " GB", " TB", " PB", " EB"}
base := 1024.0
base := 1000.0

if iec {
sizes = []string{" B", " KiB", " MiB", " GiB", " TiB", " PiB", " EiB"}
base = 1024.0
}

if s < 10 {
return fmt.Sprintf("%2.0f", s), sizes[0]
}
Expand Down
20 changes: 18 additions & 2 deletions progressbar_test.go
Expand Up @@ -323,14 +323,14 @@ func TestBarSmallBytes(t *testing.T) {
time.Sleep(100 * time.Millisecond)
bar.Add(1000)
}
if !strings.Contains(buf.String(), "8.8 kB/95 MB") {
if !strings.Contains(buf.String(), "9.0 kB/100 MB") {
t.Errorf("wrong string: %s", buf.String())
}
for i := 1; i < 10; i++ {
time.Sleep(10 * time.Millisecond)
bar.Add(1000000)
}
if !strings.Contains(buf.String(), "8.6/95 MB") {
if !strings.Contains(buf.String(), "9.0/100 MB") {
t.Errorf("wrong string: %s", buf.String())
}
}
Expand Down Expand Up @@ -823,3 +823,19 @@ func TestOptionFullWidth(t *testing.T) {
})
}
}

func TestHumanizeBytesSI(t *testing.T) {
amount, suffix := humanizeBytes(float64(12.34)*1000*1000, false)
assert.Equal(t, "12 MB", fmt.Sprintf("%s%s", amount, suffix))

amount, suffix = humanizeBytes(float64(56.78)*1000*1000*1000, false)
assert.Equal(t, "57 GB", fmt.Sprintf("%s%s", amount, suffix))
}

func TestHumanizeBytesIEC(t *testing.T) {
amount, suffix := humanizeBytes(float64(12.34)*1024*1024, true)
assert.Equal(t, "12 MiB", fmt.Sprintf("%s%s", amount, suffix))

amount, suffix = humanizeBytes(float64(56.78)*1024*1024*1024, true)
assert.Equal(t, "57 GiB", fmt.Sprintf("%s%s", amount, suffix))
}

0 comments on commit c4499b7

Please sign in to comment.