forked from gobuffalo/pop
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfile_migrator.go
133 lines (119 loc) · 2.92 KB
/
file_migrator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package pop
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"text/template"
"github.com/gobuffalo/fizz"
"github.com/gobuffalo/pop/fix"
"github.com/pkg/errors"
)
// FileMigrator is a migrator for SQL and Fizz
// files on disk at a specified path.
type FileMigrator struct {
Migrator
Path string
}
// NewFileMigrator for a path and a Connection
func NewFileMigrator(path string, c *Connection) (FileMigrator, error) {
fm := FileMigrator{
Migrator: NewMigrator(c),
Path: path,
}
fm.SchemaPath = path
err := fm.findMigrations()
if err != nil {
return fm, errors.WithStack(err)
}
return fm, nil
}
func (fm *FileMigrator) findMigrations() error {
dir := fm.Path
if fi, err := os.Stat(dir); err != nil || !fi.IsDir() {
// directory doesn't exist
return nil
}
filepath.Walk(dir, func(p string, info os.FileInfo, err error) error {
if !info.IsDir() {
matches := mrx.FindAllStringSubmatch(info.Name(), -1)
if len(matches) == 0 {
return nil
}
m := matches[0]
var dbType string
if m[3] == "" {
dbType = "all"
} else {
dbType = m[3][1:]
if !DialectSupported(dbType) {
return fmt.Errorf("unsupported dialect %s", dbType)
}
}
mf := Migration{
Path: p,
Version: m[1],
Name: m[2],
DBType: dbType,
Direction: m[4],
Type: m[5],
Runner: func(mf Migration, tx *Connection) error {
f, err := os.Open(p)
if err != nil {
return errors.WithStack(err)
}
content, err := migrationContent(mf, tx, f)
if err != nil {
return errors.Wrapf(err, "error processing %s", mf.Path)
}
if content == "" {
return nil
}
err = tx.RawQuery(content).Exec()
if err != nil {
return errors.Wrapf(err, "error executing %s, sql: %s", mf.Path, content)
}
return nil
},
}
fm.Migrations[mf.Direction] = append(fm.Migrations[mf.Direction], mf)
}
return nil
})
return nil
}
func migrationContent(mf Migration, c *Connection, r io.Reader) (string, error) {
b, err := ioutil.ReadAll(r)
if err != nil {
return "", nil
}
content := string(b)
if mf.Type == "fizz" {
// test for && fix anko migrations
fixed, err := fix.Anko(content)
if err != nil {
return "", errors.Wrapf(err, "could not fizz the migration %s", mf.Path)
}
if strings.TrimSpace(fixed) != strings.TrimSpace(content) {
fmt.Printf("[WARN] %s uses an old fizz syntax. please use\n%s\n", mf.Path, fixed)
}
content = fixed
}
t := template.Must(template.New("sql").Parse(content))
var bb bytes.Buffer
err = t.Execute(&bb, c.Dialect.Details())
if err != nil {
return "", errors.Wrapf(err, "could not execute migration template %s", mf.Path)
}
content = bb.String()
if mf.Type == "fizz" {
content, err = fizz.AString(content, c.Dialect.FizzTranslator())
if err != nil {
return "", errors.Wrapf(err, "could not fizz the migration %s", mf.Path)
}
}
return content, nil
}