supabase-cli/pkg/storage/batch.go

106 lines
2.7 KiB
Go

package storage
import (
"context"
"fmt"
"io/fs"
"os"
"path"
"path/filepath"
"github.com/go-errors/errors"
"github.com/supabase/cli/pkg/config"
"github.com/supabase/cli/pkg/queue"
)
func (s *StorageAPI) UpsertBuckets(ctx context.Context, bucketConfig config.BucketConfig, filter ...func(string) bool) error {
buckets, err := s.ListBuckets(ctx)
if err != nil {
return err
}
exists := make(map[string]string, len(buckets))
for _, b := range buckets {
exists[b.Name] = b.Id
}
for name, bucket := range bucketConfig {
// Update bucket properties if already exists
if bucketId, ok := exists[name]; ok {
for _, keep := range filter {
if !keep(bucketId) {
continue
}
}
fmt.Fprintln(os.Stderr, "Updating Storage bucket:", bucketId)
body := UpdateBucketRequest{
Id: bucketId,
Public: bucket.Public,
FileSizeLimit: int64(bucket.FileSizeLimit),
AllowedMimeTypes: bucket.AllowedMimeTypes,
}
if _, err := s.UpdateBucket(ctx, body); err != nil {
return err
}
} else {
fmt.Fprintln(os.Stderr, "Creating Storage bucket:", name)
body := CreateBucketRequest{
Name: name,
Public: bucket.Public,
FileSizeLimit: int64(bucket.FileSizeLimit),
AllowedMimeTypes: bucket.AllowedMimeTypes,
}
if _, err := s.CreateBucket(ctx, body); err != nil {
return err
}
}
}
return nil
}
type UploadOptions struct {
MaxConcurrency uint
KeyPrefix string
}
func (s *StorageAPI) UpsertObjects(ctx context.Context, bucketConfig config.BucketConfig, fsys fs.FS, opts ...func(*UploadOptions)) error {
uo := UploadOptions{MaxConcurrency: 5}
for _, apply := range opts {
apply(&uo)
}
jq := queue.NewJobQueue(uo.MaxConcurrency)
for name, bucket := range bucketConfig {
localPath := bucket.ObjectsPath
if len(localPath) == 0 {
continue
}
upload := func(filePath string, info fs.DirEntry, err error) error {
if err != nil {
return errors.New(err)
}
if !info.Type().IsRegular() {
return nil
}
dstPath := uo.KeyPrefix
relPath, err := filepath.Rel(localPath, filePath)
if err != nil {
return errors.Errorf("failed to resolve relative path: %w", err)
} else if relPath == "." {
// Copying single file
dstPath = path.Join(name, info.Name())
} else {
dstPath = path.Join(name, filepath.ToSlash(relPath))
}
fmt.Fprintln(os.Stderr, "Uploading:", filePath, "=>", dstPath)
job := func() error {
return s.UploadObject(ctx, dstPath, filePath, fsys, func(fo *FileOptions) {
fo.Overwrite = true
})
}
return jq.Put(job)
}
if err := fs.WalkDir(fsys, localPath, upload); err != nil {
return err
}
}
return jq.Collect()
}