testSuite/cmd/list.go (100 lines of code) (raw):
package cmd
import (
"context"
"fmt"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container"
"net/url"
"os"
"strings"
"github.com/Azure/azure-storage-azcopy/v10/ste"
"github.com/spf13/cobra"
)
// initializes the clean command, its aliases and description.
func init() {
resourceUrl := ""
numberOfResource := int64(0)
cleanCmd := &cobra.Command{
Use: "list",
Aliases: []string{"list"},
Short: "lists list everything inside the container / virtual directory",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) > 1 {
return fmt.Errorf("invalid arguments for clean command")
}
resourceUrl = args[0]
return nil
},
Run: func(cmd *cobra.Command, args []string) {
listContainer(resourceUrl, numberOfResource)
},
}
rootCmd.AddCommand(cleanCmd)
cleanCmd.PersistentFlags().Int64Var(&numberOfResource, "resource-num", 0, "number of resource inside the container")
}
func getContainerURLFromString(url url.URL) string {
containerName := strings.SplitAfterN(url.Path[1:], "/", 2)[0]
url.Path = "/" + containerName
return url.String()
}
// checks if a given url points to a container, as opposed to a blob or prefix match
func urlIsContainerOrShare(url *url.URL) bool {
// if the path contains more than one "/", then it means it points to a blob, and not a container
numOfSlashes := strings.Count(url.Path[1:], "/")
if numOfSlashes == 0 {
return true
} else if numOfSlashes == 1 && url.Path[len(url.Path)-1:] == "/" { // this checks if container_name/ was given
return true
}
return false
}
func getBlobNameFromURL(path string) string {
// return everything after the second /
return strings.SplitAfterN(path[1:], "/", 2)[1]
}
func listContainer(resourceUrl string, numberOfResources int64) {
// attempt to parse the source url
sourceUrl, err := url.Parse(resourceUrl)
if err != nil {
fmt.Println("cannot parse source URL")
os.Exit(1)
}
// get the container url to be used for listing
literalContainerUrl := getContainerURLFromString(*sourceUrl)
cc, err := container.NewClientWithNoCredential(literalContainerUrl, &container.ClientOptions{ClientOptions: azcore.ClientOptions{
Retry: policy.RetryOptions{
MaxRetries: ste.UploadMaxTries,
TryTimeout: ste.UploadTryTimeout,
RetryDelay: ste.UploadRetryDelay,
MaxRetryDelay: ste.UploadMaxRetryDelay,
},
}})
if err != nil {
fmt.Printf("cannot create container client. Failed with error %s\n", err.Error())
os.Exit(1)
}
// get the search prefix to query the service
searchPrefix := ""
// if the source is container url, then searchPrefix is empty
if !urlIsContainerOrShare(sourceUrl) {
searchPrefix = getBlobNameFromURL(sourceUrl.Path)
}
if len(searchPrefix) > 0 {
// if the user did not specify / at the end of the virtual directory, add it before doing the prefix search
if strings.LastIndex(searchPrefix, "/") != len(searchPrefix)-1 {
searchPrefix += "/"
}
}
numberOfBlobs := int64(0)
// perform a list blob
// look for all blobs that start with the prefix
pager := cc.NewListBlobsFlatPager(&container.ListBlobsFlatOptions{Prefix: &searchPrefix})
for pager.More() {
listBlob, err := pager.NextPage(context.TODO())
if err != nil {
fmt.Printf("cannot list blobs for download. Failed with error %s\n", err.Error())
os.Exit(1)
}
// Process the blobs returned in this result segment (if the segment is empty, the loop body won't execute)
for _, blobInfo := range listBlob.Segment.BlobItems {
blobName := *blobInfo.Name
if len(searchPrefix) > 0 {
// strip away search prefix from the blob name.
blobName = strings.Replace(blobName, searchPrefix, "", 1) //nolint:ineffassign,staticcheck
}
numberOfBlobs++
}
}
if numberOfBlobs != numberOfResources {
fmt.Printf("expected number of blobs / file %d inside the resource does not match the actual %d\n", numberOfResources, numberOfBlobs)
os.Exit(1)
}
}