github.com/opencontainers/umoci@v0.4.8-0.20240508124516-656e4836fb0d/cmd/umoci/stat.go (about) 1 /* 2 * umoci: Umoci Modifies Open Containers' Images 3 * Copyright (C) 2016-2020 SUSE LLC 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package main 19 20 import ( 21 "context" 22 "encoding/json" 23 "fmt" 24 "os" 25 26 ispec "github.com/opencontainers/image-spec/specs-go/v1" 27 "github.com/opencontainers/umoci" 28 "github.com/opencontainers/umoci/oci/cas/dir" 29 "github.com/opencontainers/umoci/oci/casext" 30 "github.com/pkg/errors" 31 "github.com/urfave/cli" 32 ) 33 34 var statCommand = cli.Command{ 35 Name: "stat", 36 Usage: "displays status information of an image manifest", 37 ArgsUsage: `--image <image-path>[:<tag>] 38 39 Where "<image-path>" is the path to the OCI image, and "<tag>" is the name of 40 the tagged image to stat. 41 42 WARNING: Do not depend on the output of this tool unless you're using --json. 43 The intention of the default formatting of this tool is that it is easy for 44 humans to read, and might change in future versions.`, 45 46 // stat gives information about a manifest. 47 Category: "image", 48 49 Before: func(ctx *cli.Context) error { 50 if ctx.NArg() != 0 { 51 return errors.Errorf("invalid number of positional arguments: expected none") 52 } 53 return nil 54 }, 55 56 Flags: []cli.Flag{ 57 cli.BoolFlag{ 58 Name: "json", 59 Usage: "output the stat information as a JSON encoded blob", 60 }, 61 }, 62 63 Action: stat, 64 } 65 66 func stat(ctx *cli.Context) error { 67 imagePath := ctx.App.Metadata["--image-path"].(string) 68 tagName := ctx.App.Metadata["--image-tag"].(string) 69 70 // Get a reference to the CAS. 71 engine, err := dir.Open(imagePath) 72 if err != nil { 73 return errors.Wrap(err, "open CAS") 74 } 75 engineExt := casext.NewEngine(engine) 76 defer engine.Close() 77 78 manifestDescriptorPaths, err := engineExt.ResolveReference(context.Background(), tagName) 79 if err != nil { 80 return errors.Wrap(err, "get descriptor") 81 } 82 if len(manifestDescriptorPaths) == 0 { 83 return errors.Errorf("tag not found: %s", tagName) 84 } 85 if len(manifestDescriptorPaths) != 1 { 86 // TODO: Handle this more nicely. 87 return errors.Errorf("tag is ambiguous: %s", tagName) 88 } 89 manifestDescriptor := manifestDescriptorPaths[0].Descriptor() 90 91 // FIXME: Implement support for manifest lists. 92 if manifestDescriptor.MediaType != ispec.MediaTypeImageManifest { 93 return errors.Wrap(fmt.Errorf("descriptor does not point to ispec.MediaTypeImageManifest: not implemented: %s", manifestDescriptor.MediaType), "invalid saved from descriptor") 94 } 95 96 // Get stat information. 97 ms, err := umoci.Stat(context.Background(), engineExt, manifestDescriptor) 98 if err != nil { 99 return errors.Wrap(err, "stat") 100 } 101 102 // Output the stat information. 103 if ctx.Bool("json") { 104 // Use JSON. 105 if err := json.NewEncoder(os.Stdout).Encode(ms); err != nil { 106 return errors.Wrap(err, "encoding stat") 107 } 108 } else { 109 if err := ms.Format(os.Stdout); err != nil { 110 return errors.Wrap(err, "format stat") 111 } 112 } 113 114 return nil 115 }