Browse code

Handle small screens

Victor Vieux authored on 2013/12/03 04:53:04
Showing 3 changed files
... ...
@@ -2294,7 +2294,7 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, h
2294 2294
 	}
2295 2295
 
2296 2296
 	if matchesContentType(resp.Header.Get("Content-Type"), "application/json") {
2297
-		return utils.DisplayJSONMessagesStream(resp.Body, out, cli.isTerminal)
2297
+		return utils.DisplayJSONMessagesStream(resp.Body, out, cli.terminalFd, cli.isTerminal)
2298 2298
 	}
2299 2299
 	if _, err := io.Copy(out, resp.Body); err != nil {
2300 2300
 		return err
... ...
@@ -3,6 +3,7 @@ package utils
3 3
 import (
4 4
 	"encoding/json"
5 5
 	"fmt"
6
+	"github.com/dotcloud/docker/term"
6 7
 	"io"
7 8
 	"strings"
8 9
 	"time"
... ...
@@ -18,27 +19,50 @@ func (e *JSONError) Error() string {
18 18
 }
19 19
 
20 20
 type JSONProgress struct {
21
-	Current int   `json:"current,omitempty"`
22
-	Total   int   `json:"total,omitempty"`
23
-	Start   int64 `json:"start,omitempty"`
21
+	terminalFd uintptr
22
+	Current    int   `json:"current,omitempty"`
23
+	Total      int   `json:"total,omitempty"`
24
+	Start      int64 `json:"start,omitempty"`
24 25
 }
25 26
 
26 27
 func (p *JSONProgress) String() string {
28
+	var (
29
+		width       = 200
30
+		pbBox       string
31
+		numbersBox  string
32
+		timeLeftBox string
33
+	)
34
+
35
+	ws, err := term.GetWinsize(p.terminalFd)
36
+	if err == nil {
37
+		width = int(ws.Width)
38
+	}
39
+
27 40
 	if p.Current == 0 && p.Total == 0 {
28 41
 		return ""
29 42
 	}
30 43
 	current := HumanSize(int64(p.Current))
31 44
 	if p.Total == 0 {
32
-		return fmt.Sprintf("%8v/?", current)
45
+		return fmt.Sprintf("%8v", current)
33 46
 	}
34 47
 	total := HumanSize(int64(p.Total))
35 48
 	percentage := int(float64(p.Current)/float64(p.Total)*100) / 2
49
+	if width > 110 {
50
+		pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", 50-percentage))
51
+	}
52
+	numbersBox = fmt.Sprintf("%8v/%v", current, total)
36 53
 
37
-	fromStart := time.Now().UTC().Sub(time.Unix(int64(p.Start), 0))
38
-	perEntry := fromStart / time.Duration(p.Current)
39
-	left := time.Duration(p.Total-p.Current) * perEntry
40
-	left = (left / time.Second) * time.Second
41
-	return fmt.Sprintf("[%s>%s] %8v/%v %s", strings.Repeat("=", percentage), strings.Repeat(" ", 50-percentage), current, total, left.String())
54
+	if p.Start > 0 {
55
+		fromStart := time.Now().UTC().Sub(time.Unix(int64(p.Start), 0))
56
+		perEntry := fromStart / time.Duration(p.Current)
57
+		left := time.Duration(p.Total-p.Current) * perEntry
58
+		left = (left / time.Second) * time.Second
59
+
60
+		if width > 50 {
61
+			timeLeftBox = " " + left.String()
62
+		}
63
+	}
64
+	return pbBox + numbersBox + timeLeftBox
42 65
 }
43 66
 
44 67
 type JSONMessage struct {
... ...
@@ -84,7 +108,7 @@ func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error {
84 84
 	return nil
85 85
 }
86 86
 
87
-func DisplayJSONMessagesStream(in io.Reader, out io.Writer, isTerminal bool) error {
87
+func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool) error {
88 88
 	var (
89 89
 		dec  = json.NewDecoder(in)
90 90
 		ids  = make(map[string]int)
... ...
@@ -98,6 +122,10 @@ func DisplayJSONMessagesStream(in io.Reader, out io.Writer, isTerminal bool) err
98 98
 			}
99 99
 			return err
100 100
 		}
101
+
102
+		if jm.Progress != nil {
103
+			jm.Progress.terminalFd = terminalFd
104
+		}
101 105
 		if (jm.Progress != nil || jm.ProgressMessage != "") && jm.ID != "" {
102 106
 			line, ok := ids[jm.ID]
103 107
 			if !ok {
... ...
@@ -12,13 +12,18 @@ func TestError(t *testing.T) {
12 12
 }
13 13
 
14 14
 func TestProgress(t *testing.T) {
15
-	jp := JSONProgress{0, 0, 0}
15
+	jp := JSONProgress{}
16 16
 	if jp.String() != "" {
17 17
 		t.Fatalf("Expected empty string, got '%s'", jp.String())
18 18
 	}
19 19
 
20
-	jp2 := JSONProgress{1, 0, 0}
21
-	if jp2.String() != "     1 B/?" {
22
-		t.Fatalf("Expected '     1/?', got '%s'", jp2.String())
20
+	jp2 := JSONProgress{Current: 1}
21
+	if jp2.String() != "     1 B" {
22
+		t.Fatalf("Expected '     1 B', got '%s'", jp2.String())
23
+	}
24
+
25
+	jp3 := JSONProgress{Current: 50, Total: 100}
26
+	if jp3.String() != "[=========================>                         ]     50 B/100 B" {
27
+		t.Fatalf("Expected '[=========================>                         ]     50 B/100 B', got '%s'", jp3.String())
23 28
 	}
24 29
 }