github.1git.de/docker/cli@v26.1.3+incompatible/cli/command/manifest/inspect.go (about)

     1  package manifest
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  
     9  	"github.com/distribution/reference"
    10  	"github.com/docker/cli/cli"
    11  	"github.com/docker/cli/cli/command"
    12  	"github.com/docker/cli/cli/manifest/types"
    13  	"github.com/docker/distribution/manifest/manifestlist"
    14  	"github.com/docker/docker/registry"
    15  	"github.com/pkg/errors"
    16  	"github.com/spf13/cobra"
    17  )
    18  
    19  type inspectOptions struct {
    20  	ref      string
    21  	list     string
    22  	verbose  bool
    23  	insecure bool
    24  }
    25  
    26  // NewInspectCommand creates a new `docker manifest inspect` command
    27  func newInspectCommand(dockerCli command.Cli) *cobra.Command {
    28  	var opts inspectOptions
    29  
    30  	cmd := &cobra.Command{
    31  		Use:   "inspect [OPTIONS] [MANIFEST_LIST] MANIFEST",
    32  		Short: "Display an image manifest, or manifest list",
    33  		Args:  cli.RequiresRangeArgs(1, 2),
    34  		RunE: func(cmd *cobra.Command, args []string) error {
    35  			switch len(args) {
    36  			case 1:
    37  				opts.ref = args[0]
    38  			case 2:
    39  				opts.list = args[0]
    40  				opts.ref = args[1]
    41  			}
    42  			return runInspect(cmd.Context(), dockerCli, opts)
    43  		},
    44  	}
    45  
    46  	flags := cmd.Flags()
    47  	flags.BoolVar(&opts.insecure, "insecure", false, "Allow communication with an insecure registry")
    48  	flags.BoolVarP(&opts.verbose, "verbose", "v", false, "Output additional info including layers and platform")
    49  	return cmd
    50  }
    51  
    52  func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) error {
    53  	namedRef, err := normalizeReference(opts.ref)
    54  	if err != nil {
    55  		return err
    56  	}
    57  
    58  	// If list reference is provided, display the local manifest in a list
    59  	if opts.list != "" {
    60  		listRef, err := normalizeReference(opts.list)
    61  		if err != nil {
    62  			return err
    63  		}
    64  
    65  		imageManifest, err := dockerCli.ManifestStore().Get(listRef, namedRef)
    66  		if err != nil {
    67  			return err
    68  		}
    69  		return printManifest(dockerCli, imageManifest, opts)
    70  	}
    71  
    72  	// Try a local manifest list first
    73  	localManifestList, err := dockerCli.ManifestStore().GetList(namedRef)
    74  	if err == nil {
    75  		return printManifestList(dockerCli, namedRef, localManifestList, opts)
    76  	}
    77  
    78  	// Next try a remote manifest
    79  	registryClient := dockerCli.RegistryClient(opts.insecure)
    80  	imageManifest, err := registryClient.GetManifest(ctx, namedRef)
    81  	if err == nil {
    82  		return printManifest(dockerCli, imageManifest, opts)
    83  	}
    84  
    85  	// Finally try a remote manifest list
    86  	manifestList, err := registryClient.GetManifestList(ctx, namedRef)
    87  	if err != nil {
    88  		return err
    89  	}
    90  	return printManifestList(dockerCli, namedRef, manifestList, opts)
    91  }
    92  
    93  func printManifest(dockerCli command.Cli, manifest types.ImageManifest, opts inspectOptions) error {
    94  	buffer := new(bytes.Buffer)
    95  	if !opts.verbose {
    96  		_, raw, err := manifest.Payload()
    97  		if err != nil {
    98  			return err
    99  		}
   100  		if err := json.Indent(buffer, raw, "", "\t"); err != nil {
   101  			return err
   102  		}
   103  		fmt.Fprintln(dockerCli.Out(), buffer.String())
   104  		return nil
   105  	}
   106  	jsonBytes, err := json.MarshalIndent(manifest, "", "\t")
   107  	if err != nil {
   108  		return err
   109  	}
   110  	dockerCli.Out().Write(append(jsonBytes, '\n'))
   111  	return nil
   112  }
   113  
   114  func printManifestList(dockerCli command.Cli, namedRef reference.Named, list []types.ImageManifest, opts inspectOptions) error {
   115  	if !opts.verbose {
   116  		targetRepo, err := registry.ParseRepositoryInfo(namedRef)
   117  		if err != nil {
   118  			return err
   119  		}
   120  
   121  		manifests := []manifestlist.ManifestDescriptor{}
   122  		// More than one response. This is a manifest list.
   123  		for _, img := range list {
   124  			mfd, err := buildManifestDescriptor(targetRepo, img)
   125  			if err != nil {
   126  				return errors.Wrap(err, "failed to assemble ManifestDescriptor")
   127  			}
   128  			manifests = append(manifests, mfd)
   129  		}
   130  		deserializedML, err := manifestlist.FromDescriptors(manifests)
   131  		if err != nil {
   132  			return err
   133  		}
   134  		jsonBytes, err := deserializedML.MarshalJSON()
   135  		if err != nil {
   136  			return err
   137  		}
   138  		fmt.Fprintln(dockerCli.Out(), string(jsonBytes))
   139  		return nil
   140  	}
   141  	jsonBytes, err := json.MarshalIndent(list, "", "\t")
   142  	if err != nil {
   143  		return err
   144  	}
   145  	dockerCli.Out().Write(append(jsonBytes, '\n'))
   146  	return nil
   147  }