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 }