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  }