Merge pull request #2999 from dotcloud/improve_progress_bars

Handle small screens
This commit is contained in:
Victor Vieux 2013-12-03 14:24:40 -08:00
commit f8176de191
3 changed files with 48 additions and 15 deletions

View File

@ -2303,7 +2303,7 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, h
}
if matchesContentType(resp.Header.Get("Content-Type"), "application/json") {
return utils.DisplayJSONMessagesStream(resp.Body, out, cli.isTerminal)
return utils.DisplayJSONMessagesStream(resp.Body, out, cli.terminalFd, cli.isTerminal)
}
if _, err := io.Copy(out, resp.Body); err != nil {
return err

View File

@ -3,6 +3,7 @@ package utils
import (
"encoding/json"
"fmt"
"github.com/dotcloud/docker/term"
"io"
"strings"
"time"
@ -18,27 +19,50 @@ func (e *JSONError) Error() string {
}
type JSONProgress struct {
Current int `json:"current,omitempty"`
Total int `json:"total,omitempty"`
Start int64 `json:"start,omitempty"`
terminalFd uintptr
Current int `json:"current,omitempty"`
Total int `json:"total,omitempty"`
Start int64 `json:"start,omitempty"`
}
func (p *JSONProgress) String() string {
var (
width = 200
pbBox string
numbersBox string
timeLeftBox string
)
ws, err := term.GetWinsize(p.terminalFd)
if err == nil {
width = int(ws.Width)
}
if p.Current == 0 && p.Total == 0 {
return ""
}
current := HumanSize(int64(p.Current))
if p.Total == 0 {
return fmt.Sprintf("%8v/?", current)
return fmt.Sprintf("%8v", current)
}
total := HumanSize(int64(p.Total))
percentage := int(float64(p.Current)/float64(p.Total)*100) / 2
if width > 110 {
pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", 50-percentage))
}
numbersBox = fmt.Sprintf("%8v/%v", current, total)
fromStart := time.Now().UTC().Sub(time.Unix(int64(p.Start), 0))
perEntry := fromStart / time.Duration(p.Current)
left := time.Duration(p.Total-p.Current) * perEntry
left = (left / time.Second) * time.Second
return fmt.Sprintf("[%s>%s] %8v/%v %s", strings.Repeat("=", percentage), strings.Repeat(" ", 50-percentage), current, total, left.String())
if p.Start > 0 {
fromStart := time.Now().UTC().Sub(time.Unix(int64(p.Start), 0))
perEntry := fromStart / time.Duration(p.Current)
left := time.Duration(p.Total-p.Current) * perEntry
left = (left / time.Second) * time.Second
if width > 50 {
timeLeftBox = " " + left.String()
}
}
return pbBox + numbersBox + timeLeftBox
}
type JSONMessage struct {
@ -84,7 +108,7 @@ func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error {
return nil
}
func DisplayJSONMessagesStream(in io.Reader, out io.Writer, isTerminal bool) error {
func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool) error {
var (
dec = json.NewDecoder(in)
ids = make(map[string]int)
@ -98,6 +122,10 @@ func DisplayJSONMessagesStream(in io.Reader, out io.Writer, isTerminal bool) err
}
return err
}
if jm.Progress != nil {
jm.Progress.terminalFd = terminalFd
}
if (jm.Progress != nil || jm.ProgressMessage != "") && jm.ID != "" {
line, ok := ids[jm.ID]
if !ok {

View File

@ -12,13 +12,18 @@ func TestError(t *testing.T) {
}
func TestProgress(t *testing.T) {
jp := JSONProgress{0, 0, 0}
jp := JSONProgress{}
if jp.String() != "" {
t.Fatalf("Expected empty string, got '%s'", jp.String())
}
jp2 := JSONProgress{1, 0, 0}
if jp2.String() != " 1 B/?" {
t.Fatalf("Expected ' 1/?', got '%s'", jp2.String())
jp2 := JSONProgress{Current: 1}
if jp2.String() != " 1 B" {
t.Fatalf("Expected ' 1 B', got '%s'", jp2.String())
}
jp3 := JSONProgress{Current: 50, Total: 100}
if jp3.String() != "[=========================> ] 50 B/100 B" {
t.Fatalf("Expected '[=========================> ] 50 B/100 B', got '%s'", jp3.String())
}
}