github.com/walkingsparrow/docker@v1.4.2-0.20151218153551-b708a2249bfa/pkg/streamformatter/streamformatter.go (about) 1 // Package streamformatter provides helper functions to format a stream. 2 package streamformatter 3 4 import ( 5 "encoding/json" 6 "fmt" 7 "io" 8 9 "github.com/docker/docker/pkg/jsonmessage" 10 "github.com/docker/docker/pkg/progress" 11 ) 12 13 // StreamFormatter formats a stream, optionally using JSON. 14 type StreamFormatter struct { 15 json bool 16 } 17 18 // NewStreamFormatter returns a simple StreamFormatter 19 func NewStreamFormatter() *StreamFormatter { 20 return &StreamFormatter{} 21 } 22 23 // NewJSONStreamFormatter returns a StreamFormatter configured to stream json 24 func NewJSONStreamFormatter() *StreamFormatter { 25 return &StreamFormatter{true} 26 } 27 28 const streamNewline = "\r\n" 29 30 var streamNewlineBytes = []byte(streamNewline) 31 32 // FormatStream formats the specified stream. 33 func (sf *StreamFormatter) FormatStream(str string) []byte { 34 if sf.json { 35 b, err := json.Marshal(&jsonmessage.JSONMessage{Stream: str}) 36 if err != nil { 37 return sf.FormatError(err) 38 } 39 return append(b, streamNewlineBytes...) 40 } 41 return []byte(str + "\r") 42 } 43 44 // FormatStatus formats the specified objects according to the specified format (and id). 45 func (sf *StreamFormatter) FormatStatus(id, format string, a ...interface{}) []byte { 46 str := fmt.Sprintf(format, a...) 47 if sf.json { 48 b, err := json.Marshal(&jsonmessage.JSONMessage{ID: id, Status: str}) 49 if err != nil { 50 return sf.FormatError(err) 51 } 52 return append(b, streamNewlineBytes...) 53 } 54 return []byte(str + streamNewline) 55 } 56 57 // FormatError formats the specified error. 58 func (sf *StreamFormatter) FormatError(err error) []byte { 59 if sf.json { 60 jsonError, ok := err.(*jsonmessage.JSONError) 61 if !ok { 62 jsonError = &jsonmessage.JSONError{Message: err.Error()} 63 } 64 if b, err := json.Marshal(&jsonmessage.JSONMessage{Error: jsonError, ErrorMessage: err.Error()}); err == nil { 65 return append(b, streamNewlineBytes...) 66 } 67 return []byte("{\"error\":\"format error\"}" + streamNewline) 68 } 69 return []byte("Error: " + err.Error() + streamNewline) 70 } 71 72 // FormatProgress formats the progress information for a specified action. 73 func (sf *StreamFormatter) FormatProgress(id, action string, progress *jsonmessage.JSONProgress) []byte { 74 if progress == nil { 75 progress = &jsonmessage.JSONProgress{} 76 } 77 if sf.json { 78 b, err := json.Marshal(&jsonmessage.JSONMessage{ 79 Status: action, 80 ProgressMessage: progress.String(), 81 Progress: progress, 82 ID: id, 83 }) 84 if err != nil { 85 return nil 86 } 87 return append(b, streamNewlineBytes...) 88 } 89 endl := "\r" 90 if progress.String() == "" { 91 endl += "\n" 92 } 93 return []byte(action + " " + progress.String() + endl) 94 } 95 96 // NewProgressOutput returns a progress.Output object that can be passed to 97 // progress.NewProgressReader. 98 func (sf *StreamFormatter) NewProgressOutput(out io.Writer, newLines bool) progress.Output { 99 return &progressOutput{ 100 sf: sf, 101 out: out, 102 newLines: newLines, 103 } 104 } 105 106 type progressOutput struct { 107 sf *StreamFormatter 108 out io.Writer 109 newLines bool 110 } 111 112 // WriteProgress formats progress information from a ProgressReader. 113 func (out *progressOutput) WriteProgress(prog progress.Progress) error { 114 var formatted []byte 115 if prog.Message != "" { 116 formatted = out.sf.FormatStatus(prog.ID, prog.Message) 117 } else { 118 jsonProgress := jsonmessage.JSONProgress{Current: prog.Current, Total: prog.Total} 119 formatted = out.sf.FormatProgress(prog.ID, prog.Action, &jsonProgress) 120 } 121 _, err := out.out.Write(formatted) 122 if err != nil { 123 return err 124 } 125 126 if out.newLines && prog.LastUpdate { 127 _, err = out.out.Write(out.sf.FormatStatus("", "")) 128 return err 129 } 130 131 return nil 132 } 133 134 // StdoutFormatter is a streamFormatter that writes to the standard output. 135 type StdoutFormatter struct { 136 io.Writer 137 *StreamFormatter 138 } 139 140 func (sf *StdoutFormatter) Write(buf []byte) (int, error) { 141 formattedBuf := sf.StreamFormatter.FormatStream(string(buf)) 142 n, err := sf.Writer.Write(formattedBuf) 143 if n != len(formattedBuf) { 144 return n, io.ErrShortWrite 145 } 146 return len(buf), err 147 } 148 149 // StderrFormatter is a streamFormatter that writes to the standard error. 150 type StderrFormatter struct { 151 io.Writer 152 *StreamFormatter 153 } 154 155 func (sf *StderrFormatter) Write(buf []byte) (int, error) { 156 formattedBuf := sf.StreamFormatter.FormatStream("\033[91m" + string(buf) + "\033[0m") 157 n, err := sf.Writer.Write(formattedBuf) 158 if n != len(formattedBuf) { 159 return n, io.ErrShortWrite 160 } 161 return len(buf), err 162 }