cmd/acr/manifest.go (119 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. package main import ( "context" "fmt" "github.com/Azure/acr-cli/internal/api" "github.com/pkg/errors" "github.com/spf13/cobra" ) const ( newManifestCmdLongMessage = `acr manifest: list manifests and delete them individually.` newManifestListCmdLongMessage = `acr manifest list: outputs all the manifests that are inside a given repository` newManifestDeleteCmdLongMessage = `acr manifest delete: delete a set of manifests inside the specified repository` ) // Besides the registry name and authentication information only the repository is needed. type manifestParameters struct { *rootParameters repoName string } // The manifest command can be used to either list manifests or delete manifests inside a repository. // that can be done with the manifest list and manifest delete commands respectively. func newManifestCmd(rootParams *rootParameters) *cobra.Command { manifestParams := manifestParameters{rootParameters: rootParams} cmd := &cobra.Command{ Use: "manifest", Short: "Manage manifests inside a repository", Long: newManifestCmdLongMessage, RunE: func(cmd *cobra.Command, _ []string) error { cmd.Help() return nil }, } listManifestCmd := newManifestListCmd(&manifestParams) deleteManifestCmd := newManifestDeleteCmd(&manifestParams) cmd.AddCommand( listManifestCmd, deleteManifestCmd, ) cmd.PersistentFlags().StringVar(&manifestParams.repoName, "repository", "", "The repository name") // Since the repository will be needed in either subcommand it is marked as a required flag cmd.MarkPersistentFlagRequired("repository") return cmd } // newManifestListCmd creates the manifest list command, it does not need any aditional parameters. // The registry interaction is done through the listManifests method func newManifestListCmd(manifestParams *manifestParameters) *cobra.Command { cmd := &cobra.Command{ Use: "list", Short: "List manifests from a repository", Long: newManifestListCmdLongMessage, RunE: func(_ *cobra.Command, _ []string) error { registryName, err := manifestParams.GetRegistryName() if err != nil { return err } loginURL := api.LoginURL(registryName) // An acrClient is created to make the http requests to the registry. acrClient, err := api.GetAcrCLIClientWithAuth(loginURL, manifestParams.username, manifestParams.password, manifestParams.configs) if err != nil { return err } ctx := context.Background() err = listManifests(ctx, acrClient, loginURL, manifestParams.repoName) if err != nil { return err } return nil }, } return cmd } // listManifests will do the http requests and print the digest of all the manifest in the selected repository. func listManifests(ctx context.Context, acrClient api.AcrCLIClientInterface, loginURL string, repoName string) error { lastManifestDigest := "" resultManifests, err := acrClient.GetAcrManifests(ctx, repoName, "", lastManifestDigest) if err != nil { return errors.Wrap(err, "failed to list manifests") } fmt.Printf("Listing manifests for the %q repository:\n", repoName) // A for loop is used because the GetAcrManifests method returns by default only 100 manifests and their attributes. for resultManifests != nil && resultManifests.ManifestsAttributes != nil { manifests := *resultManifests.ManifestsAttributes for _, manifest := range manifests { manifestDigest := *manifest.Digest fmt.Printf("%s/%s@%s\n", loginURL, repoName, manifestDigest) } // Since the GetAcrManifests supports pagination when supplied with the last digest that was returned the last manifest // digest is saved, the manifest array contains at least one element because if it was empty the API would return // a nil pointer instead of a pointer to a length 0 array. lastManifestDigest = *manifests[len(manifests)-1].Digest resultManifests, err = acrClient.GetAcrManifests(ctx, repoName, "", lastManifestDigest) if err != nil { return errors.Wrap(err, "failed to list manifests") } } return nil } // newManifestDeleteCmd defines the manifest delete subcommand, it receives as an argument an array of manifest digests. // The delete functionality of this command is implemented in the deleteManifests function. func newManifestDeleteCmd(manifestParams *manifestParameters) *cobra.Command { cmd := &cobra.Command{ Use: "delete", Short: "Delete manifest from a repository", Long: newManifestDeleteCmdLongMessage, RunE: func(_ *cobra.Command, args []string) error { registryName, err := manifestParams.GetRegistryName() if err != nil { return err } loginURL := api.LoginURL(registryName) acrClient, err := api.GetAcrCLIClientWithAuth(loginURL, manifestParams.username, manifestParams.password, manifestParams.configs) if err != nil { return err } ctx := context.Background() err = deleteManifests(ctx, acrClient, loginURL, manifestParams.repoName, args) if err != nil { return err } return nil }, } return cmd } // deleteManifests receives an array of manifests digest and deletes them using the supplied acrClient. func deleteManifests(ctx context.Context, acrClient api.AcrCLIClientInterface, loginURL string, repoName string, args []string) error { for i := 0; i < len(args); i++ { _, err := acrClient.DeleteManifest(ctx, repoName, args[i]) if err != nil { // If there is an error (this includes not found and not allowed operations) the deletion of the images is stopped and an error is returned. return errors.Wrap(err, "failed to delete manifests") } fmt.Printf("%s/%s@%s\n", loginURL, repoName, args[i]) } return nil }