package graph import ( "fmt" "path" "sort" "strings" "github.com/Sirupsen/logrus" "github.com/docker/docker/api/types" "github.com/docker/docker/image" "github.com/docker/docker/pkg/parsers/filters" "github.com/docker/docker/utils" ) var acceptedImageFilterTags = map[string]struct{}{ "dangling": {}, "label": {}, } type ImagesConfig struct { Filters string Filter string All bool } type ByCreated []*types.Image func (r ByCreated) Len() int { return len(r) } func (r ByCreated) Swap(i, j int) { r[i], r[j] = r[j], r[i] } func (r ByCreated) Less(i, j int) bool { return r[i].Created < r[j].Created } func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) { var ( allImages map[string]*image.Image err error filtTagged = true filtLabel = false ) imageFilters, err := filters.FromParam(config.Filters) if err != nil { return nil, err } for name := range imageFilters { if _, ok := acceptedImageFilterTags[name]; !ok { return nil, fmt.Errorf("Invalid filter '%s'", name) } } if i, ok := imageFilters["dangling"]; ok { for _, value := range i { if strings.ToLower(value) == "true" { filtTagged = false } } } _, filtLabel = imageFilters["label"] if config.All && filtTagged { allImages, err = s.graph.Map() } else { allImages, err = s.graph.Heads() } if err != nil { return nil, err } lookup := make(map[string]*types.Image) s.Lock() for repoName, repository := range s.Repositories { if config.Filter != "" { if match, _ := path.Match(config.Filter, repoName); !match { continue } } for ref, id := range repository { imgRef := utils.ImageReference(repoName, ref) image, err := s.graph.Get(id) if err != nil { logrus.Warnf("couldn't load %s from %s: %s", id, imgRef, err) continue } if lImage, exists := lookup[id]; exists { if filtTagged { if utils.DigestReference(ref) { lImage.RepoDigests = append(lImage.RepoDigests, imgRef) } else { // Tag Ref. lImage.RepoTags = append(lImage.RepoTags, imgRef) } } } else { // get the boolean list for if only the untagged images are requested delete(allImages, id) if !imageFilters.MatchKVList("label", image.ContainerConfig.Labels) { continue } if filtTagged { newImage := new(types.Image) newImage.ParentId = image.Parent newImage.ID = image.ID newImage.Created = int(image.Created.Unix()) newImage.Size = int(image.Size) newImage.VirtualSize = int(s.graph.GetParentsSize(image, 0) + image.Size) newImage.Labels = image.ContainerConfig.Labels if utils.DigestReference(ref) { newImage.RepoTags = []string{} newImage.RepoDigests = []string{imgRef} } else { newImage.RepoTags = []string{imgRef} newImage.RepoDigests = []string{} } lookup[id] = newImage } } } } s.Unlock() images := []*types.Image{} for _, value := range lookup { images = append(images, value) } // Display images which aren't part of a repository/tag if config.Filter == "" || filtLabel { for _, image := range allImages { if !imageFilters.MatchKVList("label", image.ContainerConfig.Labels) { continue } newImage := new(types.Image) newImage.ParentId = image.Parent newImage.RepoTags = []string{":"} newImage.RepoDigests = []string{"@"} newImage.ID = image.ID newImage.Created = int(image.Created.Unix()) newImage.Size = int(image.Size) newImage.VirtualSize = int(s.graph.GetParentsSize(image, 0) + image.Size) newImage.Labels = image.ContainerConfig.Labels images = append(images, newImage) } } sort.Sort(sort.Reverse(ByCreated(images))) return images, nil }