Browse code

Fixes hacks from progressreader refactor

related to #10959

Signed-off-by: bobby abbott <ttobbaybbob@gmail.com>

bobby abbott authored on 2015/03/18 11:18:41
Showing 22 changed files
... ...
@@ -22,9 +22,11 @@ import (
22 22
 	"github.com/docker/docker/graph"
23 23
 	"github.com/docker/docker/pkg/archive"
24 24
 	"github.com/docker/docker/pkg/fileutils"
25
+	"github.com/docker/docker/pkg/jsonmessage"
25 26
 	flag "github.com/docker/docker/pkg/mflag"
26 27
 	"github.com/docker/docker/pkg/parsers"
27 28
 	"github.com/docker/docker/pkg/progressreader"
29
+	"github.com/docker/docker/pkg/streamformatter"
28 30
 	"github.com/docker/docker/pkg/symlink"
29 31
 	"github.com/docker/docker/pkg/units"
30 32
 	"github.com/docker/docker/pkg/urlutil"
... ...
@@ -198,7 +200,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
198 198
 	// Setup an upload progress bar
199 199
 	// FIXME: ProgressReader shouldn't be this annoying to use
200 200
 	if context != nil {
201
-		sf := utils.NewStreamFormatter(false)
201
+		sf := streamformatter.NewStreamFormatter(false)
202 202
 		body = progressreader.New(progressreader.Config{
203 203
 			In:        context,
204 204
 			Out:       cli.out,
... ...
@@ -291,7 +293,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
291 291
 		headers.Set("Content-Type", "application/tar")
292 292
 	}
293 293
 	err = cli.stream("POST", fmt.Sprintf("/build?%s", v.Encode()), body, cli.out, headers)
294
-	if jerr, ok := err.(*utils.JSONError); ok {
294
+	if jerr, ok := err.(*jsonmessage.JSONError); ok {
295 295
 		// If no error code is set, default to 1
296 296
 		if jerr.Code == 0 {
297 297
 			jerr.Code = 1
... ...
@@ -19,11 +19,11 @@ import (
19 19
 	"github.com/docker/docker/api"
20 20
 	"github.com/docker/docker/autogen/dockerversion"
21 21
 	"github.com/docker/docker/engine"
22
+	"github.com/docker/docker/pkg/jsonmessage"
22 23
 	"github.com/docker/docker/pkg/signal"
23 24
 	"github.com/docker/docker/pkg/stdcopy"
24 25
 	"github.com/docker/docker/pkg/term"
25 26
 	"github.com/docker/docker/registry"
26
-	"github.com/docker/docker/utils"
27 27
 )
28 28
 
29 29
 var (
... ...
@@ -164,7 +164,7 @@ func (cli *DockerCli) streamHelper(method, path string, setRawTerminal bool, in
164 164
 	}
165 165
 
166 166
 	if api.MatchesContentType(resp.Header.Get("Content-Type"), "application/json") {
167
-		return utils.DisplayJSONMessagesStream(resp.Body, stdout, cli.outFd, cli.isTerminalOut)
167
+		return jsonmessage.DisplayJSONMessagesStream(resp.Body, stdout, cli.outFd, cli.isTerminalOut)
168 168
 	}
169 169
 	if stdout != nil || stderr != nil {
170 170
 		// When TTY is ON, use regular copy
... ...
@@ -32,6 +32,7 @@ import (
32 32
 	"github.com/docker/docker/pkg/listenbuffer"
33 33
 	"github.com/docker/docker/pkg/parsers"
34 34
 	"github.com/docker/docker/pkg/stdcopy"
35
+	"github.com/docker/docker/pkg/streamformatter"
35 36
 	"github.com/docker/docker/pkg/version"
36 37
 	"github.com/docker/docker/registry"
37 38
 	"github.com/docker/docker/utils"
... ...
@@ -595,7 +596,7 @@ func postImagesCreate(eng *engine.Engine, version version.Version, w http.Respon
595 595
 		if !job.Stdout.Used() {
596 596
 			return err
597 597
 		}
598
-		sf := utils.NewStreamFormatter(version.GreaterThan("1.0"))
598
+		sf := streamformatter.NewStreamFormatter(version.GreaterThan("1.0"))
599 599
 		w.Write(sf.FormatError(err))
600 600
 	}
601 601
 
... ...
@@ -680,7 +681,7 @@ func postImagesPush(eng *engine.Engine, version version.Version, w http.Response
680 680
 		if !job.Stdout.Used() {
681 681
 			return err
682 682
 		}
683
-		sf := utils.NewStreamFormatter(version.GreaterThan("1.0"))
683
+		sf := streamformatter.NewStreamFormatter(version.GreaterThan("1.0"))
684 684
 		w.Write(sf.FormatError(err))
685 685
 	}
686 686
 	return nil
... ...
@@ -1107,7 +1108,7 @@ func postBuild(eng *engine.Engine, version version.Version, w http.ResponseWrite
1107 1107
 		if !job.Stdout.Used() {
1108 1108
 			return err
1109 1109
 		}
1110
-		sf := utils.NewStreamFormatter(version.GreaterThanOrEqualTo("1.8"))
1110
+		sf := streamformatter.NewStreamFormatter(version.GreaterThanOrEqualTo("1.8"))
1111 1111
 		w.Write(sf.FormatError(err))
1112 1112
 	}
1113 1113
 	return nil
... ...
@@ -33,6 +33,7 @@ import (
33 33
 	"github.com/docker/docker/daemon"
34 34
 	"github.com/docker/docker/engine"
35 35
 	"github.com/docker/docker/pkg/fileutils"
36
+	"github.com/docker/docker/pkg/streamformatter"
36 37
 	"github.com/docker/docker/pkg/stringid"
37 38
 	"github.com/docker/docker/pkg/symlink"
38 39
 	"github.com/docker/docker/pkg/tarsum"
... ...
@@ -105,7 +106,7 @@ type Builder struct {
105 105
 
106 106
 	// Deprecated, original writer used for ImagePull. To be removed.
107 107
 	OutOld          io.Writer
108
-	StreamFormatter *utils.StreamFormatter
108
+	StreamFormatter *streamformatter.StreamFormatter
109 109
 
110 110
 	Config *runconfig.Config // runconfig for cmd, run, entrypoint etc.
111 111
 
... ...
@@ -26,6 +26,7 @@ import (
26 26
 	"github.com/docker/docker/pkg/archive"
27 27
 	"github.com/docker/docker/pkg/chrootarchive"
28 28
 	"github.com/docker/docker/pkg/ioutils"
29
+	"github.com/docker/docker/pkg/jsonmessage"
29 30
 	"github.com/docker/docker/pkg/parsers"
30 31
 	"github.com/docker/docker/pkg/progressreader"
31 32
 	"github.com/docker/docker/pkg/stringid"
... ...
@@ -601,7 +602,7 @@ func (b *Builder) run(c *daemon.Container) error {
601 601
 
602 602
 	// Wait for it to finish
603 603
 	if ret, _ := c.WaitStop(-1 * time.Second); ret != 0 {
604
-		err := &utils.JSONError{
604
+		err := &jsonmessage.JSONError{
605 605
 			Message: fmt.Sprintf("The command %v returned a non-zero code: %d", b.Config.Cmd, ret),
606 606
 			Code:    ret,
607 607
 		}
... ...
@@ -17,6 +17,7 @@ import (
17 17
 	"github.com/docker/docker/graph"
18 18
 	"github.com/docker/docker/pkg/archive"
19 19
 	"github.com/docker/docker/pkg/parsers"
20
+	"github.com/docker/docker/pkg/streamformatter"
20 21
 	"github.com/docker/docker/pkg/urlutil"
21 22
 	"github.com/docker/docker/registry"
22 23
 	"github.com/docker/docker/runconfig"
... ...
@@ -127,16 +128,16 @@ func (b *BuilderJob) CmdBuild(job *engine.Job) error {
127 127
 	}
128 128
 	defer context.Close()
129 129
 
130
-	sf := utils.NewStreamFormatter(job.GetenvBool("json"))
130
+	sf := streamformatter.NewStreamFormatter(job.GetenvBool("json"))
131 131
 
132 132
 	builder := &Builder{
133 133
 		Daemon: b.Daemon,
134 134
 		Engine: b.Engine,
135
-		OutStream: &utils.StdoutFormater{
135
+		OutStream: &streamformatter.StdoutFormater{
136 136
 			Writer:          job.Stdout,
137 137
 			StreamFormatter: sf,
138 138
 		},
139
-		ErrStream: &utils.StderrFormater{
139
+		ErrStream: &streamformatter.StderrFormater{
140 140
 			Writer:          job.Stdout,
141 141
 			StreamFormatter: sf,
142 142
 		},
... ...
@@ -10,23 +10,23 @@ import (
10 10
 	"time"
11 11
 
12 12
 	"github.com/docker/docker/engine"
13
+	"github.com/docker/docker/pkg/jsonmessage"
13 14
 	"github.com/docker/docker/pkg/parsers/filters"
14
-	"github.com/docker/docker/utils"
15 15
 )
16 16
 
17 17
 const eventsLimit = 64
18 18
 
19
-type listener chan<- *utils.JSONMessage
19
+type listener chan<- *jsonmessage.JSONMessage
20 20
 
21 21
 type Events struct {
22 22
 	mu          sync.RWMutex
23
-	events      []*utils.JSONMessage
23
+	events      []*jsonmessage.JSONMessage
24 24
 	subscribers []listener
25 25
 }
26 26
 
27 27
 func New() *Events {
28 28
 	return &Events{
29
-		events: make([]*utils.JSONMessage, 0, eventsLimit),
29
+		events: make([]*jsonmessage.JSONMessage, 0, eventsLimit),
30 30
 	}
31 31
 }
32 32
 
... ...
@@ -63,7 +63,7 @@ func (e *Events) Get(job *engine.Job) error {
63 63
 		timeout.Stop()
64 64
 	}
65 65
 
66
-	listener := make(chan *utils.JSONMessage)
66
+	listener := make(chan *jsonmessage.JSONMessage)
67 67
 	e.subscribe(listener)
68 68
 	defer e.unsubscribe(listener)
69 69
 
... ...
@@ -107,7 +107,7 @@ func (e *Events) SubscribersCount(job *engine.Job) error {
107 107
 	return nil
108 108
 }
109 109
 
110
-func writeEvent(job *engine.Job, event *utils.JSONMessage, eventFilters filters.Args) error {
110
+func writeEvent(job *engine.Job, event *jsonmessage.JSONMessage, eventFilters filters.Args) error {
111 111
 	isFiltered := func(field string, filter []string) bool {
112 112
 		if len(filter) == 0 {
113 113
 			return false
... ...
@@ -170,7 +170,7 @@ func (e *Events) subscribersCount() int {
170 170
 func (e *Events) log(action, id, from string) {
171 171
 	e.mu.Lock()
172 172
 	now := time.Now().UTC().Unix()
173
-	jm := &utils.JSONMessage{Status: action, ID: id, From: from, Time: now}
173
+	jm := &jsonmessage.JSONMessage{Status: action, ID: id, From: from, Time: now}
174 174
 	if len(e.events) == cap(e.events) {
175 175
 		// discard oldest event
176 176
 		copy(e.events, e.events[1:])
... ...
@@ -9,13 +9,13 @@ import (
9 9
 	"time"
10 10
 
11 11
 	"github.com/docker/docker/engine"
12
-	"github.com/docker/docker/utils"
12
+	"github.com/docker/docker/pkg/jsonmessage"
13 13
 )
14 14
 
15 15
 func TestEventsPublish(t *testing.T) {
16 16
 	e := New()
17
-	l1 := make(chan *utils.JSONMessage)
18
-	l2 := make(chan *utils.JSONMessage)
17
+	l1 := make(chan *jsonmessage.JSONMessage)
18
+	l2 := make(chan *jsonmessage.JSONMessage)
19 19
 	e.subscribe(l1)
20 20
 	e.subscribe(l2)
21 21
 	count := e.subscribersCount()
... ...
@@ -61,7 +61,7 @@ func TestEventsPublish(t *testing.T) {
61 61
 
62 62
 func TestEventsPublishTimeout(t *testing.T) {
63 63
 	e := New()
64
-	l := make(chan *utils.JSONMessage)
64
+	l := make(chan *jsonmessage.JSONMessage)
65 65
 	e.subscribe(l)
66 66
 
67 67
 	c := make(chan struct{})
... ...
@@ -108,9 +108,9 @@ func TestLogEvents(t *testing.T) {
108 108
 	}
109 109
 	buf = bytes.NewBuffer(buf.Bytes())
110 110
 	dec := json.NewDecoder(buf)
111
-	var msgs []utils.JSONMessage
111
+	var msgs []jsonmessage.JSONMessage
112 112
 	for {
113
-		var jm utils.JSONMessage
113
+		var jm jsonmessage.JSONMessage
114 114
 		if err := dec.Decode(&jm); err != nil {
115 115
 			if err == io.EOF {
116 116
 				break
... ...
@@ -138,8 +138,8 @@ func TestEventsCountJob(t *testing.T) {
138 138
 	if err := e.Install(eng); err != nil {
139 139
 		t.Fatal(err)
140 140
 	}
141
-	l1 := make(chan *utils.JSONMessage)
142
-	l2 := make(chan *utils.JSONMessage)
141
+	l1 := make(chan *jsonmessage.JSONMessage)
142
+	l2 := make(chan *jsonmessage.JSONMessage)
143 143
 	e.subscribe(l1)
144 144
 	e.subscribe(l2)
145 145
 	job := eng.Job("subscribers_count")
... ...
@@ -18,6 +18,7 @@ import (
18 18
 	"github.com/docker/docker/image"
19 19
 	"github.com/docker/docker/pkg/archive"
20 20
 	"github.com/docker/docker/pkg/progressreader"
21
+	"github.com/docker/docker/pkg/streamformatter"
21 22
 	"github.com/docker/docker/pkg/stringid"
22 23
 	"github.com/docker/docker/pkg/truncindex"
23 24
 	"github.com/docker/docker/runconfig"
... ...
@@ -198,7 +199,7 @@ func (graph *Graph) Register(img *image.Image, layerData archive.ArchiveReader)
198 198
 //   The archive is stored on disk and will be automatically deleted as soon as has been read.
199 199
 //   If output is not nil, a human-readable progress bar will be written to it.
200 200
 //   FIXME: does this belong in Graph? How about MktempFile, let the caller use it for archives?
201
-func (graph *Graph) TempLayerArchive(id string, sf *utils.StreamFormatter, output io.Writer) (*archive.TempArchive, error) {
201
+func (graph *Graph) TempLayerArchive(id string, sf *streamformatter.StreamFormatter, output io.Writer) (*archive.TempArchive, error) {
202 202
 	image, err := graph.Get(id)
203 203
 	if err != nil {
204 204
 		return nil, err
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	"github.com/docker/docker/engine"
12 12
 	"github.com/docker/docker/pkg/archive"
13 13
 	"github.com/docker/docker/pkg/progressreader"
14
+	"github.com/docker/docker/pkg/streamformatter"
14 15
 	"github.com/docker/docker/runconfig"
15 16
 	"github.com/docker/docker/utils"
16 17
 )
... ...
@@ -23,7 +24,7 @@ func (s *TagStore) CmdImport(job *engine.Job) error {
23 23
 		src          = job.Args[0]
24 24
 		repo         = job.Args[1]
25 25
 		tag          string
26
-		sf           = utils.NewStreamFormatter(job.GetenvBool("json"))
26
+		sf           = streamformatter.NewStreamFormatter(job.GetenvBool("json"))
27 27
 		archive      archive.ArchiveReader
28 28
 		resp         *http.Response
29 29
 		stdoutBuffer = bytes.NewBuffer(nil)
... ...
@@ -15,6 +15,7 @@ import (
15 15
 	"github.com/docker/docker/engine"
16 16
 	"github.com/docker/docker/image"
17 17
 	"github.com/docker/docker/pkg/progressreader"
18
+	"github.com/docker/docker/pkg/streamformatter"
18 19
 	"github.com/docker/docker/pkg/stringid"
19 20
 	"github.com/docker/docker/registry"
20 21
 	"github.com/docker/docker/utils"
... ...
@@ -28,7 +29,7 @@ func (s *TagStore) CmdPull(job *engine.Job) error {
28 28
 	var (
29 29
 		localName   = job.Args[0]
30 30
 		tag         string
31
-		sf          = utils.NewStreamFormatter(job.GetenvBool("json"))
31
+		sf          = streamformatter.NewStreamFormatter(job.GetenvBool("json"))
32 32
 		authConfig  = &registry.AuthConfig{}
33 33
 		metaHeaders map[string][]string
34 34
 	)
... ...
@@ -107,7 +108,7 @@ func (s *TagStore) CmdPull(job *engine.Job) error {
107 107
 	return nil
108 108
 }
109 109
 
110
-func (s *TagStore) pullRepository(r *registry.Session, out io.Writer, repoInfo *registry.RepositoryInfo, askedTag string, sf *utils.StreamFormatter, parallel bool) error {
110
+func (s *TagStore) pullRepository(r *registry.Session, out io.Writer, repoInfo *registry.RepositoryInfo, askedTag string, sf *streamformatter.StreamFormatter, parallel bool) error {
111 111
 	out.Write(sf.FormatStatus("", "Pulling repository %s", repoInfo.CanonicalName))
112 112
 
113 113
 	repoData, err := r.GetRepositoryData(repoInfo.RemoteName)
... ...
@@ -265,7 +266,7 @@ func (s *TagStore) pullRepository(r *registry.Session, out io.Writer, repoInfo *
265 265
 	return nil
266 266
 }
267 267
 
268
-func (s *TagStore) pullImage(r *registry.Session, out io.Writer, imgID, endpoint string, token []string, sf *utils.StreamFormatter) (bool, error) {
268
+func (s *TagStore) pullImage(r *registry.Session, out io.Writer, imgID, endpoint string, token []string, sf *streamformatter.StreamFormatter) (bool, error) {
269 269
 	history, err := r.GetRemoteHistory(imgID, endpoint, token)
270 270
 	if err != nil {
271 271
 		return false, err
... ...
@@ -363,7 +364,7 @@ func (s *TagStore) pullImage(r *registry.Session, out io.Writer, imgID, endpoint
363 363
 	return layers_downloaded, nil
364 364
 }
365 365
 
366
-func WriteStatus(requestedTag string, out io.Writer, sf *utils.StreamFormatter, layers_downloaded bool) {
366
+func WriteStatus(requestedTag string, out io.Writer, sf *streamformatter.StreamFormatter, layers_downloaded bool) {
367 367
 	if layers_downloaded {
368 368
 		out.Write(sf.FormatStatus("", "Status: Downloaded newer image for %s", requestedTag))
369 369
 	} else {
... ...
@@ -382,7 +383,7 @@ type downloadInfo struct {
382 382
 	err        chan error
383 383
 }
384 384
 
385
-func (s *TagStore) pullV2Repository(eng *engine.Engine, r *registry.Session, out io.Writer, repoInfo *registry.RepositoryInfo, tag string, sf *utils.StreamFormatter, parallel bool) error {
385
+func (s *TagStore) pullV2Repository(eng *engine.Engine, r *registry.Session, out io.Writer, repoInfo *registry.RepositoryInfo, tag string, sf *streamformatter.StreamFormatter, parallel bool) error {
386 386
 	endpoint, err := r.V2RegistryEndpoint(repoInfo.Index)
387 387
 	if err != nil {
388 388
 		if repoInfo.Index.Official {
... ...
@@ -428,7 +429,7 @@ func (s *TagStore) pullV2Repository(eng *engine.Engine, r *registry.Session, out
428 428
 	return nil
429 429
 }
430 430
 
431
-func (s *TagStore) pullV2Tag(eng *engine.Engine, r *registry.Session, out io.Writer, endpoint *registry.Endpoint, repoInfo *registry.RepositoryInfo, tag string, sf *utils.StreamFormatter, parallel bool, auth *registry.RequestAuthorization) (bool, error) {
431
+func (s *TagStore) pullV2Tag(eng *engine.Engine, r *registry.Session, out io.Writer, endpoint *registry.Endpoint, repoInfo *registry.RepositoryInfo, tag string, sf *streamformatter.StreamFormatter, parallel bool, auth *registry.RequestAuthorization) (bool, error) {
432 432
 	log.Debugf("Pulling tag from V2 registry: %q", tag)
433 433
 
434 434
 	manifestBytes, manifestDigest, err := r.GetV2ImageManifest(endpoint, repoInfo.RemoteName, tag, auth)
... ...
@@ -17,6 +17,7 @@ import (
17 17
 	"github.com/docker/docker/engine"
18 18
 	"github.com/docker/docker/image"
19 19
 	"github.com/docker/docker/pkg/progressreader"
20
+	"github.com/docker/docker/pkg/streamformatter"
20 21
 	"github.com/docker/docker/pkg/stringid"
21 22
 	"github.com/docker/docker/registry"
22 23
 	"github.com/docker/docker/runconfig"
... ...
@@ -130,7 +131,7 @@ type imagePushData struct {
130 130
 
131 131
 // lookupImageOnEndpoint checks the specified endpoint to see if an image exists
132 132
 // and if it is absent then it sends the image id to the channel to be pushed.
133
-func lookupImageOnEndpoint(wg *sync.WaitGroup, r *registry.Session, out io.Writer, sf *utils.StreamFormatter,
133
+func lookupImageOnEndpoint(wg *sync.WaitGroup, r *registry.Session, out io.Writer, sf *streamformatter.StreamFormatter,
134 134
 	images chan imagePushData, imagesToPush chan string) {
135 135
 	defer wg.Done()
136 136
 	for image := range images {
... ...
@@ -144,7 +145,7 @@ func lookupImageOnEndpoint(wg *sync.WaitGroup, r *registry.Session, out io.Write
144 144
 }
145 145
 
146 146
 func (s *TagStore) pushImageToEndpoint(endpoint string, out io.Writer, remoteName string, imageIDs []string,
147
-	tags map[string][]string, repo *registry.RepositoryData, sf *utils.StreamFormatter, r *registry.Session) error {
147
+	tags map[string][]string, repo *registry.RepositoryData, sf *streamformatter.StreamFormatter, r *registry.Session) error {
148 148
 	workerCount := len(imageIDs)
149 149
 	// start a maximum of 5 workers to check if images exist on the specified endpoint.
150 150
 	if workerCount > 5 {
... ...
@@ -203,7 +204,7 @@ func (s *TagStore) pushImageToEndpoint(endpoint string, out io.Writer, remoteNam
203 203
 // pushRepository pushes layers that do not already exist on the registry.
204 204
 func (s *TagStore) pushRepository(r *registry.Session, out io.Writer,
205 205
 	repoInfo *registry.RepositoryInfo, localRepo map[string]string,
206
-	tag string, sf *utils.StreamFormatter) error {
206
+	tag string, sf *streamformatter.StreamFormatter) error {
207 207
 	log.Debugf("Local repo: %s", localRepo)
208 208
 	out = utils.NewWriteFlusher(out)
209 209
 	imgList, tags, err := s.getImageList(localRepo, tag)
... ...
@@ -238,7 +239,7 @@ func (s *TagStore) pushRepository(r *registry.Session, out io.Writer,
238 238
 	return err
239 239
 }
240 240
 
241
-func (s *TagStore) pushImage(r *registry.Session, out io.Writer, imgID, ep string, token []string, sf *utils.StreamFormatter) (checksum string, err error) {
241
+func (s *TagStore) pushImage(r *registry.Session, out io.Writer, imgID, ep string, token []string, sf *streamformatter.StreamFormatter) (checksum string, err error) {
242 242
 	out = utils.NewWriteFlusher(out)
243 243
 	jsonRaw, err := ioutil.ReadFile(path.Join(s.graph.Root, imgID, "json"))
244 244
 	if err != nil {
... ...
@@ -292,7 +293,7 @@ func (s *TagStore) pushImage(r *registry.Session, out io.Writer, imgID, ep strin
292 292
 	return imgData.Checksum, nil
293 293
 }
294 294
 
295
-func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, out io.Writer, repoInfo *registry.RepositoryInfo, tag string, sf *utils.StreamFormatter) error {
295
+func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, out io.Writer, repoInfo *registry.RepositoryInfo, tag string, sf *streamformatter.StreamFormatter) error {
296 296
 	endpoint, err := r.V2RegistryEndpoint(repoInfo.Index)
297 297
 	if err != nil {
298 298
 		if repoInfo.Index.Official {
... ...
@@ -442,7 +443,7 @@ func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, o
442 442
 }
443 443
 
444 444
 // PushV2Image pushes the image content to the v2 registry, first buffering the contents to disk
445
-func (s *TagStore) pushV2Image(r *registry.Session, img *image.Image, endpoint *registry.Endpoint, imageName string, sf *utils.StreamFormatter, out io.Writer, auth *registry.RequestAuthorization) (string, error) {
445
+func (s *TagStore) pushV2Image(r *registry.Session, img *image.Image, endpoint *registry.Endpoint, imageName string, sf *streamformatter.StreamFormatter, out io.Writer, auth *registry.RequestAuthorization) (string, error) {
446 446
 	out.Write(sf.FormatProgress(stringid.TruncateID(img.ID), "Buffering to Disk", nil))
447 447
 
448 448
 	image, err := s.graph.Get(img.ID)
... ...
@@ -498,7 +499,7 @@ func (s *TagStore) CmdPush(job *engine.Job) error {
498 498
 	}
499 499
 	var (
500 500
 		localName   = job.Args[0]
501
-		sf          = utils.NewStreamFormatter(job.GetenvBool("json"))
501
+		sf          = streamformatter.NewStreamFormatter(job.GetenvBool("json"))
502 502
 		authConfig  = &registry.AuthConfig{}
503 503
 		metaHeaders map[string][]string
504 504
 	)
505 505
new file mode 100644
... ...
@@ -0,0 +1,172 @@
0
+package jsonmessage
1
+
2
+import (
3
+	"encoding/json"
4
+	"fmt"
5
+	"io"
6
+	"strings"
7
+	"time"
8
+
9
+	"github.com/docker/docker/pkg/term"
10
+	"github.com/docker/docker/pkg/timeutils"
11
+	"github.com/docker/docker/pkg/units"
12
+)
13
+
14
+type JSONError struct {
15
+	Code    int    `json:"code,omitempty"`
16
+	Message string `json:"message,omitempty"`
17
+}
18
+
19
+func (e *JSONError) Error() string {
20
+	return e.Message
21
+}
22
+
23
+type JSONProgress struct {
24
+	terminalFd uintptr
25
+	Current    int   `json:"current,omitempty"`
26
+	Total      int   `json:"total,omitempty"`
27
+	Start      int64 `json:"start,omitempty"`
28
+}
29
+
30
+func (p *JSONProgress) String() string {
31
+	var (
32
+		width       = 200
33
+		pbBox       string
34
+		numbersBox  string
35
+		timeLeftBox string
36
+	)
37
+
38
+	ws, err := term.GetWinsize(p.terminalFd)
39
+	if err == nil {
40
+		width = int(ws.Width)
41
+	}
42
+
43
+	if p.Current <= 0 && p.Total <= 0 {
44
+		return ""
45
+	}
46
+	current := units.HumanSize(float64(p.Current))
47
+	if p.Total <= 0 {
48
+		return fmt.Sprintf("%8v", current)
49
+	}
50
+	total := units.HumanSize(float64(p.Total))
51
+	percentage := int(float64(p.Current)/float64(p.Total)*100) / 2
52
+	if percentage > 50 {
53
+		percentage = 50
54
+	}
55
+	if width > 110 {
56
+		// this number can't be negetive gh#7136
57
+		numSpaces := 0
58
+		if 50-percentage > 0 {
59
+			numSpaces = 50 - percentage
60
+		}
61
+		pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces))
62
+	}
63
+	numbersBox = fmt.Sprintf("%8v/%v", current, total)
64
+
65
+	if p.Current > 0 && p.Start > 0 && percentage < 50 {
66
+		fromStart := time.Now().UTC().Sub(time.Unix(int64(p.Start), 0))
67
+		perEntry := fromStart / time.Duration(p.Current)
68
+		left := time.Duration(p.Total-p.Current) * perEntry
69
+		left = (left / time.Second) * time.Second
70
+
71
+		if width > 50 {
72
+			timeLeftBox = " " + left.String()
73
+		}
74
+	}
75
+	return pbBox + numbersBox + timeLeftBox
76
+}
77
+
78
+type JSONMessage struct {
79
+	Stream          string        `json:"stream,omitempty"`
80
+	Status          string        `json:"status,omitempty"`
81
+	Progress        *JSONProgress `json:"progressDetail,omitempty"`
82
+	ProgressMessage string        `json:"progress,omitempty"` //deprecated
83
+	ID              string        `json:"id,omitempty"`
84
+	From            string        `json:"from,omitempty"`
85
+	Time            int64         `json:"time,omitempty"`
86
+	Error           *JSONError    `json:"errorDetail,omitempty"`
87
+	ErrorMessage    string        `json:"error,omitempty"` //deprecated
88
+}
89
+
90
+func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error {
91
+	if jm.Error != nil {
92
+		if jm.Error.Code == 401 {
93
+			return fmt.Errorf("Authentication is required.")
94
+		}
95
+		return jm.Error
96
+	}
97
+	var endl string
98
+	if isTerminal && jm.Stream == "" && jm.Progress != nil {
99
+		// <ESC>[2K = erase entire current line
100
+		fmt.Fprintf(out, "%c[2K\r", 27)
101
+		endl = "\r"
102
+	} else if jm.Progress != nil && jm.Progress.String() != "" { //disable progressbar in non-terminal
103
+		return nil
104
+	}
105
+	if jm.Time != 0 {
106
+		fmt.Fprintf(out, "%s ", time.Unix(jm.Time, 0).Format(timeutils.RFC3339NanoFixed))
107
+	}
108
+	if jm.ID != "" {
109
+		fmt.Fprintf(out, "%s: ", jm.ID)
110
+	}
111
+	if jm.From != "" {
112
+		fmt.Fprintf(out, "(from %s) ", jm.From)
113
+	}
114
+	if jm.Progress != nil && isTerminal {
115
+		fmt.Fprintf(out, "%s %s%s", jm.Status, jm.Progress.String(), endl)
116
+	} else if jm.ProgressMessage != "" { //deprecated
117
+		fmt.Fprintf(out, "%s %s%s", jm.Status, jm.ProgressMessage, endl)
118
+	} else if jm.Stream != "" {
119
+		fmt.Fprintf(out, "%s%s", jm.Stream, endl)
120
+	} else {
121
+		fmt.Fprintf(out, "%s%s\n", jm.Status, endl)
122
+	}
123
+	return nil
124
+}
125
+
126
+func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool) error {
127
+	var (
128
+		dec  = json.NewDecoder(in)
129
+		ids  = make(map[string]int)
130
+		diff = 0
131
+	)
132
+	for {
133
+		var jm JSONMessage
134
+		if err := dec.Decode(&jm); err != nil {
135
+			if err == io.EOF {
136
+				break
137
+			}
138
+			return err
139
+		}
140
+
141
+		if jm.Progress != nil {
142
+			jm.Progress.terminalFd = terminalFd
143
+		}
144
+		if jm.ID != "" && (jm.Progress != nil || jm.ProgressMessage != "") {
145
+			line, ok := ids[jm.ID]
146
+			if !ok {
147
+				line = len(ids)
148
+				ids[jm.ID] = line
149
+				if isTerminal {
150
+					fmt.Fprintf(out, "\n")
151
+				}
152
+				diff = 0
153
+			} else {
154
+				diff = len(ids) - line
155
+			}
156
+			if jm.ID != "" && isTerminal {
157
+				// <ESC>[{diff}A = move cursor up diff rows
158
+				fmt.Fprintf(out, "%c[%dA", 27, diff)
159
+			}
160
+		}
161
+		err := jm.Display(out, isTerminal)
162
+		if jm.ID != "" && isTerminal {
163
+			// <ESC>[{diff}B = move cursor down diff rows
164
+			fmt.Fprintf(out, "%c[%dB", 27, diff)
165
+		}
166
+		if err != nil {
167
+			return err
168
+		}
169
+	}
170
+	return nil
171
+}
0 172
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+package jsonmessage
1
+
2
+import (
3
+	"testing"
4
+)
5
+
6
+func TestError(t *testing.T) {
7
+	je := JSONError{404, "Not found"}
8
+	if je.Error() != "Not found" {
9
+		t.Fatalf("Expected 'Not found' got '%s'", je.Error())
10
+	}
11
+}
12
+
13
+func TestProgress(t *testing.T) {
14
+	jp := JSONProgress{}
15
+	if jp.String() != "" {
16
+		t.Fatalf("Expected empty string, got '%s'", jp.String())
17
+	}
18
+
19
+	expected := "     1 B"
20
+	jp2 := JSONProgress{Current: 1}
21
+	if jp2.String() != expected {
22
+		t.Fatalf("Expected %q, got %q", expected, jp2.String())
23
+	}
24
+
25
+	expected = "[=========================>                         ]     50 B/100 B"
26
+	jp3 := JSONProgress{Current: 50, Total: 100}
27
+	if jp3.String() != expected {
28
+		t.Fatalf("Expected %q, got %q", expected, jp3.String())
29
+	}
30
+
31
+	// this number can't be negetive gh#7136
32
+	expected = "[==================================================>]     50 B/40 B"
33
+	jp4 := JSONProgress{Current: 50, Total: 40}
34
+	if jp4.String() != expected {
35
+		t.Fatalf("Expected %q, got %q", expected, jp4.String())
36
+	}
37
+}
... ...
@@ -1,37 +1,16 @@
1 1
 package progressreader
2 2
 
3 3
 import (
4
+	"github.com/docker/docker/pkg/jsonmessage"
5
+	"github.com/docker/docker/pkg/streamformatter"
4 6
 	"io"
5 7
 )
6 8
 
7
-type StreamFormatter interface {
8
-	FormatProg(string, string, interface{}) []byte
9
-	FormatStatus(string, string, ...interface{}) []byte
10
-	FormatError(error) []byte
11
-}
12
-
13
-type PR_JSONProgress interface {
14
-	GetCurrent() int
15
-	GetTotal() int
16
-}
17
-
18
-type JSONProg struct {
19
-	Current int
20
-	Total   int
21
-}
22
-
23
-func (j *JSONProg) GetCurrent() int {
24
-	return j.Current
25
-}
26
-func (j *JSONProg) GetTotal() int {
27
-	return j.Total
28
-}
29
-
30 9
 // Reader with progress bar
31 10
 type Config struct {
32 11
 	In         io.ReadCloser // Stream to read from
33 12
 	Out        io.Writer     // Where to send progress bar to
34
-	Formatter  StreamFormatter
13
+	Formatter  *streamformatter.StreamFormatter
35 14
 	Size       int
36 15
 	Current    int
37 16
 	LastUpdate int
... ...
@@ -54,7 +33,7 @@ func (config *Config) Read(p []byte) (n int, err error) {
54 54
 		}
55 55
 	}
56 56
 	if config.Current-config.LastUpdate > updateEvery || err != nil {
57
-		config.Out.Write(config.Formatter.FormatProg(config.ID, config.Action, &JSONProg{Current: config.Current, Total: config.Size}))
57
+		config.Out.Write(config.Formatter.FormatProgress(config.ID, config.Action, &jsonmessage.JSONProgress{Current: config.Current, Total: config.Size}))
58 58
 		config.LastUpdate = config.Current
59 59
 	}
60 60
 	// Send newline when complete
... ...
@@ -64,6 +43,6 @@ func (config *Config) Read(p []byte) (n int, err error) {
64 64
 	return read, err
65 65
 }
66 66
 func (config *Config) Close() error {
67
-	config.Out.Write(config.Formatter.FormatProg(config.ID, config.Action, &JSONProg{Current: config.Current, Total: config.Size}))
67
+	config.Out.Write(config.Formatter.FormatProgress(config.ID, config.Action, &jsonmessage.JSONProgress{Current: config.Current, Total: config.Size}))
68 68
 	return config.In.Close()
69 69
 }
70 70
new file mode 100644
... ...
@@ -0,0 +1,113 @@
0
+package streamformatter
1
+
2
+import (
3
+	"encoding/json"
4
+	"fmt"
5
+	"github.com/docker/docker/pkg/jsonmessage"
6
+	"io"
7
+)
8
+
9
+type StreamFormatter struct {
10
+	json bool
11
+}
12
+
13
+func NewStreamFormatter(json bool) *StreamFormatter {
14
+	return &StreamFormatter{json}
15
+}
16
+
17
+const streamNewline = "\r\n"
18
+
19
+var streamNewlineBytes = []byte(streamNewline)
20
+
21
+func (sf *StreamFormatter) FormatStream(str string) []byte {
22
+	if sf.json {
23
+		b, err := json.Marshal(&jsonmessage.JSONMessage{Stream: str})
24
+		if err != nil {
25
+			return sf.FormatError(err)
26
+		}
27
+		return append(b, streamNewlineBytes...)
28
+	}
29
+	return []byte(str + "\r")
30
+}
31
+
32
+func (sf *StreamFormatter) FormatStatus(id, format string, a ...interface{}) []byte {
33
+	str := fmt.Sprintf(format, a...)
34
+	if sf.json {
35
+		b, err := json.Marshal(&jsonmessage.JSONMessage{ID: id, Status: str})
36
+		if err != nil {
37
+			return sf.FormatError(err)
38
+		}
39
+		return append(b, streamNewlineBytes...)
40
+	}
41
+	return []byte(str + streamNewline)
42
+}
43
+
44
+func (sf *StreamFormatter) FormatError(err error) []byte {
45
+	if sf.json {
46
+		jsonError, ok := err.(*jsonmessage.JSONError)
47
+		if !ok {
48
+			jsonError = &jsonmessage.JSONError{Message: err.Error()}
49
+		}
50
+		if b, err := json.Marshal(&jsonmessage.JSONMessage{Error: jsonError, ErrorMessage: err.Error()}); err == nil {
51
+			return append(b, streamNewlineBytes...)
52
+		}
53
+		return []byte("{\"error\":\"format error\"}" + streamNewline)
54
+	}
55
+	return []byte("Error: " + err.Error() + streamNewline)
56
+}
57
+
58
+func (sf *StreamFormatter) FormatProgress(id, action string, progress *jsonmessage.JSONProgress) []byte {
59
+	if progress == nil {
60
+		progress = &jsonmessage.JSONProgress{}
61
+	}
62
+	if sf.json {
63
+
64
+		b, err := json.Marshal(&jsonmessage.JSONMessage{
65
+			Status:          action,
66
+			ProgressMessage: progress.String(),
67
+			Progress:        progress,
68
+			ID:              id,
69
+		})
70
+		if err != nil {
71
+			return nil
72
+		}
73
+		return b
74
+	}
75
+	endl := "\r"
76
+	if progress.String() == "" {
77
+		endl += "\n"
78
+	}
79
+	return []byte(action + " " + progress.String() + endl)
80
+}
81
+
82
+func (sf *StreamFormatter) Json() bool {
83
+	return sf.json
84
+}
85
+
86
+type StdoutFormater struct {
87
+	io.Writer
88
+	*StreamFormatter
89
+}
90
+
91
+func (sf *StdoutFormater) Write(buf []byte) (int, error) {
92
+	formattedBuf := sf.StreamFormatter.FormatStream(string(buf))
93
+	n, err := sf.Writer.Write(formattedBuf)
94
+	if n != len(formattedBuf) {
95
+		return n, io.ErrShortWrite
96
+	}
97
+	return len(buf), err
98
+}
99
+
100
+type StderrFormater struct {
101
+	io.Writer
102
+	*StreamFormatter
103
+}
104
+
105
+func (sf *StderrFormater) Write(buf []byte) (int, error) {
106
+	formattedBuf := sf.StreamFormatter.FormatStream("\033[91m" + string(buf) + "\033[0m")
107
+	n, err := sf.Writer.Write(formattedBuf)
108
+	if n != len(formattedBuf) {
109
+		return n, io.ErrShortWrite
110
+	}
111
+	return len(buf), err
112
+}
0 113
new file mode 100644
... ...
@@ -0,0 +1,68 @@
0
+package streamformatter
1
+
2
+import (
3
+	"encoding/json"
4
+	"errors"
5
+	"github.com/docker/docker/pkg/jsonmessage"
6
+	"reflect"
7
+	"testing"
8
+)
9
+
10
+func TestFormatStream(t *testing.T) {
11
+	sf := NewStreamFormatter(true)
12
+	res := sf.FormatStream("stream")
13
+	if string(res) != `{"stream":"stream"}`+"\r\n" {
14
+		t.Fatalf("%q", res)
15
+	}
16
+}
17
+
18
+func TestFormatStatus(t *testing.T) {
19
+	sf := NewStreamFormatter(true)
20
+	res := sf.FormatStatus("ID", "%s%d", "a", 1)
21
+	if string(res) != `{"status":"a1","id":"ID"}`+"\r\n" {
22
+		t.Fatalf("%q", res)
23
+	}
24
+}
25
+
26
+func TestFormatSimpleError(t *testing.T) {
27
+	sf := NewStreamFormatter(true)
28
+	res := sf.FormatError(errors.New("Error for formatter"))
29
+	if string(res) != `{"errorDetail":{"message":"Error for formatter"},"error":"Error for formatter"}`+"\r\n" {
30
+		t.Fatalf("%q", res)
31
+	}
32
+}
33
+
34
+func TestFormatJSONError(t *testing.T) {
35
+	sf := NewStreamFormatter(true)
36
+	err := &jsonmessage.JSONError{Code: 50, Message: "Json error"}
37
+	res := sf.FormatError(err)
38
+	if string(res) != `{"errorDetail":{"code":50,"message":"Json error"},"error":"Json error"}`+"\r\n" {
39
+		t.Fatalf("%q", res)
40
+	}
41
+}
42
+
43
+func TestFormatProgress(t *testing.T) {
44
+	sf := NewStreamFormatter(true)
45
+	progress := &jsonmessage.JSONProgress{
46
+		Current: 15,
47
+		Total:   30,
48
+		Start:   1,
49
+	}
50
+	res := sf.FormatProgress("id", "action", progress)
51
+	msg := &jsonmessage.JSONMessage{}
52
+	if err := json.Unmarshal(res, msg); err != nil {
53
+		t.Fatal(err)
54
+	}
55
+	if msg.ID != "id" {
56
+		t.Fatalf("ID must be 'id', got: %s", msg.ID)
57
+	}
58
+	if msg.Status != "action" {
59
+		t.Fatalf("Status must be 'action', got: %s", msg.Status)
60
+	}
61
+	if msg.ProgressMessage != progress.String() {
62
+		t.Fatalf("ProgressMessage must be %s, got: %s", progress.String(), msg.ProgressMessage)
63
+	}
64
+	if !reflect.DeepEqual(msg.Progress, progress) {
65
+		t.Fatal("Original progress not equals progress from FormatProgress")
66
+	}
67
+}
0 68
deleted file mode 100644
... ...
@@ -1,172 +0,0 @@
1
-package utils
2
-
3
-import (
4
-	"encoding/json"
5
-	"fmt"
6
-	"io"
7
-	"strings"
8
-	"time"
9
-
10
-	"github.com/docker/docker/pkg/term"
11
-	"github.com/docker/docker/pkg/timeutils"
12
-	"github.com/docker/docker/pkg/units"
13
-)
14
-
15
-type JSONError struct {
16
-	Code    int    `json:"code,omitempty"`
17
-	Message string `json:"message,omitempty"`
18
-}
19
-
20
-func (e *JSONError) Error() string {
21
-	return e.Message
22
-}
23
-
24
-type JSONProgress struct {
25
-	terminalFd uintptr
26
-	Current    int   `json:"current,omitempty"`
27
-	Total      int   `json:"total,omitempty"`
28
-	Start      int64 `json:"start,omitempty"`
29
-}
30
-
31
-func (p *JSONProgress) String() string {
32
-	var (
33
-		width       = 200
34
-		pbBox       string
35
-		numbersBox  string
36
-		timeLeftBox string
37
-	)
38
-
39
-	ws, err := term.GetWinsize(p.terminalFd)
40
-	if err == nil {
41
-		width = int(ws.Width)
42
-	}
43
-
44
-	if p.Current <= 0 && p.Total <= 0 {
45
-		return ""
46
-	}
47
-	current := units.HumanSize(float64(p.Current))
48
-	if p.Total <= 0 {
49
-		return fmt.Sprintf("%8v", current)
50
-	}
51
-	total := units.HumanSize(float64(p.Total))
52
-	percentage := int(float64(p.Current)/float64(p.Total)*100) / 2
53
-	if percentage > 50 {
54
-		percentage = 50
55
-	}
56
-	if width > 110 {
57
-		// this number can't be negetive gh#7136
58
-		numSpaces := 0
59
-		if 50-percentage > 0 {
60
-			numSpaces = 50 - percentage
61
-		}
62
-		pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces))
63
-	}
64
-	numbersBox = fmt.Sprintf("%8v/%v", current, total)
65
-
66
-	if p.Current > 0 && p.Start > 0 && percentage < 50 {
67
-		fromStart := time.Now().UTC().Sub(time.Unix(int64(p.Start), 0))
68
-		perEntry := fromStart / time.Duration(p.Current)
69
-		left := time.Duration(p.Total-p.Current) * perEntry
70
-		left = (left / time.Second) * time.Second
71
-
72
-		if width > 50 {
73
-			timeLeftBox = " " + left.String()
74
-		}
75
-	}
76
-	return pbBox + numbersBox + timeLeftBox
77
-}
78
-
79
-type JSONMessage struct {
80
-	Stream          string        `json:"stream,omitempty"`
81
-	Status          string        `json:"status,omitempty"`
82
-	Progress        *JSONProgress `json:"progressDetail,omitempty"`
83
-	ProgressMessage string        `json:"progress,omitempty"` //deprecated
84
-	ID              string        `json:"id,omitempty"`
85
-	From            string        `json:"from,omitempty"`
86
-	Time            int64         `json:"time,omitempty"`
87
-	Error           *JSONError    `json:"errorDetail,omitempty"`
88
-	ErrorMessage    string        `json:"error,omitempty"` //deprecated
89
-}
90
-
91
-func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error {
92
-	if jm.Error != nil {
93
-		if jm.Error.Code == 401 {
94
-			return fmt.Errorf("Authentication is required.")
95
-		}
96
-		return jm.Error
97
-	}
98
-	var endl string
99
-	if isTerminal && jm.Stream == "" && jm.Progress != nil {
100
-		// <ESC>[2K = erase entire current line
101
-		fmt.Fprintf(out, "%c[2K\r", 27)
102
-		endl = "\r"
103
-	} else if jm.Progress != nil && jm.Progress.String() != "" { //disable progressbar in non-terminal
104
-		return nil
105
-	}
106
-	if jm.Time != 0 {
107
-		fmt.Fprintf(out, "%s ", time.Unix(jm.Time, 0).Format(timeutils.RFC3339NanoFixed))
108
-	}
109
-	if jm.ID != "" {
110
-		fmt.Fprintf(out, "%s: ", jm.ID)
111
-	}
112
-	if jm.From != "" {
113
-		fmt.Fprintf(out, "(from %s) ", jm.From)
114
-	}
115
-	if jm.Progress != nil && isTerminal {
116
-		fmt.Fprintf(out, "%s %s%s", jm.Status, jm.Progress.String(), endl)
117
-	} else if jm.ProgressMessage != "" { //deprecated
118
-		fmt.Fprintf(out, "%s %s%s", jm.Status, jm.ProgressMessage, endl)
119
-	} else if jm.Stream != "" {
120
-		fmt.Fprintf(out, "%s%s", jm.Stream, endl)
121
-	} else {
122
-		fmt.Fprintf(out, "%s%s\n", jm.Status, endl)
123
-	}
124
-	return nil
125
-}
126
-
127
-func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool) error {
128
-	var (
129
-		dec  = json.NewDecoder(in)
130
-		ids  = make(map[string]int)
131
-		diff = 0
132
-	)
133
-	for {
134
-		var jm JSONMessage
135
-		if err := dec.Decode(&jm); err != nil {
136
-			if err == io.EOF {
137
-				break
138
-			}
139
-			return err
140
-		}
141
-
142
-		if jm.Progress != nil {
143
-			jm.Progress.terminalFd = terminalFd
144
-		}
145
-		if jm.ID != "" && (jm.Progress != nil || jm.ProgressMessage != "") {
146
-			line, ok := ids[jm.ID]
147
-			if !ok {
148
-				line = len(ids)
149
-				ids[jm.ID] = line
150
-				if isTerminal {
151
-					fmt.Fprintf(out, "\n")
152
-				}
153
-				diff = 0
154
-			} else {
155
-				diff = len(ids) - line
156
-			}
157
-			if jm.ID != "" && isTerminal {
158
-				// <ESC>[{diff}A = move cursor up diff rows
159
-				fmt.Fprintf(out, "%c[%dA", 27, diff)
160
-			}
161
-		}
162
-		err := jm.Display(out, isTerminal)
163
-		if jm.ID != "" && isTerminal {
164
-			// <ESC>[{diff}B = move cursor down diff rows
165
-			fmt.Fprintf(out, "%c[%dB", 27, diff)
166
-		}
167
-		if err != nil {
168
-			return err
169
-		}
170
-	}
171
-	return nil
172
-}
173 1
deleted file mode 100644
... ...
@@ -1,38 +0,0 @@
1
-package utils
2
-
3
-import (
4
-	"testing"
5
-)
6
-
7
-func TestError(t *testing.T) {
8
-	je := JSONError{404, "Not found"}
9
-	if je.Error() != "Not found" {
10
-		t.Fatalf("Expected 'Not found' got '%s'", je.Error())
11
-	}
12
-}
13
-
14
-func TestProgress(t *testing.T) {
15
-	jp := JSONProgress{}
16
-	if jp.String() != "" {
17
-		t.Fatalf("Expected empty string, got '%s'", jp.String())
18
-	}
19
-
20
-	expected := "     1 B"
21
-	jp2 := JSONProgress{Current: 1}
22
-	if jp2.String() != expected {
23
-		t.Fatalf("Expected %q, got %q", expected, jp2.String())
24
-	}
25
-
26
-	expected = "[=========================>                         ]     50 B/100 B"
27
-	jp3 := JSONProgress{Current: 50, Total: 100}
28
-	if jp3.String() != expected {
29
-		t.Fatalf("Expected %q, got %q", expected, jp3.String())
30
-	}
31
-
32
-	// this number can't be negetive gh#7136
33
-	expected = "[==================================================>]     50 B/40 B"
34
-	jp4 := JSONProgress{Current: 50, Total: 40}
35
-	if jp4.String() != expected {
36
-		t.Fatalf("Expected %q, got %q", expected, jp4.String())
37
-	}
38
-}
39 1
deleted file mode 100644
... ...
@@ -1,121 +0,0 @@
1
-package utils
2
-
3
-import (
4
-	"encoding/json"
5
-	"fmt"
6
-	"github.com/docker/docker/pkg/progressreader"
7
-	"io"
8
-)
9
-
10
-type StreamFormatter struct {
11
-	json bool
12
-}
13
-
14
-func NewStreamFormatter(json bool) *StreamFormatter {
15
-	return &StreamFormatter{json}
16
-}
17
-
18
-const streamNewline = "\r\n"
19
-
20
-var streamNewlineBytes = []byte(streamNewline)
21
-
22
-func (sf *StreamFormatter) FormatStream(str string) []byte {
23
-	if sf.json {
24
-		b, err := json.Marshal(&JSONMessage{Stream: str})
25
-		if err != nil {
26
-			return sf.FormatError(err)
27
-		}
28
-		return append(b, streamNewlineBytes...)
29
-	}
30
-	return []byte(str + "\r")
31
-}
32
-
33
-func (sf *StreamFormatter) FormatStatus(id, format string, a ...interface{}) []byte {
34
-	str := fmt.Sprintf(format, a...)
35
-	if sf.json {
36
-		b, err := json.Marshal(&JSONMessage{ID: id, Status: str})
37
-		if err != nil {
38
-			return sf.FormatError(err)
39
-		}
40
-		return append(b, streamNewlineBytes...)
41
-	}
42
-	return []byte(str + streamNewline)
43
-}
44
-
45
-func (sf *StreamFormatter) FormatError(err error) []byte {
46
-	if sf.json {
47
-		jsonError, ok := err.(*JSONError)
48
-		if !ok {
49
-			jsonError = &JSONError{Message: err.Error()}
50
-		}
51
-		if b, err := json.Marshal(&JSONMessage{Error: jsonError, ErrorMessage: err.Error()}); err == nil {
52
-			return append(b, streamNewlineBytes...)
53
-		}
54
-		return []byte("{\"error\":\"format error\"}" + streamNewline)
55
-	}
56
-	return []byte("Error: " + err.Error() + streamNewline)
57
-}
58
-func (sf *StreamFormatter) FormatProg(id, action string, p interface{}) []byte {
59
-	switch progress := p.(type) {
60
-	case *JSONProgress:
61
-		return sf.FormatProgress(id, action, progress)
62
-	case progressreader.PR_JSONProgress:
63
-		return sf.FormatProgress(id, action, &JSONProgress{Current: progress.GetCurrent(), Total: progress.GetTotal()})
64
-	}
65
-	return nil
66
-}
67
-func (sf *StreamFormatter) FormatProgress(id, action string, progress *JSONProgress) []byte {
68
-	if progress == nil {
69
-		progress = &JSONProgress{}
70
-	}
71
-	if sf.json {
72
-
73
-		b, err := json.Marshal(&JSONMessage{
74
-			Status:          action,
75
-			ProgressMessage: progress.String(),
76
-			Progress:        progress,
77
-			ID:              id,
78
-		})
79
-		if err != nil {
80
-			return nil
81
-		}
82
-		return b
83
-	}
84
-	endl := "\r"
85
-	if progress.String() == "" {
86
-		endl += "\n"
87
-	}
88
-	return []byte(action + " " + progress.String() + endl)
89
-}
90
-
91
-func (sf *StreamFormatter) Json() bool {
92
-	return sf.json
93
-}
94
-
95
-type StdoutFormater struct {
96
-	io.Writer
97
-	*StreamFormatter
98
-}
99
-
100
-func (sf *StdoutFormater) Write(buf []byte) (int, error) {
101
-	formattedBuf := sf.StreamFormatter.FormatStream(string(buf))
102
-	n, err := sf.Writer.Write(formattedBuf)
103
-	if n != len(formattedBuf) {
104
-		return n, io.ErrShortWrite
105
-	}
106
-	return len(buf), err
107
-}
108
-
109
-type StderrFormater struct {
110
-	io.Writer
111
-	*StreamFormatter
112
-}
113
-
114
-func (sf *StderrFormater) Write(buf []byte) (int, error) {
115
-	formattedBuf := sf.StreamFormatter.FormatStream("\033[91m" + string(buf) + "\033[0m")
116
-	n, err := sf.Writer.Write(formattedBuf)
117
-	if n != len(formattedBuf) {
118
-		return n, io.ErrShortWrite
119
-	}
120
-	return len(buf), err
121
-}
122 1
deleted file mode 100644
... ...
@@ -1,67 +0,0 @@
1
-package utils
2
-
3
-import (
4
-	"encoding/json"
5
-	"errors"
6
-	"reflect"
7
-	"testing"
8
-)
9
-
10
-func TestFormatStream(t *testing.T) {
11
-	sf := NewStreamFormatter(true)
12
-	res := sf.FormatStream("stream")
13
-	if string(res) != `{"stream":"stream"}`+"\r\n" {
14
-		t.Fatalf("%q", res)
15
-	}
16
-}
17
-
18
-func TestFormatStatus(t *testing.T) {
19
-	sf := NewStreamFormatter(true)
20
-	res := sf.FormatStatus("ID", "%s%d", "a", 1)
21
-	if string(res) != `{"status":"a1","id":"ID"}`+"\r\n" {
22
-		t.Fatalf("%q", res)
23
-	}
24
-}
25
-
26
-func TestFormatSimpleError(t *testing.T) {
27
-	sf := NewStreamFormatter(true)
28
-	res := sf.FormatError(errors.New("Error for formatter"))
29
-	if string(res) != `{"errorDetail":{"message":"Error for formatter"},"error":"Error for formatter"}`+"\r\n" {
30
-		t.Fatalf("%q", res)
31
-	}
32
-}
33
-
34
-func TestFormatJSONError(t *testing.T) {
35
-	sf := NewStreamFormatter(true)
36
-	err := &JSONError{Code: 50, Message: "Json error"}
37
-	res := sf.FormatError(err)
38
-	if string(res) != `{"errorDetail":{"code":50,"message":"Json error"},"error":"Json error"}`+"\r\n" {
39
-		t.Fatalf("%q", res)
40
-	}
41
-}
42
-
43
-func TestFormatProgress(t *testing.T) {
44
-	sf := NewStreamFormatter(true)
45
-	progress := &JSONProgress{
46
-		Current: 15,
47
-		Total:   30,
48
-		Start:   1,
49
-	}
50
-	res := sf.FormatProgress("id", "action", progress)
51
-	msg := &JSONMessage{}
52
-	if err := json.Unmarshal(res, msg); err != nil {
53
-		t.Fatal(err)
54
-	}
55
-	if msg.ID != "id" {
56
-		t.Fatalf("ID must be 'id', got: %s", msg.ID)
57
-	}
58
-	if msg.Status != "action" {
59
-		t.Fatalf("Status must be 'action', got: %s", msg.Status)
60
-	}
61
-	if msg.ProgressMessage != progress.String() {
62
-		t.Fatalf("ProgressMessage must be %s, got: %s", progress.String(), msg.ProgressMessage)
63
-	}
64
-	if !reflect.DeepEqual(msg.Progress, progress) {
65
-		t.Fatal("Original progress not equals progress from FormatProgress")
66
-	}
67
-}
... ...
@@ -23,6 +23,7 @@ import (
23 23
 	"github.com/docker/docker/pkg/archive"
24 24
 	"github.com/docker/docker/pkg/fileutils"
25 25
 	"github.com/docker/docker/pkg/ioutils"
26
+	"github.com/docker/docker/pkg/jsonmessage"
26 27
 	"github.com/docker/docker/pkg/stringutils"
27 28
 )
28 29
 
... ...
@@ -254,7 +255,7 @@ func NewWriteFlusher(w io.Writer) *WriteFlusher {
254 254
 }
255 255
 
256 256
 func NewHTTPRequestError(msg string, res *http.Response) error {
257
-	return &JSONError{
257
+	return &jsonmessage.JSONError{
258 258
 		Message: msg,
259 259
 		Code:    res.StatusCode,
260 260
 	}