github.com/khulnasoft/cli@v0.0.0-20240402070845-01bcad7beefa/cli/command/image/list.go (about)

     1  package image
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  
     8  	"github.com/docker/docker/api/types/image"
     9  	"github.com/khulnasoft/cli/cli"
    10  	"github.com/khulnasoft/cli/cli/command"
    11  	"github.com/khulnasoft/cli/cli/command/formatter"
    12  	flagsHelper "github.com/khulnasoft/cli/cli/flags"
    13  	"github.com/khulnasoft/cli/opts"
    14  	"github.com/spf13/cobra"
    15  )
    16  
    17  type imagesOptions struct {
    18  	matchName string
    19  
    20  	quiet       bool
    21  	all         bool
    22  	noTrunc     bool
    23  	showDigests bool
    24  	format      string
    25  	filter      opts.FilterOpt
    26  	calledAs    string
    27  }
    28  
    29  // NewImagesCommand creates a new `docker images` command
    30  func NewImagesCommand(dockerCLI command.Cli) *cobra.Command {
    31  	options := imagesOptions{filter: opts.NewFilterOpt()}
    32  
    33  	cmd := &cobra.Command{
    34  		Use:   "images [OPTIONS] [REPOSITORY[:TAG]]",
    35  		Short: "List images",
    36  		Args:  cli.RequiresMaxArgs(1),
    37  		RunE: func(cmd *cobra.Command, args []string) error {
    38  			if len(args) > 0 {
    39  				options.matchName = args[0]
    40  			}
    41  			// Pass through how the command was invoked. We use this to print
    42  			// warnings when an ambiguous argument was passed when using the
    43  			// legacy (top-level) "docker images" subcommand.
    44  			options.calledAs = cmd.CalledAs()
    45  			return runImages(cmd.Context(), dockerCLI, options)
    46  		},
    47  		Annotations: map[string]string{
    48  			"category-top": "7",
    49  			"aliases":      "docker image ls, docker image list, docker images",
    50  		},
    51  	}
    52  
    53  	flags := cmd.Flags()
    54  
    55  	flags.BoolVarP(&options.quiet, "quiet", "q", false, "Only show image IDs")
    56  	flags.BoolVarP(&options.all, "all", "a", false, "Show all images (default hides intermediate images)")
    57  	flags.BoolVar(&options.noTrunc, "no-trunc", false, "Don't truncate output")
    58  	flags.BoolVar(&options.showDigests, "digests", false, "Show digests")
    59  	flags.StringVar(&options.format, "format", "", flagsHelper.FormatHelp)
    60  	flags.VarP(&options.filter, "filter", "f", "Filter output based on conditions provided")
    61  
    62  	return cmd
    63  }
    64  
    65  func newListCommand(dockerCLI command.Cli) *cobra.Command {
    66  	cmd := *NewImagesCommand(dockerCLI)
    67  	cmd.Aliases = []string{"list"}
    68  	cmd.Use = "ls [OPTIONS] [REPOSITORY[:TAG]]"
    69  	return &cmd
    70  }
    71  
    72  func runImages(ctx context.Context, dockerCLI command.Cli, options imagesOptions) error {
    73  	filters := options.filter.Value()
    74  	if options.matchName != "" {
    75  		filters.Add("reference", options.matchName)
    76  	}
    77  
    78  	images, err := dockerCLI.Client().ImageList(ctx, image.ListOptions{
    79  		All:     options.all,
    80  		Filters: filters,
    81  	})
    82  	if err != nil {
    83  		return err
    84  	}
    85  
    86  	format := options.format
    87  	if len(format) == 0 {
    88  		if len(dockerCLI.ConfigFile().ImagesFormat) > 0 && !options.quiet {
    89  			format = dockerCLI.ConfigFile().ImagesFormat
    90  		} else {
    91  			format = formatter.TableFormatKey
    92  		}
    93  	}
    94  
    95  	imageCtx := formatter.ImageContext{
    96  		Context: formatter.Context{
    97  			Output: dockerCLI.Out(),
    98  			Format: formatter.NewImageFormat(format, options.quiet, options.showDigests),
    99  			Trunc:  !options.noTrunc,
   100  		},
   101  		Digest: options.showDigests,
   102  	}
   103  	if err := formatter.ImageWrite(imageCtx, images); err != nil {
   104  		return err
   105  	}
   106  	if options.matchName != "" && len(images) == 0 && options.calledAs == "images" {
   107  		printAmbiguousHint(dockerCLI.Err(), options.matchName)
   108  	}
   109  	return nil
   110  }
   111  
   112  // printAmbiguousHint prints an informational warning if the provided filter
   113  // argument is ambiguous.
   114  //
   115  // The "docker images" top-level subcommand predates the "docker <object> <verb>"
   116  // convention (e.g. "docker image ls"), but accepts a positional argument to
   117  // search/filter images by name (globbing). It's common for users to accidentally
   118  // mistake these commands, and to use (e.g.) "docker images ls", expecting
   119  // to see all images, but ending up with an empty list because no image named
   120  // "ls" was found.
   121  //
   122  // Disallowing these search-terms would be a breaking change, but we can print
   123  // and informational message to help the users correct their mistake.
   124  func printAmbiguousHint(stdErr io.Writer, matchName string) {
   125  	switch matchName {
   126  	// List of subcommands for "docker image" and their aliases (see "docker image --help"):
   127  	case "build",
   128  		"history",
   129  		"import",
   130  		"inspect",
   131  		"list",
   132  		"load",
   133  		"ls",
   134  		"prune",
   135  		"pull",
   136  		"push",
   137  		"rm",
   138  		"save",
   139  		"tag":
   140  
   141  		_, _ = fmt.Fprintf(stdErr, "\nNo images found matching %q: did you mean \"docker image %[1]s\"?\n", matchName)
   142  	}
   143  }