github.com/squaremo/docker@v1.3.2-0.20150516120342-42cfc9554972/api/client/images.go (about) 1 package client 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/url" 7 "text/tabwriter" 8 "time" 9 10 "github.com/docker/docker/api/types" 11 "github.com/docker/docker/opts" 12 flag "github.com/docker/docker/pkg/mflag" 13 "github.com/docker/docker/pkg/parsers" 14 "github.com/docker/docker/pkg/parsers/filters" 15 "github.com/docker/docker/pkg/stringid" 16 "github.com/docker/docker/pkg/units" 17 "github.com/docker/docker/utils" 18 ) 19 20 // CmdImages lists the images in a specified repository, or all top-level images if no repository is specified. 21 // 22 // Usage: docker images [OPTIONS] [REPOSITORY] 23 func (cli *DockerCli) CmdImages(args ...string) error { 24 cmd := cli.Subcmd("images", "[REPOSITORY]", "List images", true) 25 quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs") 26 all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (default hides intermediate images)") 27 noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output") 28 showDigests := cmd.Bool([]string{"-digests"}, false, "Show digests") 29 30 flFilter := opts.NewListOpts(nil) 31 cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided") 32 cmd.Require(flag.Max, 1) 33 cmd.ParseFlags(args, true) 34 35 // Consolidate all filter flags, and sanity check them early. 36 // They'll get process in the daemon/server. 37 imageFilterArgs := filters.Args{} 38 for _, f := range flFilter.GetAll() { 39 var err error 40 imageFilterArgs, err = filters.ParseFlag(f, imageFilterArgs) 41 if err != nil { 42 return err 43 } 44 } 45 46 matchName := cmd.Arg(0) 47 v := url.Values{} 48 if len(imageFilterArgs) > 0 { 49 filterJSON, err := filters.ToParam(imageFilterArgs) 50 if err != nil { 51 return err 52 } 53 v.Set("filters", filterJSON) 54 } 55 56 if cmd.NArg() == 1 { 57 // FIXME rename this parameter, to not be confused with the filters flag 58 v.Set("filter", matchName) 59 } 60 if *all { 61 v.Set("all", "1") 62 } 63 64 rdr, _, err := cli.call("GET", "/images/json?"+v.Encode(), nil, nil) 65 if err != nil { 66 return err 67 } 68 69 images := []types.Image{} 70 if err := json.NewDecoder(rdr).Decode(&images); err != nil { 71 return err 72 } 73 74 w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0) 75 if !*quiet { 76 if *showDigests { 77 fmt.Fprintln(w, "REPOSITORY\tTAG\tDIGEST\tIMAGE ID\tCREATED\tVIRTUAL SIZE") 78 } else { 79 fmt.Fprintln(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tVIRTUAL SIZE") 80 } 81 } 82 83 for _, image := range images { 84 ID := image.ID 85 if !*noTrunc { 86 ID = stringid.TruncateID(ID) 87 } 88 89 repoTags := image.RepoTags 90 repoDigests := image.RepoDigests 91 92 if len(repoTags) == 1 && repoTags[0] == "<none>:<none>" && len(repoDigests) == 1 && repoDigests[0] == "<none>@<none>" { 93 // dangling image - clear out either repoTags or repoDigsts so we only show it once below 94 repoDigests = []string{} 95 } 96 97 // combine the tags and digests lists 98 tagsAndDigests := append(repoTags, repoDigests...) 99 for _, repoAndRef := range tagsAndDigests { 100 repo, ref := parsers.ParseRepositoryTag(repoAndRef) 101 // default tag and digest to none - if there's a value, it'll be set below 102 tag := "<none>" 103 digest := "<none>" 104 if utils.DigestReference(ref) { 105 digest = ref 106 } else { 107 tag = ref 108 } 109 110 if !*quiet { 111 if *showDigests { 112 fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s ago\t%s\n", repo, tag, digest, ID, units.HumanDuration(time.Now().UTC().Sub(time.Unix(int64(image.Created), 0))), units.HumanSize(float64(image.VirtualSize))) 113 } else { 114 fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\n", repo, tag, ID, units.HumanDuration(time.Now().UTC().Sub(time.Unix(int64(image.Created), 0))), units.HumanSize(float64(image.VirtualSize))) 115 } 116 } else { 117 fmt.Fprintln(w, ID) 118 } 119 } 120 } 121 122 if !*quiet { 123 w.Flush() 124 } 125 return nil 126 }