mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #2999 from dotcloud/improve_progress_bars
Handle small screens
This commit is contained in:
commit
f8176de191
3 changed files with 48 additions and 15 deletions
|
@ -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") {
|
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 {
|
if _, err := io.Copy(out, resp.Body); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -3,6 +3,7 @@ package utils
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/dotcloud/docker/term"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -18,27 +19,50 @@ func (e *JSONError) Error() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
type JSONProgress struct {
|
type JSONProgress struct {
|
||||||
Current int `json:"current,omitempty"`
|
terminalFd uintptr
|
||||||
Total int `json:"total,omitempty"`
|
Current int `json:"current,omitempty"`
|
||||||
Start int64 `json:"start,omitempty"`
|
Total int `json:"total,omitempty"`
|
||||||
|
Start int64 `json:"start,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *JSONProgress) String() string {
|
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 {
|
if p.Current == 0 && p.Total == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
current := HumanSize(int64(p.Current))
|
current := HumanSize(int64(p.Current))
|
||||||
if p.Total == 0 {
|
if p.Total == 0 {
|
||||||
return fmt.Sprintf("%8v/?", current)
|
return fmt.Sprintf("%8v", current)
|
||||||
}
|
}
|
||||||
total := HumanSize(int64(p.Total))
|
total := HumanSize(int64(p.Total))
|
||||||
percentage := int(float64(p.Current)/float64(p.Total)*100) / 2
|
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))
|
if p.Start > 0 {
|
||||||
perEntry := fromStart / time.Duration(p.Current)
|
fromStart := time.Now().UTC().Sub(time.Unix(int64(p.Start), 0))
|
||||||
left := time.Duration(p.Total-p.Current) * perEntry
|
perEntry := fromStart / time.Duration(p.Current)
|
||||||
left = (left / time.Second) * time.Second
|
left := time.Duration(p.Total-p.Current) * perEntry
|
||||||
return fmt.Sprintf("[%s>%s] %8v/%v %s", strings.Repeat("=", percentage), strings.Repeat(" ", 50-percentage), current, total, left.String())
|
left = (left / time.Second) * time.Second
|
||||||
|
|
||||||
|
if width > 50 {
|
||||||
|
timeLeftBox = " " + left.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pbBox + numbersBox + timeLeftBox
|
||||||
}
|
}
|
||||||
|
|
||||||
type JSONMessage struct {
|
type JSONMessage struct {
|
||||||
|
@ -84,7 +108,7 @@ func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error {
|
||||||
return nil
|
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 (
|
var (
|
||||||
dec = json.NewDecoder(in)
|
dec = json.NewDecoder(in)
|
||||||
ids = make(map[string]int)
|
ids = make(map[string]int)
|
||||||
|
@ -98,6 +122,10 @@ func DisplayJSONMessagesStream(in io.Reader, out io.Writer, isTerminal bool) err
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if jm.Progress != nil {
|
||||||
|
jm.Progress.terminalFd = terminalFd
|
||||||
|
}
|
||||||
if (jm.Progress != nil || jm.ProgressMessage != "") && jm.ID != "" {
|
if (jm.Progress != nil || jm.ProgressMessage != "") && jm.ID != "" {
|
||||||
line, ok := ids[jm.ID]
|
line, ok := ids[jm.ID]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -12,13 +12,18 @@ func TestError(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProgress(t *testing.T) {
|
func TestProgress(t *testing.T) {
|
||||||
jp := JSONProgress{0, 0, 0}
|
jp := JSONProgress{}
|
||||||
if jp.String() != "" {
|
if jp.String() != "" {
|
||||||
t.Fatalf("Expected empty string, got '%s'", jp.String())
|
t.Fatalf("Expected empty string, got '%s'", jp.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
jp2 := JSONProgress{1, 0, 0}
|
jp2 := JSONProgress{Current: 1}
|
||||||
if jp2.String() != " 1 B/?" {
|
if jp2.String() != " 1 B" {
|
||||||
t.Fatalf("Expected ' 1/?', got '%s'", jp2.String())
|
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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue