144 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
| package artifact
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 
 | |
| 	"github.com/containers/common/pkg/completion"
 | |
| 	"github.com/containers/common/pkg/report"
 | |
| 	"github.com/containers/image/v5/docker/reference"
 | |
| 	"github.com/containers/podman/v5/cmd/podman/common"
 | |
| 	"github.com/containers/podman/v5/cmd/podman/registry"
 | |
| 	"github.com/containers/podman/v5/cmd/podman/validate"
 | |
| 	"github.com/containers/podman/v5/pkg/domain/entities"
 | |
| 	"github.com/docker/go-units"
 | |
| 	"github.com/spf13/cobra"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	listCmd = &cobra.Command{
 | |
| 		Use:               "ls [options]",
 | |
| 		Aliases:           []string{"list"},
 | |
| 		Short:             "List OCI artifacts",
 | |
| 		Long:              "List OCI artifacts in local store",
 | |
| 		RunE:              list,
 | |
| 		Args:              validate.NoArgs,
 | |
| 		ValidArgsFunction: completion.AutocompleteNone,
 | |
| 		Example:           `podman artifact ls`,
 | |
| 		Annotations:       map[string]string{registry.EngineMode: registry.ABIMode},
 | |
| 	}
 | |
| 	listFlag = listFlagType{}
 | |
| )
 | |
| 
 | |
| type listFlagType struct {
 | |
| 	format    string
 | |
| 	noHeading bool
 | |
| 	noTrunc   bool
 | |
| }
 | |
| 
 | |
| type artifactListOutput struct {
 | |
| 	Digest     string
 | |
| 	Repository string
 | |
| 	Size       string
 | |
| 	Tag        string
 | |
| }
 | |
| 
 | |
| var (
 | |
| 	defaultArtifactListOutputFormat = "{{range .}}{{.Repository}}\t{{.Tag}}\t{{.Digest}}\t{{.Size}}\n{{end -}}"
 | |
| )
 | |
| 
 | |
| func init() {
 | |
| 	registry.Commands = append(registry.Commands, registry.CliCommand{
 | |
| 		Command: listCmd,
 | |
| 		Parent:  artifactCmd,
 | |
| 	})
 | |
| 	flags := listCmd.Flags()
 | |
| 	formatFlagName := "format"
 | |
| 	flags.StringVar(&listFlag.format, formatFlagName, defaultArtifactListOutputFormat, "Format volume output using JSON or a Go template")
 | |
| 	_ = listCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&artifactListOutput{}))
 | |
| 	flags.BoolVarP(&listFlag.noHeading, "noheading", "n", false, "Do not print column headings")
 | |
| 	flags.BoolVar(&listFlag.noTrunc, "no-trunc", false, "Do not truncate output")
 | |
| }
 | |
| 
 | |
| func list(cmd *cobra.Command, _ []string) error {
 | |
| 	reports, err := registry.ImageEngine().ArtifactList(registry.Context(), entities.ArtifactListOptions{})
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return outputTemplate(cmd, reports)
 | |
| }
 | |
| 
 | |
| func outputTemplate(cmd *cobra.Command, lrs []*entities.ArtifactListReport) error {
 | |
| 	var err error
 | |
| 	artifacts := make([]artifactListOutput, 0)
 | |
| 	for _, lr := range lrs {
 | |
| 		var (
 | |
| 			tag string
 | |
| 		)
 | |
| 		artifactName, err := lr.Artifact.GetName()
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		repo, err := reference.Parse(artifactName)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		named, ok := repo.(reference.Named)
 | |
| 		if !ok {
 | |
| 			return fmt.Errorf("%q is an invalid artifact name", artifactName)
 | |
| 		}
 | |
| 		if tagged, ok := named.(reference.Tagged); ok {
 | |
| 			tag = tagged.Tag()
 | |
| 		}
 | |
| 
 | |
| 		// Note: Right now we only support things that are single manifests
 | |
| 		// We should certainly expand this support for things like arch, etc
 | |
| 		// as we move on
 | |
| 		artifactDigest, err := lr.Artifact.GetDigest()
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		artifactHash := artifactDigest.Encoded()[0:12]
 | |
| 		// If the user does not want truncated hashes
 | |
| 		if listFlag.noTrunc {
 | |
| 			artifactHash = artifactDigest.Encoded()
 | |
| 		}
 | |
| 
 | |
| 		artifacts = append(artifacts, artifactListOutput{
 | |
| 			Digest:     artifactHash,
 | |
| 			Repository: named.Name(),
 | |
| 			Size:       units.HumanSize(float64(lr.Artifact.TotalSizeBytes())),
 | |
| 			Tag:        tag,
 | |
| 		})
 | |
| 	}
 | |
| 
 | |
| 	headers := report.Headers(artifactListOutput{}, map[string]string{
 | |
| 		"REPOSITORY": "REPOSITORY",
 | |
| 		"Tag":        "TAG",
 | |
| 		"Size":       "SIZE",
 | |
| 		"Digest":     "DIGEST",
 | |
| 	})
 | |
| 
 | |
| 	rpt := report.New(os.Stdout, cmd.Name())
 | |
| 	defer rpt.Flush()
 | |
| 
 | |
| 	switch {
 | |
| 	case cmd.Flag("format").Changed:
 | |
| 		rpt, err = rpt.Parse(report.OriginUser, listFlag.format)
 | |
| 	default:
 | |
| 		rpt, err = rpt.Parse(report.OriginPodman, listFlag.format)
 | |
| 	}
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if rpt.RenderHeaders && !listFlag.noHeading {
 | |
| 		if err := rpt.Execute(headers); err != nil {
 | |
| 			return fmt.Errorf("failed to write report column headers: %w", err)
 | |
| 		}
 | |
| 	}
 | |
| 	return rpt.Execute(artifacts)
 | |
| }
 |