summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/image/filters.go176
-rw-r--r--libpod/image/image.go13
2 files changed, 189 insertions, 0 deletions
diff --git a/libpod/image/filters.go b/libpod/image/filters.go
new file mode 100644
index 000000000..d545f1bfc
--- /dev/null
+++ b/libpod/image/filters.go
@@ -0,0 +1,176 @@
+package image
+
+import (
+ "context"
+ "fmt"
+ "github.com/pkg/errors"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/containers/libpod/pkg/inspect"
+ "github.com/sirupsen/logrus"
+)
+
+// ResultFilter is a mock function for image filtering
+type ResultFilter func(*Image) bool
+
+// Filter is a function to determine whether an image is included in
+// command output. Images to be outputted are tested using the function. A true
+// return will include the image, a false return will exclude it.
+type Filter func(*Image, *inspect.ImageData) bool
+
+// CreatedBeforeFilter allows you to filter on images created before
+// the given time.Time
+func CreatedBeforeFilter(createTime time.Time) ResultFilter {
+ return func(i *Image) bool {
+ return i.Created().Before(createTime)
+ }
+}
+
+// CreatedAfterFilter allows you to filter on images created after
+// the given time.Time
+func CreatedAfterFilter(createTime time.Time) ResultFilter {
+ return func(i *Image) bool {
+ return i.Created().After(createTime)
+ }
+}
+
+// DanglingFilter allows you to filter images for dangling images
+func DanglingFilter(danglingImages bool) ResultFilter {
+ return func(i *Image) bool {
+ if danglingImages {
+ return i.Dangling()
+ }
+ return !i.Dangling()
+ }
+}
+
+// ReadOnlyFilter allows you to filter images based on read/only and read/write
+func ReadOnlyFilter(readOnly bool) ResultFilter {
+ return func(i *Image) bool {
+ if readOnly {
+ return i.IsReadOnly()
+ }
+ return !i.IsReadOnly()
+ }
+}
+
+// LabelFilter allows you to filter by images labels key and/or value
+func LabelFilter(ctx context.Context, labelfilter string) ResultFilter {
+ // We need to handle both label=key and label=key=value
+ return func(i *Image) bool {
+ var value string
+ splitFilter := strings.Split(labelfilter, "=")
+ key := splitFilter[0]
+ if len(splitFilter) > 1 {
+ value = splitFilter[1]
+ }
+ labels, err := i.Labels(ctx)
+ if err != nil {
+ return false
+ }
+ if len(strings.TrimSpace(labels[key])) > 0 && len(strings.TrimSpace(value)) == 0 {
+ return true
+ }
+ return labels[key] == value
+ }
+}
+
+// ReferenceFilter allows you to filter by image name
+// Replacing all '/' with '|' so that filepath.Match() can work
+// '|' character is not valid in image name, so this is safe
+func ReferenceFilter(ctx context.Context, referenceFilter string) ResultFilter {
+ filter := fmt.Sprintf("*%s*", referenceFilter)
+ filter = strings.Replace(filter, "/", "|", -1)
+ return func(i *Image) bool {
+ if len(referenceFilter) < 1 {
+ return true
+ }
+ for _, name := range i.Names() {
+ newName := strings.Replace(name, "/", "|", -1)
+ match, err := filepath.Match(filter, newName)
+ if err != nil {
+ logrus.Errorf("failed to match %s and %s, %q", name, referenceFilter, err)
+ }
+ if match {
+ return true
+ }
+ }
+ return false
+ }
+}
+
+// OutputImageFilter allows you to filter by an a specific image name
+func OutputImageFilter(userImage *Image) ResultFilter {
+ return func(i *Image) bool {
+ return userImage.ID() == i.ID()
+ }
+}
+
+// FilterImages filters images using a set of predefined filter funcs
+func FilterImages(images []*Image, filters []ResultFilter) []*Image {
+ var filteredImages []*Image
+ for _, image := range images {
+ include := true
+ for _, filter := range filters {
+ include = include && filter(image)
+ }
+ if include {
+ filteredImages = append(filteredImages, image)
+ }
+ }
+ return filteredImages
+}
+
+// createFilterFuncs returns an array of filter functions based on the user inputs
+// and is later used to filter images for output
+func (ir *Runtime) createFilterFuncs(filters []string, img *Image) ([]ResultFilter, error) {
+ var filterFuncs []ResultFilter
+ ctx := context.Background()
+ for _, filter := range filters {
+ splitFilter := strings.Split(filter, "=")
+ if len(splitFilter) < 2 {
+ return nil, errors.Errorf("invalid filter syntax %s", filter)
+ }
+ switch splitFilter[0] {
+ case "before":
+ before, err := ir.NewFromLocal(splitFilter[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to find image %s in local stores", splitFilter[1])
+ }
+ filterFuncs = append(filterFuncs, CreatedBeforeFilter(before.Created()))
+ case "after":
+ after, err := ir.NewFromLocal(splitFilter[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to find image %s in local stores", splitFilter[1])
+ }
+ filterFuncs = append(filterFuncs, CreatedAfterFilter(after.Created()))
+ case "readonly":
+ readonly, err := strconv.ParseBool(splitFilter[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "invalid filter readonly=%s", splitFilter[1])
+ }
+ filterFuncs = append(filterFuncs, ReadOnlyFilter(readonly))
+ case "dangling":
+ danglingImages, err := strconv.ParseBool(splitFilter[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "invalid filter dangling=%s", splitFilter[1])
+ }
+ filterFuncs = append(filterFuncs, DanglingFilter(danglingImages))
+ case "label":
+ labelFilter := strings.Join(splitFilter[1:], "=")
+ filterFuncs = append(filterFuncs, LabelFilter(ctx, labelFilter))
+ case "reference":
+ referenceFilter := strings.Join(splitFilter[1:], "=")
+ filterFuncs = append(filterFuncs, ReferenceFilter(ctx, referenceFilter))
+ default:
+ return nil, errors.Errorf("invalid filter %s ", splitFilter[0])
+ }
+ }
+ if img != nil {
+ filterFuncs = append(filterFuncs, OutputImageFilter(img))
+ }
+ return filterFuncs, nil
+}
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 129ccd376..c8583a1c5 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -216,6 +216,19 @@ func (ir *Runtime) Shutdown(force bool) error {
return err
}
+// GetImagesWithFilters gets images with a series of filters applied
+func (ir *Runtime) GetImagesWithFilters(filters []string) ([]*Image, error) {
+ filterFuncs, err := ir.createFilterFuncs(filters, nil)
+ if err != nil {
+ return nil, err
+ }
+ images, err := ir.GetImages()
+ if err != nil {
+ return nil, err
+ }
+ return FilterImages(images, filterFuncs), nil
+}
+
func (i *Image) reloadImage() error {
newImage, err := i.imageruntime.getImage(i.ID())
if err != nil {