2017-02-09 00:17:04 +00:00
|
|
|
package awss3
|
2017-05-14 18:31:40 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
|
|
"github.com/aws/aws-sdk-go/aws/session"
|
|
|
|
"github.com/aws/aws-sdk-go/service/s3"
|
|
|
|
"github.com/aws/aws-sdk-go/service/s3/s3iface"
|
2018-10-10 22:11:48 +00:00
|
|
|
"github.com/golang-migrate/migrate/v4/source"
|
2017-05-14 18:31:40 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
source.Register("s3", &s3Driver{})
|
|
|
|
}
|
|
|
|
|
|
|
|
type s3Driver struct {
|
|
|
|
s3client s3iface.S3API
|
|
|
|
bucket string
|
|
|
|
prefix string
|
|
|
|
migrations *source.Migrations
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *s3Driver) Open(folder string) (source.Driver, error) {
|
|
|
|
u, err := url.Parse(folder)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
sess, err := session.NewSession()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
driver := s3Driver{
|
|
|
|
bucket: u.Host,
|
|
|
|
prefix: strings.Trim(u.Path, "/") + "/",
|
|
|
|
s3client: s3.New(sess),
|
|
|
|
migrations: source.NewMigrations(),
|
|
|
|
}
|
|
|
|
err = driver.loadMigrations()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &driver, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *s3Driver) loadMigrations() error {
|
|
|
|
output, err := s.s3client.ListObjects(&s3.ListObjectsInput{
|
|
|
|
Bucket: aws.String(s.bucket),
|
|
|
|
Prefix: aws.String(s.prefix),
|
|
|
|
Delimiter: aws.String("/"),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for _, object := range output.Contents {
|
|
|
|
_, fileName := path.Split(aws.StringValue(object.Key))
|
|
|
|
m, err := source.DefaultParse(fileName)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if !s.migrations.Append(m) {
|
|
|
|
return fmt.Errorf("unable to parse file %v", aws.StringValue(object.Key))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *s3Driver) Close() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *s3Driver) First() (uint, error) {
|
|
|
|
v, ok := s.migrations.First()
|
|
|
|
if !ok {
|
|
|
|
return 0, os.ErrNotExist
|
|
|
|
}
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *s3Driver) Prev(version uint) (uint, error) {
|
|
|
|
v, ok := s.migrations.Prev(version)
|
|
|
|
if !ok {
|
|
|
|
return 0, os.ErrNotExist
|
|
|
|
}
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *s3Driver) Next(version uint) (uint, error) {
|
|
|
|
v, ok := s.migrations.Next(version)
|
|
|
|
if !ok {
|
|
|
|
return 0, os.ErrNotExist
|
|
|
|
}
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *s3Driver) ReadUp(version uint) (io.ReadCloser, string, error) {
|
|
|
|
if m, ok := s.migrations.Up(version); ok {
|
|
|
|
return s.open(m)
|
|
|
|
}
|
|
|
|
return nil, "", os.ErrNotExist
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *s3Driver) ReadDown(version uint) (io.ReadCloser, string, error) {
|
|
|
|
if m, ok := s.migrations.Down(version); ok {
|
|
|
|
return s.open(m)
|
|
|
|
}
|
|
|
|
return nil, "", os.ErrNotExist
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *s3Driver) open(m *source.Migration) (io.ReadCloser, string, error) {
|
|
|
|
key := path.Join(s.prefix, m.Raw)
|
|
|
|
object, err := s.s3client.GetObject(&s3.GetObjectInput{
|
|
|
|
Bucket: aws.String(s.bucket),
|
|
|
|
Key: aws.String(key),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, "", err
|
|
|
|
}
|
|
|
|
return object.Body, m.Identifier, nil
|
|
|
|
}
|