diff --git a/api/client/history.go b/api/client/history.go index e8ad19c8af..6e0cdb24cd 100644 --- a/api/client/history.go +++ b/api/client/history.go @@ -1,11 +1,12 @@ package client import ( + "encoding/json" "fmt" "text/tabwriter" "time" - "github.com/docker/docker/engine" + "github.com/docker/docker/api/types" flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/units" @@ -20,16 +21,16 @@ func (cli *DockerCli) CmdHistory(args ...string) error { quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs") noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output") cmd.Require(flag.Exact, 1) - cmd.ParseFlags(args, true) - body, _, err := readBody(cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, nil)) + rdr, _, err := cli.call("GET", "/images/"+cmd.Arg(0)+"/history", nil, nil) if err != nil { return err } - outs := engine.NewTable("Created", 0) - if _, err := outs.ReadListFrom(body); err != nil { + history := []types.ImageHistory{} + err = json.NewDecoder(rdr).Decode(&history) + if err != nil { return err } @@ -38,30 +39,23 @@ func (cli *DockerCli) CmdHistory(args ...string) error { fmt.Fprintln(w, "IMAGE\tCREATED\tCREATED BY\tSIZE") } - for _, out := range outs.Data { - outID := out.Get("Id") - if !*quiet { - if *noTrunc { - fmt.Fprintf(w, "%s\t", outID) - } else { - fmt.Fprintf(w, "%s\t", stringid.TruncateID(outID)) - } - - fmt.Fprintf(w, "%s ago\t", units.HumanDuration(time.Now().UTC().Sub(time.Unix(out.GetInt64("Created"), 0)))) - - if *noTrunc { - fmt.Fprintf(w, "%s\t", out.Get("CreatedBy")) - } else { - fmt.Fprintf(w, "%s\t", utils.Trunc(out.Get("CreatedBy"), 45)) - } - fmt.Fprintf(w, "%s\n", units.HumanSize(float64(out.GetInt64("Size")))) + for _, entry := range history { + if *noTrunc { + fmt.Fprintf(w, entry.ID) } else { - if *noTrunc { - fmt.Fprintln(w, outID) - } else { - fmt.Fprintln(w, stringid.TruncateID(outID)) - } + fmt.Fprintf(w, stringid.TruncateID(entry.ID)) } + if !*quiet { + fmt.Fprintf(w, "\t%s ago\t", units.HumanDuration(time.Now().UTC().Sub(time.Unix(entry.Created, 0)))) + + if *noTrunc { + fmt.Fprintf(w, "%s\t", entry.CreatedBy) + } else { + fmt.Fprintf(w, "%s\t", utils.Trunc(entry.CreatedBy, 45)) + } + fmt.Fprintf(w, "%s", units.HumanSize(float64(entry.Size))) + } + fmt.Fprintf(w, "\n") } w.Flush() return nil diff --git a/api/client/rmi.go b/api/client/rmi.go index 580c0b747e..11c9ff32d0 100644 --- a/api/client/rmi.go +++ b/api/client/rmi.go @@ -1,10 +1,11 @@ package client import ( + "encoding/json" "fmt" "net/url" - "github.com/docker/docker/engine" + "github.com/docker/docker/api/types" flag "github.com/docker/docker/pkg/mflag" ) @@ -18,7 +19,6 @@ func (cli *DockerCli) CmdRmi(args ...string) error { noprune = cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents") ) cmd.Require(flag.Min, 1) - cmd.ParseFlags(args, true) v := url.Values{} @@ -31,22 +31,24 @@ func (cli *DockerCli) CmdRmi(args ...string) error { var encounteredError error for _, name := range cmd.Args() { - body, _, err := readBody(cli.call("DELETE", "/images/"+name+"?"+v.Encode(), nil, nil)) + rdr, _, err := cli.call("DELETE", "/images/"+name+"?"+v.Encode(), nil, nil) if err != nil { fmt.Fprintf(cli.err, "%s\n", err) encounteredError = fmt.Errorf("Error: failed to remove one or more images") } else { - outs := engine.NewTable("Created", 0) - if _, err := outs.ReadListFrom(body); err != nil { + dels := []types.ImageDelete{} + err = json.NewDecoder(rdr).Decode(&dels) + if err != nil { fmt.Fprintf(cli.err, "%s\n", err) encounteredError = fmt.Errorf("Error: failed to remove one or more images") continue } - for _, out := range outs.Data { - if out.Get("Deleted") != "" { - fmt.Fprintf(cli.out, "Deleted: %s\n", out.Get("Deleted")) + + for _, del := range dels { + if del.Deleted != "" { + fmt.Fprintf(cli.out, "Deleted: %s\n", del.Deleted) } else { - fmt.Fprintf(cli.out, "Untagged: %s\n", out.Get("Untagged")) + fmt.Fprintf(cli.out, "Untagged: %s\n", del.Untagged) } } } diff --git a/api/types/types.go b/api/types/types.go index f4c6dc34aa..ef3dd6fcda 100644 --- a/api/types/types.go +++ b/api/types/types.go @@ -41,3 +41,18 @@ type ContainerChange struct { Kind int Path string } + +// GET "/images/{name:.*}/history" +type ImageHistory struct { + ID string `json:"Id"` + Created int64 + CreatedBy string + Tags []string + Size int64 +} + +// DELETE "/images/{name:.*}" +type ImageDelete struct { + Untagged string `json:",omitempty"` + Deleted string `json:",omitempty"` +} diff --git a/daemon/image_delete.go b/daemon/image_delete.go index 075672a4cf..bf3d7ba9ce 100644 --- a/daemon/image_delete.go +++ b/daemon/image_delete.go @@ -1,9 +1,11 @@ package daemon import ( + "encoding/json" "fmt" "strings" + "github.com/docker/docker/api/types" "github.com/docker/docker/engine" "github.com/docker/docker/graph" "github.com/docker/docker/image" @@ -16,21 +18,22 @@ func (daemon *Daemon) ImageDelete(job *engine.Job) error { if n := len(job.Args); n != 1 { return fmt.Errorf("Usage: %s IMAGE", job.Name) } - imgs := engine.NewTable("", 0) - if err := daemon.DeleteImage(job.Eng, job.Args[0], imgs, true, job.GetenvBool("force"), job.GetenvBool("noprune")); err != nil { + + list := []types.ImageDelete{} + if err := daemon.DeleteImage(job.Eng, job.Args[0], &list, true, job.GetenvBool("force"), job.GetenvBool("noprune")); err != nil { return err } - if len(imgs.Data) == 0 { + if len(list) == 0 { return fmt.Errorf("Conflict, %s wasn't deleted", job.Args[0]) } - if _, err := imgs.WriteListTo(job.Stdout); err != nil { + if err := json.NewEncoder(job.Stdout).Encode(list); err != nil { return err } return nil } // FIXME: make this private and use the job instead -func (daemon *Daemon) DeleteImage(eng *engine.Engine, name string, imgs *engine.Table, first, force, noprune bool) error { +func (daemon *Daemon) DeleteImage(eng *engine.Engine, name string, list *[]types.ImageDelete, first, force, noprune bool) error { var ( repoName, tag string tags = []string{} @@ -102,9 +105,9 @@ func (daemon *Daemon) DeleteImage(eng *engine.Engine, name string, imgs *engine. return err } if tagDeleted { - out := &engine.Env{} - out.Set("Untagged", utils.ImageReference(repoName, tag)) - imgs.Add(out) + *list = append(*list, types.ImageDelete{ + Untagged: utils.ImageReference(repoName, tag), + }) eng.Job("log", "untag", img.ID, "").Run() } } @@ -117,12 +120,12 @@ func (daemon *Daemon) DeleteImage(eng *engine.Engine, name string, imgs *engine. if err := daemon.Graph().Delete(img.ID); err != nil { return err } - out := &engine.Env{} - out.SetJson("Deleted", img.ID) - imgs.Add(out) + *list = append(*list, types.ImageDelete{ + Deleted: img.ID, + }) eng.Job("log", "delete", img.ID, "").Run() if img.Parent != "" && !noprune { - err := daemon.DeleteImage(eng, img.Parent, imgs, false, force, noprune) + err := daemon.DeleteImage(eng, img.Parent, list, false, force, noprune) if first { return err } diff --git a/graph/history.go b/graph/history.go index 719cdf3796..1290de9a30 100644 --- a/graph/history.go +++ b/graph/history.go @@ -1,9 +1,11 @@ package graph import ( + "encoding/json" "fmt" "strings" + "github.com/docker/docker/api/types" "github.com/docker/docker/engine" "github.com/docker/docker/image" "github.com/docker/docker/utils" @@ -30,19 +32,22 @@ func (s *TagStore) CmdHistory(job *engine.Job) error { } } - outs := engine.NewTable("Created", 0) + history := []types.ImageHistory{} + err = foundImage.WalkHistory(func(img *image.Image) error { - out := &engine.Env{} - out.SetJson("Id", img.ID) - out.SetInt64("Created", img.Created.Unix()) - out.Set("CreatedBy", strings.Join(img.ContainerConfig.Cmd, " ")) - out.SetList("Tags", lookupMap[img.ID]) - out.SetInt64("Size", img.Size) - outs.Add(out) + history = append(history, types.ImageHistory{ + ID: img.ID, + Created: img.Created.Unix(), + CreatedBy: strings.Join(img.ContainerConfig.Cmd, " "), + Tags: lookupMap[img.ID], + Size: img.Size, + }) return nil }) - if _, err := outs.WriteListTo(job.Stdout); err != nil { + + if err = json.NewEncoder(job.Stdout).Encode(history); err != nil { return err } + return nil }