github.com/seashell-org/golang-migrate/v4@v4.15.3-0.20220722221203-6ab6c6c062d1/source/google_cloud_storage/storage.go (about)

     1  package googlecloudstorage
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net/url"
     7  	"os"
     8  	"path"
     9  	"strings"
    10  
    11  	"context"
    12  
    13  	"cloud.google.com/go/storage"
    14  	"github.com/seashell-org/golang-migrate/v4/source"
    15  	"google.golang.org/api/iterator"
    16  )
    17  
    18  func init() {
    19  	source.Register("gcs", &gcs{})
    20  }
    21  
    22  type gcs struct {
    23  	bucket     *storage.BucketHandle
    24  	prefix     string
    25  	migrations *source.Migrations
    26  }
    27  
    28  func (g *gcs) Open(folder string) (source.Driver, error) {
    29  	u, err := url.Parse(folder)
    30  	if err != nil {
    31  		return nil, err
    32  	}
    33  	client, err := storage.NewClient(context.Background())
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	driver := gcs{
    38  		bucket:     client.Bucket(u.Host),
    39  		prefix:     strings.Trim(u.Path, "/") + "/",
    40  		migrations: source.NewMigrations(),
    41  	}
    42  	err = driver.loadMigrations()
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	return &driver, nil
    47  }
    48  
    49  func (g *gcs) loadMigrations() error {
    50  	iter := g.bucket.Objects(context.Background(), &storage.Query{
    51  		Prefix:    g.prefix,
    52  		Delimiter: "/",
    53  	})
    54  	object, err := iter.Next()
    55  	for ; err == nil; object, err = iter.Next() {
    56  		_, fileName := path.Split(object.Name)
    57  		m, parseErr := source.DefaultParse(fileName)
    58  		if parseErr != nil {
    59  			continue
    60  		}
    61  		if !g.migrations.Append(m) {
    62  			return fmt.Errorf("unable to parse file %v", object.Name)
    63  		}
    64  	}
    65  	if err != iterator.Done {
    66  		return err
    67  	}
    68  	return nil
    69  }
    70  
    71  func (g *gcs) Close() error {
    72  	return nil
    73  }
    74  
    75  func (g *gcs) First() (uint, error) {
    76  	v, ok := g.migrations.First()
    77  	if !ok {
    78  		return 0, os.ErrNotExist
    79  	}
    80  	return v, nil
    81  }
    82  
    83  func (g *gcs) Prev(version uint) (uint, error) {
    84  	v, ok := g.migrations.Prev(version)
    85  	if !ok {
    86  		return 0, os.ErrNotExist
    87  	}
    88  	return v, nil
    89  }
    90  
    91  func (g *gcs) Next(version uint) (uint, error) {
    92  	v, ok := g.migrations.Next(version)
    93  	if !ok {
    94  		return 0, os.ErrNotExist
    95  	}
    96  	return v, nil
    97  }
    98  
    99  func (g *gcs) ReadUp(version uint) (io.ReadCloser, string, error) {
   100  	if m, ok := g.migrations.Up(version); ok {
   101  		return g.open(m)
   102  	}
   103  	return nil, "", os.ErrNotExist
   104  }
   105  
   106  func (g *gcs) ReadDown(version uint) (io.ReadCloser, string, error) {
   107  	if m, ok := g.migrations.Down(version); ok {
   108  		return g.open(m)
   109  	}
   110  	return nil, "", os.ErrNotExist
   111  }
   112  
   113  func (g *gcs) open(m *source.Migration) (io.ReadCloser, string, error) {
   114  	objectPath := path.Join(g.prefix, m.Raw)
   115  	reader, err := g.bucket.Object(objectPath).NewReader(context.Background())
   116  	if err != nil {
   117  		return nil, "", err
   118  	}
   119  	return reader, m.Identifier, nil
   120  }