moby/graph/list.go
Derek McGowan 2b58b677a5 Separate graph from image
Move graph related functions in image to graph package.
Consolidating graph functionality is the first step in refactoring graph into an image store model.
Subsequent refactors will involve breaking up graph into multiple types with a strongly defined interface.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2015-06-05 18:06:09 -07:00

153 lines
3.7 KiB
Go

package graph
import (
"fmt"
"log"
"path"
"sort"
"strings"
"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 {
log.Printf("Warning: 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{"<none>:<none>"}
newImage.RepoDigests = []string{"<none>@<none>"}
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
}