diff --git a/daemon/cluster/convert/swarm.go b/daemon/cluster/convert/swarm.go index c6e1f3652b..0d5c8738c9 100644 --- a/daemon/cluster/convert/swarm.go +++ b/daemon/cluster/convert/swarm.go @@ -123,7 +123,7 @@ func MergeSwarmSpecToGRPC(s types.Spec, spec swarmapi.ClusterSpec) (swarmapi.Clu spec.CAConfig.SigningCACert = []byte(s.CAConfig.SigningCACert) } if s.CAConfig.SigningCAKey != "" { - // do prpagate the signing CA key here because we want to provide it TO the swarm APIs + // do propagate the signing CA key here because we want to provide it TO the swarm APIs spec.CAConfig.SigningCAKey = []byte(s.CAConfig.SigningCAKey) } spec.CAConfig.ForceRotate = s.CAConfig.ForceRotate diff --git a/pkg/jsonmessage/jsonmessage.go b/pkg/jsonmessage/jsonmessage.go index 2b8e98c429..dc785d6187 100644 --- a/pkg/jsonmessage/jsonmessage.go +++ b/pkg/jsonmessage/jsonmessage.go @@ -36,7 +36,8 @@ type JSONProgress struct { Total int64 `json:"total,omitempty"` Start int64 `json:"start,omitempty"` // If true, don't show xB/yB - HideCounts bool `json:"hidecounts,omitempty"` + HideCounts bool `json:"hidecounts,omitempty"` + Units string `json:"units,omitempty"` } func (p *JSONProgress) String() string { @@ -55,11 +56,16 @@ func (p *JSONProgress) String() string { if p.Current <= 0 && p.Total <= 0 { return "" } - current := units.HumanSize(float64(p.Current)) if p.Total <= 0 { - return fmt.Sprintf("%8v", current) + switch p.Units { + case "": + current := units.HumanSize(float64(p.Current)) + return fmt.Sprintf("%8v", current) + default: + return fmt.Sprintf("%d %s", p.Current, p.Units) + } } - total := units.HumanSize(float64(p.Total)) + percentage := int(float64(p.Current)/float64(p.Total)*100) / 2 if percentage > 50 { percentage = 50 @@ -73,13 +79,25 @@ func (p *JSONProgress) String() string { pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces)) } - if !p.HideCounts { + switch { + case p.HideCounts: + case p.Units == "": // no units, use bytes + current := units.HumanSize(float64(p.Current)) + total := units.HumanSize(float64(p.Total)) + numbersBox = fmt.Sprintf("%8v/%v", current, total) if p.Current > p.Total { // remove total display if the reported current is wonky. numbersBox = fmt.Sprintf("%8v", current) } + default: + numbersBox = fmt.Sprintf("%d/%d %s", p.Current, p.Total, p.Units) + + if p.Current > p.Total { + // remove total display if the reported current is wonky. + numbersBox = fmt.Sprintf("%d %s", p.Current, p.Units) + } } if p.Current > 0 && p.Start > 0 && percentage < 50 { diff --git a/pkg/jsonmessage/jsonmessage_test.go b/pkg/jsonmessage/jsonmessage_test.go index ce3b6de8c0..c3ed6c046a 100644 --- a/pkg/jsonmessage/jsonmessage_test.go +++ b/pkg/jsonmessage/jsonmessage_test.go @@ -65,22 +65,50 @@ func TestProgress(t *testing.T) { if jp5.String() != expected { t.Fatalf("Expected %q, got %q", expected, jp5.String()) } + + expected = "[=========================> ] 50/100 units" + if termsz != nil && termsz.Width <= 110 { + expected = " 50/100 units" + } + jp6 := JSONProgress{Current: 50, Total: 100, Units: "units"} + if jp6.String() != expected { + t.Fatalf("Expected %q, got %q", expected, jp6.String()) + } + + // this number can't be negative + expected = "[==================================================>] 50 units" + if termsz != nil && termsz.Width <= 110 { + expected = " 50 units" + } + jp7 := JSONProgress{Current: 50, Total: 40, Units: "units"} + if jp7.String() != expected { + t.Fatalf("Expected %q, got %q", expected, jp7.String()) + } + + expected = "[=========================> ] " + if termsz != nil && termsz.Width <= 110 { + expected = "" + } + jp8 := JSONProgress{Current: 50, Total: 100, HideCounts: true} + if jp8.String() != expected { + t.Fatalf("Expected %q, got %q", expected, jp8.String()) + } } func TestJSONMessageDisplay(t *testing.T) { now := time.Now() messages := map[JSONMessage][]string{ // Empty - JSONMessage{}: {"\n", "\n"}, + {}: {"\n", "\n"}, // Status - JSONMessage{ + { Status: "status", }: { "status\n", "status\n", }, // General - JSONMessage{ + { Time: now.Unix(), ID: "ID", From: "From", @@ -90,7 +118,7 @@ func TestJSONMessageDisplay(t *testing.T) { fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now.Unix(), 0).Format(jsonlog.RFC3339NanoFixed)), }, // General, with nano precision time - JSONMessage{ + { TimeNano: now.UnixNano(), ID: "ID", From: "From", @@ -100,7 +128,7 @@ func TestJSONMessageDisplay(t *testing.T) { fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)), }, // General, with both times Nano is preferred - JSONMessage{ + { Time: now.Unix(), TimeNano: now.UnixNano(), ID: "ID", @@ -111,7 +139,7 @@ func TestJSONMessageDisplay(t *testing.T) { fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)), }, // Stream over status - JSONMessage{ + { Status: "status", Stream: "stream", }: { @@ -119,7 +147,7 @@ func TestJSONMessageDisplay(t *testing.T) { "stream", }, // With progress message - JSONMessage{ + { Status: "status", ProgressMessage: "progressMessage", }: { @@ -127,7 +155,7 @@ func TestJSONMessageDisplay(t *testing.T) { "status progressMessage", }, // With progress, stream empty - JSONMessage{ + { Status: "status", Stream: "", Progress: &JSONProgress{Current: 1}, diff --git a/pkg/progress/progress.go b/pkg/progress/progress.go index e78fc120b6..7c3d3a5145 100644 --- a/pkg/progress/progress.go +++ b/pkg/progress/progress.go @@ -18,6 +18,8 @@ type Progress struct { // If true, don't show xB/yB HideCounts bool + // If not empty, use units instead of bytes for counts + Units string // Aux contains extra information not presented to the user, such as // digests for push signing. diff --git a/pkg/streamformatter/streamformatter.go b/pkg/streamformatter/streamformatter.go index 48ba65503c..c4f55755ec 100644 --- a/pkg/streamformatter/streamformatter.go +++ b/pkg/streamformatter/streamformatter.go @@ -117,7 +117,7 @@ func (out *progressOutput) WriteProgress(prog progress.Progress) error { if prog.Message != "" { formatted = out.sf.formatStatus(prog.ID, prog.Message) } else { - jsonProgress := jsonmessage.JSONProgress{Current: prog.Current, Total: prog.Total, HideCounts: prog.HideCounts} + jsonProgress := jsonmessage.JSONProgress{Current: prog.Current, Total: prog.Total, HideCounts: prog.HideCounts, Units: prog.Units} formatted = out.sf.formatProgress(prog.ID, prog.Action, &jsonProgress, prog.Aux) } _, err := out.out.Write(formatted)