github.com/supabase/cli@v1.168.1/internal/storage/mv/mv.go (about)

     1  package mv
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"path"
     8  	"strings"
     9  
    10  	"github.com/go-errors/errors"
    11  	"github.com/spf13/afero"
    12  	"github.com/supabase/cli/internal/storage/client"
    13  	"github.com/supabase/cli/internal/storage/ls"
    14  	"github.com/supabase/cli/internal/utils/flags"
    15  	"github.com/supabase/cli/pkg/storage"
    16  )
    17  
    18  var (
    19  	errUnsupportedMove = errors.New("Moving between buckets is unsupported")
    20  	errMissingPath     = errors.New("You must specify an object path")
    21  )
    22  
    23  func Run(ctx context.Context, src, dst string, recursive bool, fsys afero.Fs) error {
    24  	srcParsed, err := client.ParseStorageURL(src)
    25  	if err != nil {
    26  		return err
    27  	}
    28  	dstParsed, err := client.ParseStorageURL(dst)
    29  	if err != nil {
    30  		return err
    31  	}
    32  	srcBucket, srcPrefix := client.SplitBucketPrefix(srcParsed)
    33  	dstBucket, dstPrefix := client.SplitBucketPrefix(dstParsed)
    34  	if len(srcPrefix) == 0 && len(dstPrefix) == 0 {
    35  		return errors.New(errMissingPath)
    36  	}
    37  	if srcBucket != dstBucket {
    38  		return errors.New(errUnsupportedMove)
    39  	}
    40  	api, err := client.NewStorageAPI(ctx, flags.ProjectRef)
    41  	if err != nil {
    42  		return err
    43  	}
    44  	fmt.Fprintln(os.Stderr, "Moving object:", srcParsed, "=>", dstParsed)
    45  	data, err := api.MoveObject(ctx, srcBucket, srcPrefix, dstPrefix)
    46  	if err == nil {
    47  		fmt.Fprintln(os.Stderr, data.Message)
    48  	} else if strings.Contains(err.Error(), `"error":"not_found"`) && recursive {
    49  		return MoveStorageObjectAll(ctx, api, srcParsed+"/", dstParsed)
    50  	}
    51  	return err
    52  }
    53  
    54  // Expects srcPath to be terminated by "/"
    55  func MoveStorageObjectAll(ctx context.Context, api storage.StorageAPI, srcPath, dstPath string) error {
    56  	_, dstPrefix := client.SplitBucketPrefix(dstPath)
    57  	// Cannot iterate because pagination result may be updated during move
    58  	count := 0
    59  	queue := make([]string, 0)
    60  	queue = append(queue, srcPath)
    61  	for len(queue) > 0 {
    62  		dirPath := queue[len(queue)-1]
    63  		queue = queue[:len(queue)-1]
    64  		paths, err := ls.ListStoragePaths(ctx, api, dirPath)
    65  		if err != nil {
    66  			return err
    67  		}
    68  		for _, objectName := range paths {
    69  			objectPath := dirPath + objectName
    70  			if strings.HasSuffix(objectName, "/") {
    71  				queue = append(queue, objectPath)
    72  				continue
    73  			}
    74  			count++
    75  			relPath := strings.TrimPrefix(objectPath, srcPath)
    76  			srcBucket, srcPrefix := client.SplitBucketPrefix(objectPath)
    77  			absPath := path.Join(dstPrefix, relPath)
    78  			fmt.Fprintln(os.Stderr, "Moving object:", objectPath, "=>", path.Join(dstPath, relPath))
    79  			if _, err := api.MoveObject(ctx, srcBucket, srcPrefix, absPath); err != nil {
    80  				return err
    81  			}
    82  		}
    83  	}
    84  	if count == 0 {
    85  		return errors.New("Object not found: " + srcPath)
    86  	}
    87  	return nil
    88  }