Files
zeekayandHanzo Dev 85d7501b1f Build on Go 1.27
go fix applied the modernizers. One rewrite it got wrong is corrected here: a
reverse loop over runes became a range over slices.Backward that bound the index
and the value to the SAME name, which does not compile and would have compared a
rune to an index if it had. The value gets its own name.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-17 06:18:28 -07:00

153 lines
2.9 KiB
Go

package awss3
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"
"github.com/golang-migrate/migrate/v4/source"
)
func init() {
source.Register("s3", &s3Driver{})
}
type s3Driver struct {
s3client s3iface.S3API
config *Config
migrations *source.Migrations
}
type Config struct {
Bucket string
Prefix string
}
func (s *s3Driver) Open(folder string) (source.Driver, error) {
config, err := parseURI(folder)
if err != nil {
return nil, err
}
sess, err := session.NewSession()
if err != nil {
return nil, err
}
return WithInstance(s3.New(sess), config)
}
func WithInstance(s3client s3iface.S3API, config *Config) (source.Driver, error) {
driver := &s3Driver{
config: config,
s3client: s3client,
migrations: source.NewMigrations(),
}
if err := driver.loadMigrations(); err != nil {
return nil, err
}
return driver, nil
}
func parseURI(uri string) (*Config, error) {
u, err := url.Parse(uri)
if err != nil {
return nil, err
}
prefix := strings.Trim(u.Path, "/")
if prefix != "" {
prefix += "/"
}
return &Config{
Bucket: u.Host,
Prefix: prefix,
}, nil
}
func (s *s3Driver) loadMigrations() error {
output, err := s.s3client.ListObjects(&s3.ListObjectsInput{
Bucket: new(s.config.Bucket),
Prefix: new(s.config.Prefix),
Delimiter: new("/"),
})
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.config.Prefix, m.Raw)
object, err := s.s3client.GetObject(&s3.GetObjectInput{
Bucket: new(s.config.Bucket),
Key: new(key),
})
if err != nil {
return nil, "", err
}
return object.Body, m.Identifier, nil
}