github.com/justincormack/cli@v0.0.0-20201215022714-831ebeae9675/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/docker/cli/cli"
    10  	"github.com/docker/cli/cli/command"
    11  	"github.com/docker/cli/cli/manifest/types"
    12  	"github.com/docker/distribution/manifest/manifestlist"
    13  	"github.com/docker/distribution/reference"
    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(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(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  	ctx := context.Background()
    80  	registryClient := dockerCli.RegistryClient(opts.insecure)
    81  	imageManifest, err := registryClient.GetManifest(ctx, namedRef)
    82  	if err == nil {
    83  		return printManifest(dockerCli, imageManifest, opts)
    84  	}
    85  
    86  	// Finally try a remote manifest list
    87  	manifestList, err := registryClient.GetManifestList(ctx, namedRef)
    88  	if err != nil {
    89  		return err
    90  	}
    91  	return printManifestList(dockerCli, namedRef, manifestList, opts)
    92  }
    93  
    94  func printManifest(dockerCli command.Cli, manifest types.ImageManifest, opts inspectOptions) error {
    95  	buffer := new(bytes.Buffer)
    96  	if !opts.verbose {
    97  		_, raw, err := manifest.Payload()
    98  		if err != nil {
    99  			return err
   100  		}
   101  		if err := json.Indent(buffer, raw, "", "\t"); err != nil {
   102  			return err
   103  		}
   104  		fmt.Fprintln(dockerCli.Out(), buffer.String())
   105  		return nil
   106  	}
   107  	jsonBytes, err := json.MarshalIndent(manifest, "", "\t")
   108  	if err != nil {
   109  		return err
   110  	}
   111  	dockerCli.Out().Write(append(jsonBytes, '\n'))
   112  	return nil
   113  }
   114  
   115  func printManifestList(dockerCli command.Cli, namedRef reference.Named, list []types.ImageManifest, opts inspectOptions) error {
   116  	if !opts.verbose {
   117  		targetRepo, err := registry.ParseRepositoryInfo(namedRef)
   118  		if err != nil {
   119  			return err
   120  		}
   121  
   122  		manifests := []manifestlist.ManifestDescriptor{}
   123  		// More than one response. This is a manifest list.
   124  		for _, img := range list {
   125  			mfd, err := buildManifestDescriptor(targetRepo, img)
   126  			if err != nil {
   127  				return errors.Wrap(err, "failed to assemble ManifestDescriptor")
   128  			}
   129  			manifests = append(manifests, mfd)
   130  		}
   131  		deserializedML, err := manifestlist.FromDescriptors(manifests)
   132  		if err != nil {
   133  			return err
   134  		}
   135  		jsonBytes, err := deserializedML.MarshalJSON()
   136  		if err != nil {
   137  			return err
   138  		}
   139  		fmt.Fprintln(dockerCli.Out(), string(jsonBytes))
   140  		return nil
   141  	}
   142  	jsonBytes, err := json.MarshalIndent(list, "", "\t")
   143  	if err != nil {
   144  		return err
   145  	}
   146  	dockerCli.Out().Write(append(jsonBytes, '\n'))
   147  	return nil
   148  }