summaryrefslogtreecommitdiff
path: root/cmd/podman/images.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman/images.go')
-rw-r--r--cmd/podman/images.go405
1 files changed, 0 insertions, 405 deletions
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
deleted file mode 100644
index ed33402ab..000000000
--- a/cmd/podman/images.go
+++ /dev/null
@@ -1,405 +0,0 @@
-package main
-
-import (
- "context"
- "fmt"
- "reflect"
- "sort"
- "strings"
- "time"
- "unicode"
-
- "github.com/containers/buildah/pkg/formats"
- "github.com/containers/libpod/cmd/podman/cliconfig"
- "github.com/containers/libpod/libpod/image"
- "github.com/containers/libpod/pkg/adapter"
- units "github.com/docker/go-units"
- digest "github.com/opencontainers/go-digest"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "github.com/spf13/cobra"
-)
-
-type imagesTemplateParams struct {
- Repository string
- Tag string
- ID string
- Digest digest.Digest
- Digests []digest.Digest
- CreatedAt time.Time
- CreatedSince string
- Size string
- ReadOnly bool
- History string
-}
-
-type imagesJSONParams struct {
- ID string `json:"ID"`
- Name []string `json:"Names"`
- Created string `json:"Created"`
- Digest digest.Digest `json:"Digest"`
- Digests []digest.Digest `json:"Digests"`
- CreatedAt time.Time `json:"CreatedAt"`
- Size *uint64 `json:"Size"`
- ReadOnly bool `json:"ReadOnly"`
- History []string `json:"History"`
-}
-
-type imagesOptions struct {
- quiet bool
- noHeading bool
- noTrunc bool
- digests bool
- format string
- outputformat string
- sort string
- all bool
- history bool
-}
-
-// Type declaration and functions for sorting the images output
-type imagesSorted []imagesTemplateParams
-
-func (a imagesSorted) Len() int { return len(a) }
-func (a imagesSorted) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
-
-type imagesSortedCreated struct{ imagesSorted }
-
-func (a imagesSortedCreated) Less(i, j int) bool {
- return a.imagesSorted[i].CreatedAt.After(a.imagesSorted[j].CreatedAt)
-}
-
-type imagesSortedID struct{ imagesSorted }
-
-func (a imagesSortedID) Less(i, j int) bool { return a.imagesSorted[i].ID < a.imagesSorted[j].ID }
-
-type imagesSortedTag struct{ imagesSorted }
-
-func (a imagesSortedTag) Less(i, j int) bool { return a.imagesSorted[i].Tag < a.imagesSorted[j].Tag }
-
-type imagesSortedRepository struct{ imagesSorted }
-
-func (a imagesSortedRepository) Less(i, j int) bool {
- return a.imagesSorted[i].Repository < a.imagesSorted[j].Repository
-}
-
-type imagesSortedSize struct{ imagesSorted }
-
-func (a imagesSortedSize) Less(i, j int) bool {
- size1, _ := units.FromHumanSize(a.imagesSorted[i].Size)
- size2, _ := units.FromHumanSize(a.imagesSorted[j].Size)
- return size1 < size2
-}
-
-var (
- imagesCommand cliconfig.ImagesValues
- imagesDescription = "Lists images previously pulled to the system or created on the system."
-
- _imagesCommand = cobra.Command{
- Use: "images [flags] [IMAGE]",
- Short: "List images in local storage",
- Long: imagesDescription,
- RunE: func(cmd *cobra.Command, args []string) error {
- imagesCommand.InputArgs = args
- imagesCommand.GlobalFlags = MainGlobalOpts
- imagesCommand.Remote = remoteclient
- return imagesCmd(&imagesCommand)
- },
- Example: `podman images --format json
- podman images --sort repository --format "table {{.ID}} {{.Repository}} {{.Tag}}"
- podman images --filter dangling=true`,
- }
-)
-
-func imagesInit(command *cliconfig.ImagesValues) {
- command.SetHelpTemplate(HelpTemplate())
- command.SetUsageTemplate(UsageTemplate())
-
- flags := command.Flags()
- flags.BoolVarP(&command.All, "all", "a", false, "Show all images (default hides intermediate images)")
- flags.BoolVar(&command.Digests, "digests", false, "Show digests")
- flags.StringSliceVarP(&command.Filter, "filter", "f", []string{}, "Filter output based on conditions provided (default [])")
- flags.StringVar(&command.Format, "format", "", "Change the output format to JSON or a Go template")
- flags.BoolVarP(&command.Noheading, "noheading", "n", false, "Do not print column headings")
- // TODO Need to learn how to deal with second name being a string instead of a char.
- // This needs to be "no-trunc, notruncate"
- flags.BoolVar(&command.NoTrunc, "no-trunc", false, "Do not truncate output")
- flags.BoolVarP(&command.Quiet, "quiet", "q", false, "Display only image IDs")
- flags.StringVar(&command.Sort, "sort", "created", "Sort by created, id, repository, size, or tag")
- flags.BoolVarP(&command.History, "history", "", false, "Display the image name history")
-
-}
-
-func init() {
- imagesCommand.Command = &_imagesCommand
- imagesInit(&imagesCommand)
-}
-
-func imagesCmd(c *cliconfig.ImagesValues) error {
- var (
- image string
- )
-
- ctx := getContext()
- runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
- if err != nil {
- return errors.Wrapf(err, "Could not get runtime")
- }
- defer runtime.DeferredShutdown(false)
- if len(c.InputArgs) == 1 {
- image = c.InputArgs[0]
- }
- if len(c.InputArgs) > 1 {
- return errors.New("'podman images' requires at most 1 argument")
- }
- if len(c.Filter) > 0 && image != "" {
- return errors.New("can not specify an image and a filter")
- }
- filters := c.Filter
- if len(filters) < 1 && len(image) > 0 {
- filters = append(filters, fmt.Sprintf("reference=%s", image))
- }
-
- var sortValues = map[string]bool{
- "created": true,
- "id": true,
- "repository": true,
- "size": true,
- "tag": true,
- }
- if !sortValues[c.Sort] {
- keys := make([]string, 0, len(sortValues))
- for k := range sortValues {
- keys = append(keys, k)
- }
- return errors.Errorf("invalid sort value %q, required values: %s", c.Sort, strings.Join(keys, ", "))
- }
-
- opts := imagesOptions{
- quiet: c.Quiet,
- noHeading: c.Noheading,
- noTrunc: c.NoTrunc,
- digests: c.Digests,
- format: c.Format,
- sort: c.Sort,
- all: c.All,
- history: c.History,
- }
-
- outputformat := opts.setOutputFormat()
- // These fields were renamed, so we need to provide backward compat for
- // the old names.
- if strings.Contains(outputformat, "{{.Created}}") {
- outputformat = strings.Replace(outputformat, "{{.Created}}", "{{.CreatedSince}}", -1)
- }
- if strings.Contains(outputformat, "{{.CreatedTime}}") {
- outputformat = strings.Replace(outputformat, "{{.CreatedTime}}", "{{.CreatedAt}}", -1)
- }
- opts.outputformat = outputformat
-
- filteredImages, err := runtime.GetFilteredImages(filters, false)
- if err != nil {
- return errors.Wrapf(err, "unable to get images")
- }
-
- for _, image := range filteredImages {
- if image.IsReadOnly() {
- opts.outputformat += "{{.ReadOnly}}\t"
- break
- }
- }
- return generateImagesOutput(ctx, filteredImages, opts)
-}
-
-func (i imagesOptions) setOutputFormat() string {
- if i.format != "" {
- // "\t" from the command line is not being recognized as a tab
- // replacing the string "\t" to a tab character if the user passes in "\t"
- return strings.Replace(i.format, `\t`, "\t", -1)
- }
- if i.quiet {
- return formats.IDString
- }
- format := "table {{.Repository}}\t{{if .Tag}}{{.Tag}}{{else}}<none>{{end}}\t"
- if i.noHeading {
- format = "{{.Repository}}\t{{if .Tag}}{{.Tag}}{{else}}<none>{{end}}\t"
- }
- if i.digests {
- format += "{{.Digest}}\t"
- }
- format += "{{.ID}}\t{{.CreatedSince}}\t{{.Size}}\t"
- if i.history {
- format += "{{if .History}}{{.History}}{{else}}<none>{{end}}\t"
- }
- return format
-}
-
-// imagesToGeneric creates an empty array of interfaces for output
-func imagesToGeneric(templParams []imagesTemplateParams, jsonParams []imagesJSONParams) []interface{} {
- genericParams := []interface{}{}
- if len(templParams) > 0 {
- for _, v := range templParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return genericParams
- }
- for _, v := range jsonParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return genericParams
-}
-
-func sortImagesOutput(sortBy string, imagesOutput imagesSorted) imagesSorted {
- switch sortBy {
- case "id":
- sort.Sort(imagesSortedID{imagesOutput})
- case "size":
- sort.Sort(imagesSortedSize{imagesOutput})
- case "tag":
- sort.Sort(imagesSortedTag{imagesOutput})
- case "repository":
- sort.Sort(imagesSortedRepository{imagesOutput})
- default:
- // default is created time
- sort.Sort(imagesSortedCreated{imagesOutput})
- }
- return imagesOutput
-}
-
-// getImagesTemplateOutput returns the images information to be printed in human readable format
-func getImagesTemplateOutput(ctx context.Context, images []*adapter.ContainerImage, opts imagesOptions) imagesSorted {
- var imagesOutput imagesSorted
- for _, img := range images {
- // If all is false and the image doesn't have a name, check to see if the top layer of the image is a parent
- // to another image's top layer. If it is, then it is an intermediate image so don't print out if the --all flag
- // is not set.
- isParent, err := img.IsParent(ctx)
- if err != nil {
- logrus.Errorf("error checking if image is a parent %q: %v", img.ID(), err)
- }
- if !opts.all && len(img.Names()) == 0 && isParent {
- continue
- }
- createdTime := img.Created()
-
- imageID := "sha256:" + img.ID()
- if !opts.noTrunc {
- imageID = shortID(img.ID())
- }
-
- // get all specified repo:tag and repo@digest pairs and print them separately
- repopairs, err := image.ReposToMap(img.Names())
- if err != nil {
- logrus.Errorf("error finding tag/digest for %s", img.ID())
- }
- outer:
- for repo, tags := range repopairs {
- for _, tag := range tags {
- size, err := img.Size(ctx)
- var sizeStr string
- if err != nil {
- sizeStr = err.Error()
- } else {
- sizeStr = units.HumanSizeWithPrecision(float64(*size), 3)
- lastNumIdx := strings.LastIndexFunc(sizeStr, unicode.IsNumber)
- sizeStr = sizeStr[:lastNumIdx+1] + " " + sizeStr[lastNumIdx+1:]
- }
- var imageDigest digest.Digest
- if len(tag) == 71 && strings.HasPrefix(tag, "sha256:") {
- imageDigest = digest.Digest(tag)
- tag = ""
- } else if img.Digest() != "" {
- imageDigest = img.Digest()
- }
- params := imagesTemplateParams{
- Repository: repo,
- Tag: tag,
- ID: imageID,
- Digest: imageDigest,
- Digests: img.Digests(),
- CreatedAt: createdTime,
- CreatedSince: units.HumanDuration(time.Since(createdTime)) + " ago",
- Size: sizeStr,
- ReadOnly: img.IsReadOnly(),
- History: strings.Join(img.NamesHistory(), ", "),
- }
- imagesOutput = append(imagesOutput, params)
- if opts.quiet { // Show only one image ID when quiet
- break outer
- }
- }
- }
- }
-
- // Sort images by created time
- sortImagesOutput(opts.sort, imagesOutput)
- return imagesOutput
-}
-
-// getImagesJSONOutput returns the images information in its raw form
-func getImagesJSONOutput(ctx context.Context, images []*adapter.ContainerImage) []imagesJSONParams {
- imagesOutput := []imagesJSONParams{}
- for _, img := range images {
- size, err := img.Size(ctx)
- if err != nil {
- size = nil
- }
- params := imagesJSONParams{
- ID: img.ID(),
- Name: img.Names(),
- Digest: img.Digest(),
- Digests: img.Digests(),
- Created: units.HumanDuration(time.Since(img.Created())) + " ago",
- CreatedAt: img.Created(),
- Size: size,
- ReadOnly: img.IsReadOnly(),
- History: img.NamesHistory(),
- }
- imagesOutput = append(imagesOutput, params)
- }
- return imagesOutput
-}
-
-// generateImagesOutput generates the images based on the format provided
-
-func generateImagesOutput(ctx context.Context, images []*adapter.ContainerImage, opts imagesOptions) error {
- templateMap := GenImageOutputMap()
- var out formats.Writer
-
- switch opts.format {
- case formats.JSONString:
- imagesOutput := getImagesJSONOutput(ctx, images)
- out = formats.JSONStructArray{Output: imagesToGeneric([]imagesTemplateParams{}, imagesOutput)}
- default:
- imagesOutput := getImagesTemplateOutput(ctx, images, opts)
- out = formats.StdoutTemplateArray{Output: imagesToGeneric(imagesOutput, []imagesJSONParams{}), Template: opts.outputformat, Fields: templateMap}
- }
- return out.Out()
-}
-
-// GenImageOutputMap generates the map used for outputting the images header
-// without requiring a populated image. This replaces the previous HeaderMap
-// call.
-func GenImageOutputMap() map[string]string {
- io := imagesTemplateParams{}
- v := reflect.Indirect(reflect.ValueOf(io))
- values := make(map[string]string)
-
- for i := 0; i < v.NumField(); i++ {
- key := v.Type().Field(i).Name
- value := key
- if value == "ID" {
- value = "Image" + value
- }
-
- if value == "ReadOnly" {
- values[key] = "R/O"
- continue
- }
- if value == "CreatedSince" {
- value = "created"
- }
- values[key] = strings.ToUpper(splitCamelCase(value))
- }
- return values
-}