moby/utils/jsonmessage.go

170 lines
4.2 KiB
Go
Raw Normal View History

2013-11-28 20:16:57 +00:00
package utils
import (
"encoding/json"
"fmt"
"io"
2013-11-28 20:37:07 +00:00
"strings"
2013-11-28 20:16:57 +00:00
"time"
"github.com/docker/docker/pkg/term"
"github.com/docker/docker/pkg/timeutils"
"github.com/docker/docker/pkg/units"
2013-11-28 20:16:57 +00:00
)
type JSONError struct {
Code int `json:"code,omitempty"`
Message string `json:"message,omitempty"`
}
func (e *JSONError) Error() string {
return e.Message
}
type JSONProgress struct {
2013-12-02 19:53:04 +00:00
terminalFd uintptr
Current int `json:"current,omitempty"`
Total int `json:"total,omitempty"`
Start int64 `json:"start,omitempty"`
2013-11-28 20:16:57 +00:00
}
func (p *JSONProgress) String() string {
2013-12-02 19:53:04 +00:00
var (
width = 200
pbBox string
numbersBox string
timeLeftBox string
)
ws, err := term.GetWinsize(p.terminalFd)
if err == nil {
width = int(ws.Width)
}
2013-12-04 19:57:18 +00:00
if p.Current <= 0 && p.Total <= 0 {
2013-11-28 20:16:57 +00:00
return ""
}
current := units.HumanSize(float64(p.Current))
2013-12-04 19:57:18 +00:00
if p.Total <= 0 {
2013-12-02 19:53:04 +00:00
return fmt.Sprintf("%8v", current)
2013-11-28 20:16:57 +00:00
}
total := units.HumanSize(float64(p.Total))
2013-11-28 20:37:07 +00:00
percentage := int(float64(p.Current)/float64(p.Total)*100) / 2
2013-12-02 19:53:04 +00:00
if width > 110 {
// this number can't be negetive gh#7136
numSpaces := 0
if 50-percentage > 0 {
numSpaces = 50 - percentage
}
pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces))
2013-12-02 19:53:04 +00:00
}
numbersBox = fmt.Sprintf("%8v/%v", current, total)
2013-11-28 20:37:07 +00:00
if p.Current > 0 && p.Start > 0 && percentage < 50 {
2013-12-02 19:53:04 +00:00
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
2013-11-28 20:16:57 +00:00
}
type JSONMessage struct {
2013-12-06 19:55:56 +00:00
Stream string `json:"stream,omitempty"`
2013-11-28 20:16:57 +00:00
Status string `json:"status,omitempty"`
Progress *JSONProgress `json:"progressDetail,omitempty"`
ProgressMessage string `json:"progress,omitempty"` //deprecated
ID string `json:"id,omitempty"`
From string `json:"from,omitempty"`
Time int64 `json:"time,omitempty"`
Error *JSONError `json:"errorDetail,omitempty"`
ErrorMessage string `json:"error,omitempty"` //deprecated
}
func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error {
if jm.Error != nil {
if jm.Error.Code == 401 {
return fmt.Errorf("Authentication is required.")
}
return jm.Error
}
2013-12-02 19:49:11 +00:00
var endl string
if isTerminal && jm.Stream == "" && jm.Progress != nil {
2013-11-28 20:16:57 +00:00
// <ESC>[2K = erase entire current line
fmt.Fprintf(out, "%c[2K\r", 27)
2013-12-06 19:55:56 +00:00
endl = "\r"
} else if jm.Progress != nil && jm.Progress.String() != "" { //disable progressbar in non-terminal
2013-12-06 21:56:09 +00:00
return nil
2013-11-28 20:16:57 +00:00
}
if jm.Time != 0 {
fmt.Fprintf(out, "%s ", time.Unix(jm.Time, 0).Format(timeutils.RFC3339NanoFixed))
2013-11-28 20:16:57 +00:00
}
if jm.ID != "" {
fmt.Fprintf(out, "%s: ", jm.ID)
}
if jm.From != "" {
fmt.Fprintf(out, "(from %s) ", jm.From)
}
if jm.Progress != nil && isTerminal {
2013-11-28 20:16:57 +00:00
fmt.Fprintf(out, "%s %s%s", jm.Status, jm.Progress.String(), endl)
} else if jm.ProgressMessage != "" { //deprecated
fmt.Fprintf(out, "%s %s%s", jm.Status, jm.ProgressMessage, endl)
2013-12-06 19:55:56 +00:00
} else if jm.Stream != "" {
fmt.Fprintf(out, "%s%s", jm.Stream, endl)
2013-11-28 20:16:57 +00:00
} else {
2013-12-06 19:55:56 +00:00
fmt.Fprintf(out, "%s%s\n", jm.Status, endl)
2013-11-28 20:16:57 +00:00
}
return nil
}
2013-12-02 19:53:04 +00:00
func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool) error {
2013-12-02 19:49:11 +00:00
var (
dec = json.NewDecoder(in)
ids = make(map[string]int)
diff = 0
)
2013-11-28 20:16:57 +00:00
for {
2013-12-02 19:49:11 +00:00
var jm JSONMessage
if err := dec.Decode(&jm); err != nil {
if err == io.EOF {
break
}
2013-11-28 20:16:57 +00:00
return err
}
2013-12-02 19:53:04 +00:00
if jm.Progress != nil {
jm.Progress.terminalFd = terminalFd
}
if jm.ID != "" && (jm.Progress != nil || jm.ProgressMessage != "") {
2013-11-28 20:16:57 +00:00
line, ok := ids[jm.ID]
if !ok {
line = len(ids)
ids[jm.ID] = line
if isTerminal {
fmt.Fprintf(out, "\n")
}
2013-11-28 20:16:57 +00:00
diff = 0
} else {
diff = len(ids) - line
}
if jm.ID != "" && isTerminal {
2013-11-28 20:16:57 +00:00
// <ESC>[{diff}A = move cursor up diff rows
fmt.Fprintf(out, "%c[%dA", 27, diff)
}
}
err := jm.Display(out, isTerminal)
if jm.ID != "" && isTerminal {
// <ESC>[{diff}B = move cursor down diff rows
fmt.Fprintf(out, "%c[%dB", 27, diff)
2013-11-28 20:16:57 +00:00
}
if err != nil {
return err
}
}
return nil
}