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 }