Browse code

Update the stream formatter to display custom unit numbers.

Signed-off-by: Ying Li <ying.li@docker.com>

Ying Li authored on 2017/05/03 13:22:56
Showing 5 changed files
... ...
@@ -123,7 +123,7 @@ func MergeSwarmSpecToGRPC(s types.Spec, spec swarmapi.ClusterSpec) (swarmapi.Clu
123 123
 		spec.CAConfig.SigningCACert = []byte(s.CAConfig.SigningCACert)
124 124
 	}
125 125
 	if s.CAConfig.SigningCAKey != "" {
126
-		// do prpagate the signing CA key here because we want to provide it TO the swarm APIs
126
+		// do propagate the signing CA key here because we want to provide it TO the swarm APIs
127 127
 		spec.CAConfig.SigningCAKey = []byte(s.CAConfig.SigningCAKey)
128 128
 	}
129 129
 	spec.CAConfig.ForceRotate = s.CAConfig.ForceRotate
... ...
@@ -36,7 +36,8 @@ type JSONProgress struct {
36 36
 	Total      int64 `json:"total,omitempty"`
37 37
 	Start      int64 `json:"start,omitempty"`
38 38
 	// If true, don't show xB/yB
39
-	HideCounts bool `json:"hidecounts,omitempty"`
39
+	HideCounts bool   `json:"hidecounts,omitempty"`
40
+	Units      string `json:"units,omitempty"`
40 41
 }
41 42
 
