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