github.com/walkingsparrow/docker@v1.4.2-0.20151218153551-b708a2249bfa/api/client/images.go (about) 1 package client 2 3 import ( 4 "fmt" 5 "strings" 6 "text/tabwriter" 7 "time" 8 9 "github.com/docker/docker/api/types" 10 "github.com/docker/docker/api/types/filters" 11 Cli "github.com/docker/docker/cli" 12 "github.com/docker/docker/opts" 13 flag "github.com/docker/docker/pkg/mflag" 14 "github.com/docker/docker/pkg/stringid" 15 "github.com/docker/docker/reference" 16 "github.com/docker/go-units" 17 ) 18 19 // CmdImages lists the images in a specified repository, or all top-level images if no repository is specified. 20 // 21 // Usage: docker images [OPTIONS] [REPOSITORY] 22 func (cli *DockerCli) CmdImages(args ...string) error { 23 cmd := Cli.Subcmd("images", []string{"[REPOSITORY[:TAG]]"}, Cli.DockerCommands["images"].Description, true) 24 quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs") 25 all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (default hides intermediate images)") 26 noTrunc := cmd.Bool([]string{"-no-trunc"}, false, "Don't truncate output") 27 showDigests := cmd.Bool([]string{"-digests"}, false, "Show digests") 28 29 flFilter := opts.NewListOpts(nil) 30 cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided") 31 cmd.Require(flag.Max, 1) 32 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.NewArgs() 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 var matchName string 47 if cmd.NArg() == 1 { 48 matchName = cmd.Arg(0) 49 } 50 51 options := types.ImageListOptions{ 52 MatchName: matchName, 53 All: *all, 54 Filters: imageFilterArgs, 55 } 56 57 images, err := cli.client.ImageList(options) 58 if err != nil { 59 return err 60 } 61 62 w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0) 63 if !*quiet { 64 if *showDigests { 65 fmt.Fprintln(w, "REPOSITORY\tTAG\tDIGEST\tIMAGE ID\tCREATED\tSIZE") 66 } else { 67 fmt.Fprintln(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tSIZE") 68 } 69 } 70 71 for _, image := range images { 72 ID := image.ID 73 if !*noTrunc { 74 ID = stringid.TruncateID(ID) 75 } 76 77 repoTags := image.RepoTags 78 repoDigests := image.RepoDigests 79 80 if len(repoTags) == 1 && repoTags[0] == "<none>:<none>" && len(repoDigests) == 1 && repoDigests[0] == "<none>@<none>" { 81 // dangling image - clear out either repoTags or repoDigsts so we only show it once below 82 repoDigests = []string{} 83 } 84 85 // combine the tags and digests lists 86 tagsAndDigests := append(repoTags, repoDigests...) 87 for _, repoAndRef := range tagsAndDigests { 88 // default repo, tag, and digest to none - if there's a value, it'll be set below 89 repo := "<none>" 90 tag := "<none>" 91 digest := "<none>" 92 93 if !strings.HasPrefix(repoAndRef, "<none>") { 94 ref, err := reference.ParseNamed(repoAndRef) 95 if err != nil { 96 return err 97 } 98 repo = ref.Name() 99 100 switch x := ref.(type) { 101 case reference.Canonical: 102 digest = x.Digest().String() 103 case reference.NamedTagged: 104 tag = x.Tag() 105 } 106 } 107 108 if !*quiet { 109 if *showDigests { 110 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.Size))) 111 } else { 112 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.Size))) 113 } 114 } else { 115 fmt.Fprintln(w, ID) 116 } 117 } 118 } 119 120 if !*quiet { 121 w.Flush() 122 } 123 return nil 124 }