| package manifest | |
| import ( | |
| "bytes" | |
| "context" | |
| "encoding/json" | |
| "fmt" | |
| "github.com/distribution/reference" | |
| "github.com/docker/cli/cli" | |
| "github.com/docker/cli/cli/command" | |
| "github.com/docker/cli/cli/manifest/types" | |
| "github.com/docker/distribution/manifest/manifestlist" | |
| "github.com/spf13/cobra" | |
| ) | |
| type inspectOptions struct { | |
| ref string | |
| list string | |
| verbose bool | |
| insecure bool | |
| } | |
| // NewInspectCommand creates a new `docker manifest inspect` command | |
| func newInspectCommand(dockerCLI command.Cli) *cobra.Command { | |
| var opts inspectOptions | |
| cmd := &cobra.Command{ | |
| Use: "inspect [OPTIONS] [MANIFEST_LIST] MANIFEST", | |
| Short: "Display an image manifest, or manifest list", | |
| Args: cli.RequiresRangeArgs(1, 2), | |
| RunE: func(cmd *cobra.Command, args []string) error { | |
| switch len(args) { | |
| case 1: | |
| opts.ref = args[0] | |
| case 2: | |
| opts.list = args[0] | |
| opts.ref = args[1] | |
| } | |
| return runInspect(cmd.Context(), dockerCLI, opts) | |
| }, | |
| DisableFlagsInUseLine: true, | |
| } | |
| flags := cmd.Flags() | |
| flags.BoolVar(&opts.insecure, "insecure", false, "Allow communication with an insecure registry") | |
| flags.BoolVarP(&opts.verbose, "verbose", "v", false, "Output additional info including layers and platform") | |
| return cmd | |
| } | |
| func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) error { | |
| namedRef, err := normalizeReference(opts.ref) | |
| if err != nil { | |
| return err | |
| } | |
| // If list reference is provided, display the local manifest in a list | |
| if opts.list != "" { | |
| listRef, err := normalizeReference(opts.list) | |
| if err != nil { | |
| return err | |
| } | |
| imageManifest, err := newManifestStore(dockerCli).Get(listRef, namedRef) | |
| if err != nil { | |
| return err | |
| } | |
| return printManifest(dockerCli, imageManifest, opts) | |
| } | |
| // Try a local manifest list first | |
| localManifestList, err := newManifestStore(dockerCli).GetList(namedRef) | |
| if err == nil { | |
| return printManifestList(dockerCli, namedRef, localManifestList, opts) | |
| } | |
| // Next try a remote manifest | |
| registryClient := newRegistryClient(dockerCli, opts.insecure) | |
| imageManifest, err := registryClient.GetManifest(ctx, namedRef) | |
| if err == nil { | |
| return printManifest(dockerCli, imageManifest, opts) | |
| } | |
| // Finally try a remote manifest list | |
| manifestList, err := registryClient.GetManifestList(ctx, namedRef) | |
| if err != nil { | |
| return err | |
| } | |
| return printManifestList(dockerCli, namedRef, manifestList, opts) | |
| } | |
| func printManifest(dockerCli command.Cli, manifest types.ImageManifest, opts inspectOptions) error { | |
| buffer := new(bytes.Buffer) | |
| if !opts.verbose { | |
| _, raw, err := manifest.Payload() | |
| if err != nil { | |
| return err | |
| } | |
| if err := json.Indent(buffer, raw, "", "\t"); err != nil { | |
| return err | |
| } | |
| _, _ = fmt.Fprintln(dockerCli.Out(), buffer.String()) | |
| return nil | |
| } | |
| jsonBytes, err := json.MarshalIndent(manifest, "", "\t") | |
| if err != nil { | |
| return err | |
| } | |
| _, _ = dockerCli.Out().Write(append(jsonBytes, '\n')) | |
| return nil | |
| } | |
| func printManifestList(dockerCli command.Cli, namedRef reference.Named, list []types.ImageManifest, opts inspectOptions) error { | |
| if !opts.verbose { | |
| targetRepo := reference.TrimNamed(namedRef) | |
| manifests := make([]manifestlist.ManifestDescriptor, 0, len(list)) | |
| // More than one response. This is a manifest list. | |
| for _, img := range list { | |
| mfd, err := buildManifestDescriptor(targetRepo, img) | |
| if err != nil { | |
| return fmt.Errorf("failed to assemble ManifestDescriptor: %w", err) | |
| } | |
| manifests = append(manifests, mfd) | |
| } | |
| deserializedML, err := manifestlist.FromDescriptors(manifests) | |
| if err != nil { | |
| return err | |
| } | |
| jsonBytes, err := deserializedML.MarshalJSON() | |
| if err != nil { | |
| return err | |
| } | |
| _, _ = fmt.Fprintln(dockerCli.Out(), string(jsonBytes)) | |
| return nil | |
| } | |
| jsonBytes, err := json.MarshalIndent(list, "", "\t") | |
| if err != nil { | |
| return err | |
| } | |
| _, _ = dockerCli.Out().Write(append(jsonBytes, '\n')) | |
| return nil | |
| } |