Files
docker-cli/cli/command/manifest/inspect.go
Derek McGowan 1fd2d66df8 Fix manifest lists to always use correct size
Stores complete OCI descriptor instead of digest and platform
fields. This includes the size which was getting lost by not
storing the original manifest bytes.

Attempt to support existing cached files, if not output
the filename with the incorrect content.

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
2018-06-28 18:17:38 -07:00

149 lines
3.8 KiB
Go

package manifest
import (
"bytes"
"context"
"encoding/json"
"fmt"
"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/docker/distribution/reference"
"github.com/docker/docker/registry"
"github.com/pkg/errors"
"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(dockerCli, opts)
},
}
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(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 := dockerCli.ManifestStore().Get(listRef, namedRef)
if err != nil {
return err
}
return printManifest(dockerCli, imageManifest, opts)
}
// Try a local manifest list first
localManifestList, err := dockerCli.ManifestStore().GetList(namedRef)
if err == nil {
return printManifestList(dockerCli, namedRef, localManifestList, opts)
}
// Next try a remote manifest
ctx := context.Background()
registryClient := dockerCli.RegistryClient(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, err := registry.ParseRepositoryInfo(namedRef)
if err != nil {
return err
}
manifests := []manifestlist.ManifestDescriptor{}
// More than one response. This is a manifest list.
for _, img := range list {
mfd, err := buildManifestDescriptor(targetRepo, img)
if err != nil {
return errors.Wrap(err, "failed to assemble ManifestDescriptor")
}
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
}