42 43
 func (p *JSONProgress) String() string {
... ...
@@ -55,11 +56,16 @@ func (p *JSONProgress) String() string {
55 55
 	if p.Current <= 0 && p.Total <= 0 {
56 56
 		return ""
57 57
 	}
58
-	current := units.HumanSize(float64(p.Current))
59 58
 	if p.Total <= 0 {
60
-		return fmt.Sprintf("%8v", current)
59
+		switch p.Units {
60
+		case "":
61
+			current := units.HumanSize(float64(p.Current))
62
+			return fmt.Sprintf("%8v", current)
63
+		default:
64
+			return fmt.Sprintf("%d %s", p.Current, p.Units)
65
+		}
61 66
 	}
62
-	total := units.HumanSize(float64(p.Total))
67
+
63 68
 	percentage := int(float64(p.Current)/float64(p.Total)*100) / 2
64 69
 	if percentage > 50 {
65 70
 		percentage = 50
... ...
@@ -73,13 +79,25 @@ func (p *JSONProgress) String() string {
73 73
 		pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces))
74 74
 	}
75 75
 
76
-	if !p.HideCounts {
76
+	switch {
77
+	case p.HideCounts:
78
+	case p.Units == "": // no units, use bytes
79
+		current := units.HumanSize(float64(p.Current))
80
+		total := units.HumanSize(float64(p.Total))
81
+
77 82
 		numbersBox = fmt.Sprintf("%8v/%v", current, total)
78 83
 
79 84
 		if p.Current > p.Total {
80 85
 			// remove total display if the reported current is wonky.
81 86
 			numbersBox = fmt.Sprintf("%8v", current)
82 87
 		}
88
+	default:
89
+		numbersBox = fmt.Sprintf("%d/%d %s", p.Current, p.Total, p.Units)
90
+
91
+		if p.Current > p.Total {
92
+			// remove total display if the reported current is wonky.
93
+			numbersBox = fmt.Sprintf("%d %s", p.Current, p.Units)
94
+		}
83 95
 	}
84 96
 
85 97
 	if p.Current > 0 && p.Start > 0 && percentage < 50 {
... ...
@@ -65,22 +65,50 @@ func TestProgress(t *testing.T) {
65 65
 	if jp5.String() != expected {
66 66
 		t.Fatalf("Expected %q, got %q", expected, jp5.String())
67 67
 	}
68
+
69
+	expected = "[=========================>                         ] 50/100 units"
70
+	if termsz != nil && termsz.Width <= 110 {
71
+		expected = "    50/100 units"
72
+	}
73
+	jp6 := JSONProgress{Current: 50, Total: 100, Units: "units"}
74
+	if jp6.String() != expected {
75
+		t.Fatalf("Expected %q, got %q", expected, jp6.String())
76
+	}
77
+
78
+	// this number can't be negative
79
+	expected = "[==================================================>] 50 units"
80
+	if termsz != nil && termsz.Width <= 110 {
81
+		expected = "    50 units"
82
+	}
83
+	jp7 := JSONProgress{Current: 50, Total: 40, Units: "units"}
84
+	if jp7.String() != expected {
85
+		t.Fatalf("Expected %q, got %q", expected, jp7.String())
86
+	}
87
+
88
+	expected = "[=========================>                         ] "
89
+	if termsz != nil && termsz.Width <= 110 {
90
+		expected = ""
91
+	}
92
+	jp8 := JSONProgress{Current: 50, Total: 100, HideCounts: true}
93
+	if jp8.String() != expected {
94
+		t.Fatalf("Expected %q, got %q", expected, jp8.String())
95
+	}
68 96
 }
69 97
 
70 98
 func TestJSONMessageDisplay(t *testing.T) {
71 99
 	now := time.Now()
72 100
 	messages := map[JSONMessage][]string{
73 101
 		// Empty
74
-		JSONMessage{}: {"\n", "\n"},
102
+		{}: {"\n", "\n"},
75 103
 		// Status
76
-		JSONMessage{
104
+		{
77 105
 			Status: "status",
78 106
 		}: {
79 107
 			"status\n",
80 108
 			"status\n",
81 109
 		},
82 110
 		// General
83
-		JSONMessage{
111
+		{
84 112
 			Time:   now.Unix(),
85 113
 			ID:     "ID",
86 114
 			From:   "From",
... ...
@@ -90,7 +118,7 @@ func TestJSONMessageDisplay(t *testing.T) {
90 90
 			fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now.Unix(), 0).Format(jsonlog.RFC3339NanoFixed)),
91 91
 		},
92 92
 		// General, with nano precision time
93
-		JSONMessage{
93
+		{
94 94
 			TimeNano: now.UnixNano(),
95 95
 			ID:       "ID",
96 96
 			From:     "From",
... ...
@@ -100,7 +128,7 @@ func TestJSONMessageDisplay(t *testing.T) {
100 100
 			fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)),
101 101
 		},
102 102
 		// General, with both times Nano is preferred
103
-		JSONMessage{
103
+		{
104 104
 			Time:     now.Unix(),
105 105
 			TimeNano: now.UnixNano(),
106 106
 			ID:       "ID",
... ...
@@ -111,7 +139,7 @@ func TestJSONMessageDisplay(t *testing.T) {
111 111
 			fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)),
112 112
 		},
113 113
 		// Stream over status
114
-		JSONMessage{
114
+		{
115 115
 			Status: "status",
116 116
 			Stream: "stream",
117 117
 		}: {
... ...
@@ -119,7 +147,7 @@ func TestJSONMessageDisplay(t *testing.T) {
119 119
 			"stream",
120 120
 		},
121 121
 		// With progress message
122
-		JSONMessage{
122
+		{
123 123
 			Status:          "status",
124 124
 			ProgressMessage: "progressMessage",
125 125
 		}: {
... ...
@@ -127,7 +155,7 @@ func TestJSONMessageDisplay(t *testing.T) {
127 127
 			"status progressMessage",
128 128
 		},
129 129
 		// With progress, stream empty
130
-		JSONMessage{
130
+		{
131 131
 			Status:   "status",
132 132
 			Stream:   "",
133 133
 			Progress: &JSONProgress{Current: 1},
... ...
@@ -18,6 +18,8 @@ type Progress struct {
18 18
 
19 19
 	// If true, don't show xB/yB
20 20
 	HideCounts bool
21
+	// If not empty, use units instead of bytes for counts
22
+	Units string
21 23
 
22 24
 	// Aux contains extra information not presented to the user, such as
23 25
 	// digests for push signing.
... ...
@@ -117,7 +117,7 @@ func (out *progressOutput) WriteProgress(prog progress.Progress) error {
117 117
 	if prog.Message != "" {
118 118
 		formatted = out.sf.formatStatus(prog.ID, prog.Message)
119 119
 	} else {
120
-		jsonProgress := jsonmessage.JSONProgress{Current: prog.Current, Total: prog.Total, HideCounts: prog.HideCounts}
120
+		jsonProgress := jsonmessage.JSONProgress{Current: prog.Current, Total: prog.Total, HideCounts: prog.HideCounts, Units: prog.Units}
121 121
 		formatted = out.sf.formatProgress(prog.ID, prog.Action, &jsonProgress, prog.Aux)
122 122
 	}
123 123
 	_, err := out.out.Write(formatted)