mirror of
https://github.com/containers/podman.git
synced 2025-06-01 01:00:22 +08:00
197 lines
5.7 KiB
Go
197 lines
5.7 KiB
Go
package image
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/containers/podman/v3/pkg/inspect"
|
|
"github.com/containers/podman/v3/pkg/util"
|
|
"github.com/pkg/errors"
|
|
"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)
|
|
}
|
|
}
|
|
|
|
// IntermediateFilter returns filter for intermediate images (i.e., images
|
|
// with children and no tags).
|
|
func (ir *Runtime) IntermediateFilter(ctx context.Context, images []*Image) (ResultFilter, error) {
|
|
tree, err := ir.layerTree()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return func(i *Image) bool {
|
|
if len(i.Names()) > 0 {
|
|
return true
|
|
}
|
|
children, err := tree.children(ctx, i, false)
|
|
if err != nil {
|
|
logrus.Error(err.Error())
|
|
return false
|
|
}
|
|
return len(children) == 0
|
|
}, nil
|
|
}
|
|
|
|
// 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, filter string) ResultFilter {
|
|
// We need to handle both label=key and label=key=value
|
|
return func(i *Image) bool {
|
|
labels, err := i.Labels(ctx)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return util.MatchLabelFilters([]string{filter}, labels)
|
|
}
|
|
}
|
|
|
|
// 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
|
|
}
|
|
}
|
|
|
|
// IDFilter allows you to filter by image Id
|
|
func IDFilter(idFilter string) ResultFilter {
|
|
return func(i *Image) bool {
|
|
return i.ID() == idFilter
|
|
}
|
|
}
|
|
|
|
// 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.SplitN(filter, "=", 2)
|
|
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 "since", "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":
|
|
filterFuncs = append(filterFuncs, ReferenceFilter(ctx, splitFilter[1]))
|
|
case "id":
|
|
filterFuncs = append(filterFuncs, IDFilter(splitFilter[1]))
|
|
default:
|
|
return nil, errors.Errorf("invalid filter %s ", splitFilter[0])
|
|
}
|
|
}
|
|
if img != nil {
|
|
filterFuncs = append(filterFuncs, OutputImageFilter(img))
|
|
}
|
|
return filterFuncs, nil
|
|
}
|