From 3a610f754f425ea6042c3f8b5452273656a06c90 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Fri, 13 Dec 2013 10:26:00 -0800 Subject: [PATCH] Add compat 1.8 Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- api.go | 7 +-- commands.go | 105 +++++++++++++++++++------------------ engine/env.go | 39 ++++++++++++-- integration/api_test.go | 40 +++++--------- integration/server_test.go | 2 - integration/sorter_test.go | 4 +- server.go | 14 ++--- 7 files changed, 112 insertions(+), 99 deletions(-) diff --git a/api.go b/api.go index 10dab5fae2..7e874c9f12 100644 --- a/api.go +++ b/api.go @@ -28,7 +28,7 @@ import ( ) const ( - APIVERSION = 1.8 + APIVERSION = 1.9 DEFAULTHTTPHOST = "127.0.0.1" DEFAULTHTTPPORT = 4243 DEFAULTUNIXSOCKET = "/var/run/docker.sock" @@ -181,18 +181,15 @@ func getImagesJSON(srv *Server, version float64, w http.ResponseWriter, r *http. if err := parseForm(r); err != nil { return err } - fmt.Printf("getImagesJSON\n") job := srv.Eng.Job("images") job.Setenv("filter", r.Form.Get("filter")) job.Setenv("all", r.Form.Get("all")) - // FIXME: 1.7 clients expect a single json list + job.SetenvBool("list", version <= 1.8) job.Stdout.Add(w) w.WriteHeader(http.StatusOK) - fmt.Printf("running images job\n") if err := job.Run(); err != nil { return err } - fmt.Printf("job has been run\n") return nil } diff --git a/commands.go b/commands.go index fd231abeea..40c450928c 100644 --- a/commands.go +++ b/commands.go @@ -1137,36 +1137,38 @@ func (cli *DockerCli) CmdImages(args ...string) error { return err } - var outs []APIImages - if err := json.Unmarshal(body, &outs); err != nil { + outs := engine.NewTable("Created", 0) + + if _, err := outs.ReadFrom(bytes.NewReader(body)); err != nil { return err } var ( - printNode func(cli *DockerCli, noTrunc bool, image APIImages, prefix string) - startImage APIImages + printNode func(cli *DockerCli, noTrunc bool, image *engine.Env, prefix string) + startImage *engine.Env - roots []APIImages - byParent = make(map[string][]APIImages) + roots = engine.NewTable("Created", outs.Len()) + byParent = make(map[string]*engine.Table) ) - for _, image := range outs { - if image.ParentId == "" { - roots = append(roots, image) + for _, image := range outs.Data { + if image.Get("ParentId") == "" { + roots.Add(image) } else { - if children, exists := byParent[image.ParentId]; exists { - byParent[image.ParentId] = append(children, image) + if children, exists := byParent[image.Get("ParentId")]; exists { + children.Add(image) } else { - byParent[image.ParentId] = []APIImages{image} + byParent[image.Get("ParentId")] = engine.NewTable("Created", 1) + byParent[image.Get("ParentId")].Add(image) } } if filter != "" { - if filter == image.ID || filter == utils.TruncateID(image.ID) { + if filter == image.Get("ID") || filter == utils.TruncateID(image.Get("ID")) { startImage = image } - for _, repotag := range image.RepoTags { + for _, repotag := range image.GetList("RepoTags") { if repotag == filter { startImage = image } @@ -1181,10 +1183,12 @@ func (cli *DockerCli) CmdImages(args ...string) error { printNode = (*DockerCli).printTreeNode } - if startImage.ID != "" { - cli.WalkTree(*noTrunc, &[]APIImages{startImage}, byParent, "", printNode) + if startImage != nil { + root := engine.NewTable("Created", 1) + root.Add(startImage) + cli.WalkTree(*noTrunc, root, byParent, "", printNode) } else if filter == "" { - cli.WalkTree(*noTrunc, &roots, byParent, "", printNode) + cli.WalkTree(*noTrunc, roots, byParent, "", printNode) } if *flViz { fmt.Fprintf(cli.out, " base [style=invisible]\n}\n") @@ -1203,9 +1207,8 @@ func (cli *DockerCli) CmdImages(args ...string) error { return err } - var outs []APIImages - err = json.Unmarshal(body, &outs) - if err != nil { + outs := engine.NewTable("Created", 0) + if _, err := outs.ReadFrom(bytes.NewReader(body)); err != nil { return err } @@ -1214,19 +1217,19 @@ func (cli *DockerCli) CmdImages(args ...string) error { fmt.Fprintln(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tVIRTUAL SIZE") } - for _, out := range outs { - for _, repotag := range out.RepoTags { + for _, out := range outs.Data { + for _, repotag := range out.GetList("RepoTags") { repo, tag := utils.ParseRepositoryTag(repotag) - + outID := out.Get("ID") if !*noTrunc { - out.ID = utils.TruncateID(out.ID) + outID = utils.TruncateID(outID) } if !*quiet { - fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, out.ID, utils.HumanDuration(time.Now().UTC().Sub(time.Unix(out.Created, 0))), utils.HumanSize(out.VirtualSize)) + fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, outID, utils.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0))), utils.HumanSize(out.GetInt64("VirtualSize"))) } else { - fmt.Fprintln(w, out.ID) + fmt.Fprintln(w, outID) } } } @@ -1238,66 +1241,66 @@ func (cli *DockerCli) CmdImages(args ...string) error { return nil } -func (cli *DockerCli) WalkTree(noTrunc bool, images *[]APIImages, byParent map[string][]APIImages, prefix string, printNode func(cli *DockerCli, noTrunc bool, image APIImages, prefix string)) { - length := len(*images) +func (cli *DockerCli) WalkTree(noTrunc bool, images *engine.Table, byParent map[string]*engine.Table, prefix string, printNode func(cli *DockerCli, noTrunc bool, image *engine.Env, prefix string)) { + length := images.Len() if length > 1 { - for index, image := range *images { + for index, image := range images.Data { if index+1 == length { printNode(cli, noTrunc, image, prefix+"└─") - if subimages, exists := byParent[image.ID]; exists { - cli.WalkTree(noTrunc, &subimages, byParent, prefix+" ", printNode) + if subimages, exists := byParent[image.Get("ID")]; exists { + cli.WalkTree(noTrunc, subimages, byParent, prefix+" ", printNode) } } else { - printNode(cli, noTrunc, image, prefix+"├─") - if subimages, exists := byParent[image.ID]; exists { - cli.WalkTree(noTrunc, &subimages, byParent, prefix+"│ ", printNode) + printNode(cli, noTrunc, image, prefix+"\u251C─") + if subimages, exists := byParent[image.Get("ID")]; exists { + cli.WalkTree(noTrunc, subimages, byParent, prefix+"\u2502 ", printNode) } } } } else { - for _, image := range *images { + for _, image := range images.Data { printNode(cli, noTrunc, image, prefix+"└─") - if subimages, exists := byParent[image.ID]; exists { - cli.WalkTree(noTrunc, &subimages, byParent, prefix+" ", printNode) + if subimages, exists := byParent[image.Get("ID")]; exists { + cli.WalkTree(noTrunc, subimages, byParent, prefix+" ", printNode) } } } } -func (cli *DockerCli) printVizNode(noTrunc bool, image APIImages, prefix string) { +func (cli *DockerCli) printVizNode(noTrunc bool, image *engine.Env, prefix string) { var ( imageID string parentID string ) if noTrunc { - imageID = image.ID - parentID = image.ParentId + imageID = image.Get("ID") + parentID = image.Get("ParentId") } else { - imageID = utils.TruncateID(image.ID) - parentID = utils.TruncateID(image.ParentId) + imageID = utils.TruncateID(image.Get("ID")) + parentID = utils.TruncateID(image.Get("ParentId")) } - if image.ParentId == "" { + if parentID == "" { fmt.Fprintf(cli.out, " base -> \"%s\" [style=invis]\n", imageID) } else { fmt.Fprintf(cli.out, " \"%s\" -> \"%s\"\n", parentID, imageID) } - if image.RepoTags[0] != ":" { + if image.GetList("RepoTags")[0] != ":" { fmt.Fprintf(cli.out, " \"%s\" [label=\"%s\\n%s\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n", - imageID, imageID, strings.Join(image.RepoTags, "\\n")) + imageID, imageID, strings.Join(image.GetList("RepoTags"), "\\n")) } } -func (cli *DockerCli) printTreeNode(noTrunc bool, image APIImages, prefix string) { +func (cli *DockerCli) printTreeNode(noTrunc bool, image *engine.Env, prefix string) { var imageID string if noTrunc { - imageID = image.ID + imageID = image.Get("ID") } else { - imageID = utils.TruncateID(image.ID) + imageID = utils.TruncateID(image.Get("ID")) } - fmt.Fprintf(cli.out, "%s%s Virtual Size: %s", prefix, imageID, utils.HumanSize(image.VirtualSize)) - if image.RepoTags[0] != ":" { - fmt.Fprintf(cli.out, " Tags: %s\n", strings.Join(image.RepoTags, ", ")) + fmt.Fprintf(cli.out, "%s%s Virtual Size: %s", prefix, imageID, utils.HumanSize(image.GetInt64("VirtualSize"))) + if image.GetList("RepoTags")[0] != ":" { + fmt.Fprintf(cli.out, " Tags: %s\n", strings.Join(image.GetList("RepoTags"), ", ")) } else { fmt.Fprint(cli.out, "\n") } diff --git a/engine/env.go b/engine/env.go index f4cc124240..0593bfa012 100644 --- a/engine/env.go +++ b/engine/env.go @@ -237,15 +237,21 @@ func (env *Env) Map() map[string]string { type Table struct { Data []*Env sortKey string + Chan chan *Env } func NewTable(sortKey string, sizeHint int) *Table { return &Table{ make([]*Env, 0, sizeHint), sortKey, + make(chan *Env), } } +func (t *Table) SetKey(sortKey string) { + t.sortKey = sortKey +} + func (t *Table) Add(env *Env) { t.Data = append(t.Data, env) } @@ -279,16 +285,41 @@ func (t *Table) Sort() { sort.Sort(t) } +func (t *Table) ReverseSort() { + sort.Sort(sort.Reverse(t)) +} + +func (t *Table) WriteListTo(dst io.Writer) (n int64, err error) { + if _, err := dst.Write([]byte{'['}); err != nil { + return -1, err + } + n = 1 + for i, env := range t.Data { + bytes, err := env.WriteTo(dst) + if err != nil { + return -1, err + } + n += bytes + if i != len(t.Data)-1 { + if _, err := dst.Write([]byte{','}); err != nil { + return -1, err + } + n += 1 + } + } + if _, err := dst.Write([]byte{']'}); err != nil { + return -1, err + } + return n + 1, nil +} + func (t *Table) WriteTo(dst io.Writer) (n int64, err error) { for _, env := range t.Data { bytes, err := env.WriteTo(dst) if err != nil { return -1, err } - if _, err := dst.Write([]byte{'\n'}); err != nil { - return -1, err - } - n += bytes + 1 + n += bytes } return n, nil } diff --git a/integration/api_test.go b/integration/api_test.go index de54078dea..47d63efb1d 100644 --- a/integration/api_test.go +++ b/integration/api_test.go @@ -204,18 +204,18 @@ func TestGetImagesJSON(t *testing.T) { } assertHttpNotError(r2, t) - images2 := []docker.APIImages{} - if err := json.Unmarshal(r2.Body.Bytes(), &images2); err != nil { + images2 := engine.NewTable("ID", 0) + if _, err := images2.ReadFrom(r2.Body); err != nil { t.Fatal(err) } - if len(images2) != initialImages.Len() { - t.Errorf("Expected %d image, %d found", initialImages.Len(), len(images2)) + if images2.Len() != initialImages.Len() { + t.Errorf("Expected %d image, %d found", initialImages.Len(), images2.Len()) } found = false - for _, img := range images2 { - if img.ID == unitTestImageID { + for _, img := range images2.Data { + if img.Get("ID") == unitTestImageID { found = true break } @@ -237,29 +237,13 @@ func TestGetImagesJSON(t *testing.T) { } assertHttpNotError(r3, t) - images3 := []docker.APIImages{} - if err := json.Unmarshal(r3.Body.Bytes(), &images3); err != nil { + images3 := engine.NewTable("ID", 0) + if _, err := images3.ReadFrom(r3.Body); err != nil { t.Fatal(err) } - if len(images3) != 0 { - t.Errorf("Expected 0 image, %d found", len(images3)) - } - - r4 := httptest.NewRecorder() - - // all=foobar - req4, err := http.NewRequest("GET", "/images/json?all=foobar", nil) - if err != nil { - t.Fatal(err) - } - - if err := docker.ServeRequest(srv, docker.APIVERSION, r4, req4); err != nil { - t.Fatal(err) - } - // Don't assert against HTTP error since we expect an error - if r4.Code != http.StatusBadRequest { - t.Fatalf("%d Bad Request expected, received %d\n", http.StatusBadRequest, r4.Code) + if images3.Len() != 0 { + t.Errorf("Expected 0 image, %d found", images3.Len()) } } @@ -1136,8 +1120,8 @@ func TestDeleteImages(t *testing.T) { images := getImages(eng, t, true, "") - if images.Len() != initialImages.Len()+1 { - t.Errorf("Expected %d images, %d found", initialImages.Len()+1, images.Len()) + if len(images.Data[0].GetList("RepoTags")) != len(initialImages.Data[0].GetList("RepoTags"))+1 { + t.Errorf("Expected %d images, %d found", len(initialImages.Data[0].GetList("RepoTags"))+1, len(images.Data[0].GetList("RepoTags"))) } req, err := http.NewRequest("DELETE", "/images/"+unitTestImageID, nil) diff --git a/integration/server_test.go b/integration/server_test.go index 106bff9c2b..e755d14728 100644 --- a/integration/server_test.go +++ b/integration/server_test.go @@ -324,8 +324,6 @@ func TestImagesFilter(t *testing.T) { eng := NewTestEngine(t) defer nuke(mkRuntimeFromEngine(eng, t)) - srv := mkServerFromEngine(eng, t) - if err := eng.Job("tag", unitTestImageName, "utest", "tag1").Run(); err != nil { t.Fatal(err) } diff --git a/integration/sorter_test.go b/integration/sorter_test.go index 1c089a2997..02d08d3409 100644 --- a/integration/sorter_test.go +++ b/integration/sorter_test.go @@ -43,8 +43,8 @@ func TestServerListOrderedImagesByCreationDateAndTag(t *testing.T) { images := getImages(eng, t, true, "") - if images.Data[0].GetList("RepoTags")[0] != "repo:zed" && images.Data[0].GetList("RepoTags")[0] != "repo:bar" { - t.Errorf("Expected []APIImges to be ordered by most recent creation date. %s", images) + if repoTags := images.Data[0].GetList("RepoTags"); repoTags[0] != "repo:zed" && repoTags[0] != "repo:bar" { + t.Errorf("Expected Images to be ordered by most recent creation date.") } } diff --git a/server.go b/server.go index 556b342c16..a0c545fbc4 100644 --- a/server.go +++ b/server.go @@ -573,8 +573,6 @@ func (srv *Server) ImagesViz(out io.Writer) error { } func (srv *Server) Images(job *engine.Job) engine.Status { - fmt.Printf("Images()\n") - srv.Eng.Job("version").Run() var ( allImages map[string]*Image err error @@ -639,13 +637,15 @@ func (srv *Server) Images(job *engine.Job) engine.Status { } } - outs.Sort() - job.Logf("Sending %d images to stdout", outs.Len()) - if n, err := outs.WriteTo(job.Stdout); err != nil { + outs.ReverseSort() + if job.GetenvBool("list") { + if _, err := outs.WriteListTo(job.Stdout); err != nil { + job.Errorf("%s", err) + return engine.StatusErr + } + } else if _, err := outs.WriteTo(job.Stdout); err != nil { job.Errorf("%s", err) return engine.StatusErr - } else { - job.Logf("%d bytes sent", n) } return engine.StatusOK }