dl: format download progress in human readable form
Fixes golang/go#45556
Change-Id: Idabdceb1063f3544b805f45dd2e034cc459fda91
Reviewed-on: https://go-review.googlesource.com/c/dl/+/339869
Reviewed-by: Alex Rakoczy <alex@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Alex Rakoczy <alex@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
diff --git a/internal/version/version.go b/internal/version/version.go
index 275d6cc..709eca4 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -23,6 +23,7 @@
"path"
"path/filepath"
"runtime"
+ "strconv"
"strings"
"time"
)
@@ -75,6 +76,28 @@
os.Exit(0)
}
+func fmtSize(size int64) string {
+ const (
+ byte_unit = 1 << (10 * iota)
+ kilobyte_unit
+ megabyte_unit
+ )
+
+ unit := "B"
+ value := float64(size)
+
+ switch {
+ case size >= megabyte_unit:
+ unit = "MB"
+ value = value / megabyte_unit
+ case size >= kilobyte_unit:
+ unit = "KB"
+ value = value / kilobyte_unit
+ }
+ formatted := strings.TrimSuffix(strconv.FormatFloat(value, 'f', 1, 64), ".0")
+ return fmt.Sprintf("%s %s", formatted, unit)
+}
+
// install installs a version of Go to the named target directory, creating the
// directory as needed.
func install(targetDir, version string) error {
@@ -333,7 +356,7 @@
if res.StatusCode != http.StatusOK {
return errors.New(res.Status)
}
- pw := &progressWriter{w: f, total: res.ContentLength}
+ pw := &progressWriter{w: f, total: res.ContentLength, output: os.Stderr}
n, err := io.Copy(pw, res.Body)
if err != nil {
return err
@@ -346,10 +369,12 @@
}
type progressWriter struct {
- w io.Writer
- n int64
- total int64
- last time.Time
+ w io.Writer
+ n int64
+ total int64
+ last time.Time
+ formatted bool
+ output io.Writer
}
func (p *progressWriter) update() {
@@ -357,9 +382,15 @@
if p.n == p.total {
end = ""
}
- fmt.Fprintf(os.Stderr, "Downloaded %5.1f%% (%*d / %d bytes)%s\n",
- (100.0*float64(p.n))/float64(p.total),
- ndigits(p.total), p.n, p.total, end)
+ if p.formatted {
+ fmt.Fprintf(p.output, "Downloaded %5.1f%% (%s / %s)%s\n",
+ (100.0*float64(p.n))/float64(p.total),
+ fmtSize(p.n), fmtSize(p.total), end)
+ } else {
+ fmt.Fprintf(p.output, "Downloaded %5.1f%% (%*d / %d bytes)%s\n",
+ (100.0*float64(p.n))/float64(p.total),
+ ndigits(p.total), p.n, p.total, end)
+ }
}
func ndigits(i int64) int {
diff --git a/internal/version/version_test.go b/internal/version/version_test.go
index c08e211..3f3da62 100644
--- a/internal/version/version_test.go
+++ b/internal/version/version_test.go
@@ -5,7 +5,10 @@
package version
import (
+ "bytes"
+ "fmt"
"reflect"
+ "strings"
"testing"
)
@@ -33,3 +36,32 @@
}
}
}
+
+func TestFormatted(t *testing.T) {
+ var total int64 = 1
+ var buff = new(bytes.Buffer)
+ var units = []string{"B", "KB", "MB"}
+ for i := 1; i < 4; i++ {
+ pw := &progressWriter{w: nil, total: total, formatted: true, output: buff}
+ pw.update()
+ total *= 1024
+ expected := fmt.Sprintf("%d %s", 1, units[i-1])
+ if !strings.Contains(buff.String(), expected) {
+ t.Errorf("expected: %s recieved: %s", expected, buff.String())
+ }
+ }
+}
+
+func TestUnFormatted(t *testing.T) {
+ var total int64 = 1
+ var buff = new(bytes.Buffer)
+ for i := 1; i < 4; i++ {
+ pw := &progressWriter{w: nil, total: total, formatted: false, output: buff}
+ pw.update()
+ expected := fmt.Sprintf("%d bytes", total)
+ if !strings.Contains(buff.String(), expected) {
+ t.Errorf("expected: %s recieved: %s", expected, buff.String())
+ }
+ total *= 1024
+ }
+}