github.com/dannyzhou2015/migrate/v4@v4.15.2/source/aws_s3/s3.go (about)

     1  package awss3
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net/url"
     7  	"os"
     8  	"path"
     9  	"strings"
    10  
    11  	"github.com/aws/aws-sdk-go/aws"
    12  	"github.com/aws/aws-sdk-go/aws/session"
    13  	"github.com/aws/aws-sdk-go/service/s3"
    14  	"github.com/aws/aws-sdk-go/service/s3/s3iface"
    15  	"github.com/dannyzhou2015/migrate/v4/source"
    16  )
    17  
    18  func init() {
    19  	source.Register("s3", &s3Driver{})
    20  }
    21  
    22  type s3Driver struct {
    23  	s3client   s3iface.S3API
    24  	config     *Config
    25  	migrations *source.Migrations
    26  }
    27  
    28  type Config struct {
    29  	Bucket string
    30  	Prefix string
    31  }
    32  
    33  func (s *s3Driver) Open(folder string) (source.Driver, error) {
    34  	config, err := parseURI(folder)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	sess, err := session.NewSession()
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	return WithInstance(s3.New(sess), config)
    45  }
    46  
    47  func WithInstance(s3client s3iface.S3API, config *Config) (source.Driver, error) {
    48  	driver := &s3Driver{
    49  		config:     config,
    50  		s3client:   s3client,
    51  		migrations: source.NewMigrations(),
    52  	}
    53  
    54  	if err := driver.loadMigrations(); err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	return driver, nil
    59  }
    60  
    61  func parseURI(uri string) (*Config, error) {
    62  	u, err := url.Parse(uri)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	prefix := strings.Trim(u.Path, "/")
    68  	if prefix != "" {
    69  		prefix += "/"
    70  	}
    71  
    72  	return &Config{
    73  		Bucket: u.Host,
    74  		Prefix: prefix,
    75  	}, nil
    76  }
    77  
    78  func (s *s3Driver) loadMigrations() error {
    79  	output, err := s.s3client.ListObjects(&s3.ListObjectsInput{
    80  		Bucket:    aws.String(s.config.Bucket),
    81  		Prefix:    aws.String(s.config.Prefix),
    82  		Delimiter: aws.String("/"),
    83  	})
    84  	if err != nil {
    85  		return err
    86  	}
    87  	for _, object := range output.Contents {
    88  		_, fileName := path.Split(aws.StringValue(object.Key))
    89  		m, err := source.DefaultParse(fileName)
    90  		if err != nil {
    91  			continue
    92  		}
    93  		if !s.migrations.Append(m) {
    94  			return fmt.Errorf("unable to parse file %v", aws.StringValue(object.Key))
    95  		}
    96  	}
    97  	return nil
    98  }
    99  
   100  func (s *s3Driver) Close() error {
   101  	return nil
   102  }
   103  
   104  func (s *s3Driver) First() (uint, error) {
   105  	v, ok := s.migrations.First()
   106  	if !ok {
   107  		return 0, os.ErrNotExist
   108  	}
   109  	return v, nil
   110  }
   111  
   112  func (s *s3Driver) Prev(version uint) (uint, error) {
   113  	v, ok := s.migrations.Prev(version)
   114  	if !ok {
   115  		return 0, os.ErrNotExist
   116  	}
   117  	return v, nil
   118  }
   119  
   120  func (s *s3Driver) Next(version uint) (uint, error) {
   121  	v, ok := s.migrations.Next(version)
   122  	if !ok {
   123  		return 0, os.ErrNotExist
   124  	}
   125  	return v, nil
   126  }
   127  
   128  func (s *s3Driver) ReadUp(version uint) (io.ReadCloser, string, error) {
   129  	if m, ok := s.migrations.Up(version); ok {
   130  		return s.open(m)
   131  	}
   132  	return nil, "", os.ErrNotExist
   133  }
   134  
   135  func (s *s3Driver) ReadDown(version uint) (io.ReadCloser, string, error) {
   136  	if m, ok := s.migrations.Down(version); ok {
   137  		return s.open(m)
   138  	}
   139  	return nil, "", os.ErrNotExist
   140  }
   141  
   142  func (s *s3Driver) open(m *source.Migration) (io.ReadCloser, string, error) {
   143  	key := path.Join(s.config.Prefix, m.Raw)
   144  	object, err := s.s3client.GetObject(&s3.GetObjectInput{
   145  		Bucket: aws.String(s.config.Bucket),
   146  		Key:    aws.String(key),
   147  	})
   148  	if err != nil {
   149  		return nil, "", err
   150  	}
   151  	return object.Body, m.Identifier, nil
   152  }