move functions supporting images command to libkpod/image

Signed-off-by: Ryan Cole <rcyoalne@gmail.com>
This commit is contained in:
Ryan Cole 2017-07-23 21:38:03 -04:00
parent df7536e3c0
commit 0f44ff1d3b
6 changed files with 281 additions and 235 deletions

View file

@ -3,13 +3,11 @@ package main
import (
"fmt"
"os"
"strings"
"text/template"
is "github.com/containers/image/storage"
"github.com/containers/storage"
"github.com/kubernetes-incubator/cri-o/libkpod/common"
"github.com/kubernetes-incubator/cri-o/libkpod/image"
libkpodimage "github.com/kubernetes-incubator/cri-o/libkpod/image"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
@ -22,15 +20,6 @@ type imageOutputParams struct {
Size string
}
type filterParams struct {
dangling string
label string
beforeImage string // Images are sorted by date, so we can just output until we see the image
sinceImage string // Images are sorted by date, so we can just output until we don't see the image
seenImage bool // Hence this boolean
referencePattern string
}
var (
imagesFlags = []cli.Flag{
cli.BoolFlag{
@ -106,14 +95,9 @@ func imagesCmd(c *cli.Context) error {
return errors.New("'buildah images' requires at most 1 argument")
}
images, err := store.Images()
if err != nil {
return errors.Wrapf(err, "error reading images")
}
var params *filterParams
var params *libkpodimage.FilterParams
if c.IsSet("filter") {
params, err = parseFilter(images, c.String("filter"))
params, err = libkpodimage.ParseFilter(store, c.String("filter"))
if err != nil {
return errors.Wrapf(err, "error parsing filter")
}
@ -121,60 +105,15 @@ func imagesCmd(c *cli.Context) error {
params = nil
}
if len(images) > 0 && !noheading && !quiet && !hasTemplate {
imageList, err := libkpodimage.GetImagesMatchingFilter(store, params, name)
if err != nil {
return errors.Wrapf(err, "could not get list of images matching filter")
}
if len(imageList) > 0 && !noheading && !quiet && !hasTemplate {
outputHeader(truncate, digests)
}
return outputImages(images, formatString, store, params, name, hasTemplate, truncate, digests, quiet)
}
func parseFilter(images []storage.Image, filter string) (*filterParams, error) {
params := new(filterParams)
filterStrings := strings.Split(filter, ",")
for _, param := range filterStrings {
pair := strings.SplitN(param, "=", 2)
switch strings.TrimSpace(pair[0]) {
case "dangling":
if common.IsValidBool(pair[1]) {
params.dangling = pair[1]
} else {
return nil, fmt.Errorf("invalid filter: '%s=[%s]'", pair[0], pair[1])
}
case "label":
params.label = pair[1]
case "before":
if imageExists(images, pair[1]) {
params.beforeImage = pair[1]
} else {
return nil, fmt.Errorf("no such id: %s", pair[0])
}
case "since":
if imageExists(images, pair[1]) {
params.sinceImage = pair[1]
} else {
return nil, fmt.Errorf("no such id: %s``", pair[0])
}
case "reference":
params.referencePattern = pair[1]
default:
return nil, fmt.Errorf("invalid filter: '%s'", pair[0])
}
}
return params, nil
}
func imageExists(images []storage.Image, ref string) bool {
for _, image := range images {
if matchesID(image.ID, ref) {
return true
}
for _, name := range image.Names {
if matchesReference(name, ref) {
return true
}
}
}
return false
return outputImages(store, imageList, formatString, hasTemplate, truncate, digests, quiet)
}
func outputHeader(truncate, digests bool) {
@ -191,7 +130,7 @@ func outputHeader(truncate, digests bool) {
fmt.Printf("%-22s %s\n", "CREATED AT", "SIZE")
}
func outputImages(images []storage.Image, format string, store storage.Store, filters *filterParams, argName string, hasTemplate, truncate, digests, quiet bool) error {
func outputImages(store storage.Store, images []storage.Image, format string, hasTemplate, truncate, digests, quiet bool) error {
for _, img := range images {
imageMetadata, err := image.ParseMetadata(img)
if err != nil {
@ -202,156 +141,33 @@ func outputImages(images []storage.Image, format string, store storage.Store, fi
if len(imageMetadata.Blobs) > 0 {
digest = string(imageMetadata.Blobs[0].Digest)
}
size, _ := image.Size(store, img)
size, _ := libkpodimage.Size(store, img)
names := []string{""}
if len(img.Names) > 0 {
names = img.Names
} else {
// images without names should be printed with "<none>" as the image name
names = append(names, "<none>")
if quiet {
fmt.Printf("%-64s\n", img.ID)
// We only want to print each id once
break
}
for _, name := range names {
if !matchesFilter(img, store, name, filters) || !matchesReference(name, argName) {
continue
}
if quiet {
fmt.Printf("%-64s\n", img.ID)
// We only want to print each id once
break
}
params := imageOutputParams{
ID: img.ID,
Name: name,
Digest: digest,
CreatedAt: createdTime,
Size: formattedSize(size),
}
if hasTemplate {
err = outputUsingTemplate(format, params)
if err != nil {
return err
}
continue
}
outputUsingFormatString(truncate, digests, params)
params := imageOutputParams{
ID: img.ID,
Name: img.Names[0],
Digest: digest,
CreatedAt: createdTime,
Size: libkpodimage.FormattedSize(size),
}
if hasTemplate {
err = outputUsingTemplate(format, params)
if err != nil {
return err
}
continue
}
outputUsingFormatString(truncate, digests, params)
}
return nil
}
func matchesFilter(image storage.Image, store storage.Store, name string, params *filterParams) bool {
if params == nil {
return true
}
if params.dangling != "" && !matchesDangling(name, params.dangling) {
return false
} else if params.label != "" && !matchesLabel(image, store, params.label) {
return false
} else if params.beforeImage != "" && !matchesBeforeImage(image, name, params) {
return false
} else if params.sinceImage != "" && !matchesSinceImage(image, name, params) {
return false
} else if params.referencePattern != "" && !matchesReference(name, params.referencePattern) {
return false
}
return true
}
func matchesDangling(name string, dangling string) bool {
if common.IsFalse(dangling) && name != "<none>" {
return true
} else if common.IsTrue(dangling) && name == "<none>" {
return true
}
return false
}
func matchesLabel(image storage.Image, store storage.Store, label string) bool {
storeRef, err := is.Transport.ParseStoreReference(store, "@"+image.ID)
if err != nil {
}
img, err := storeRef.NewImage(nil)
if err != nil {
return false
}
info, err := img.Inspect()
if err != nil {
return false
}
pair := strings.SplitN(label, "=", 2)
for key, value := range info.Labels {
if key == pair[0] {
if len(pair) == 2 {
if value == pair[1] {
return true
}
} else {
return false
}
}
}
return false
}
// Returns true if the image was created since the filter image. Returns
// false otherwise
func matchesBeforeImage(image storage.Image, name string, params *filterParams) bool {
if params.seenImage {
return false
}
if matchesReference(name, params.beforeImage) || matchesID(image.ID, params.beforeImage) {
params.seenImage = true
return false
}
return true
}
// Returns true if the image was created since the filter image. Returns
// false otherwise
func matchesSinceImage(image storage.Image, name string, params *filterParams) bool {
if params.seenImage {
return true
}
if matchesReference(name, params.sinceImage) || matchesID(image.ID, params.sinceImage) {
params.seenImage = true
}
return false
}
func matchesID(id, argID string) bool {
return strings.HasPrefix(argID, id)
}
func matchesReference(name, argName string) bool {
if argName == "" {
return true
}
splitName := strings.Split(name, ":")
// If the arg contains a tag, we handle it differently than if it does not
if strings.Contains(argName, ":") {
splitArg := strings.Split(argName, ":")
return strings.HasSuffix(splitName[0], splitArg[0]) && (splitName[1] == splitArg[1])
}
return strings.HasSuffix(splitName[0], argName)
}
func formattedSize(size int64) string {
suffixes := [5]string{"B", "KB", "MB", "GB", "TB"}
count := 0
formattedSize := float64(size)
for formattedSize >= 1024 && count < 4 {
formattedSize /= 1024
count++
}
return fmt.Sprintf("%.4g %s", formattedSize, suffixes[count])
}
func outputUsingTemplate(format string, params imageOutputParams) error {
tmpl, err := template.New("image").Parse(format)
if err != nil {