mirror of https://github.com/status-im/migrate.git
update go-bindata with latest source.Migration helper
This commit is contained in:
parent
3889c93b63
commit
f7699f1dec
|
@ -45,7 +45,7 @@ is easy. Just implement the [source/driver interface](source/driver.go).
|
||||||
|
|
||||||
## CLI usage
|
## CLI usage
|
||||||
|
|
||||||
```bash
|
```
|
||||||
# dowload, build and install the CLI tool
|
# dowload, build and install the CLI tool
|
||||||
# -tags takes database and source drivers and will only build those
|
# -tags takes database and source drivers and will only build those
|
||||||
$ go get -u -tags 'postgres' -o migrate github.com/mattes/migrate/cli
|
$ go get -u -tags 'postgres' -o migrate github.com/mattes/migrate/cli
|
||||||
|
|
|
@ -33,8 +33,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Wrap assets into Resource
|
// wrap assets into Resource
|
||||||
resource := bindata.Resource(migrations.AssetNames(),
|
s := bindata.Resource(migrations.AssetNames(),
|
||||||
func(name string) ([]byte, error) {
|
func(name string) ([]byte, error) {
|
||||||
return migrations.Asset(name)
|
return migrations.Asset(name)
|
||||||
})
|
})
|
||||||
|
|
|
@ -6,9 +6,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/mattes/migrate/source"
|
"github.com/mattes/migrate/source"
|
||||||
)
|
)
|
||||||
|
@ -31,15 +28,10 @@ func init() {
|
||||||
source.Register("go-bindata", &Bindata{})
|
source.Register("go-bindata", &Bindata{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// filename example: `123_name.up.ext`
|
|
||||||
// filename example: `123_name.down.ext`
|
|
||||||
var filenameRegex = regexp.MustCompile(`^([0-9]+)_(.*)\.(` + string(down) + `|` + string(up) + `)\.(.*)$`)
|
|
||||||
|
|
||||||
type Bindata struct {
|
type Bindata struct {
|
||||||
path string
|
path string
|
||||||
filesIndex uintSlice
|
|
||||||
files map[uint]map[direction]file
|
|
||||||
assetSource *AssetSource
|
assetSource *AssetSource
|
||||||
|
migrations *source.Migrations
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bindata) Open(url string) (source.Driver, error) {
|
func (b *Bindata) Open(url string) (source.Driver, error) {
|
||||||
|
@ -59,35 +51,20 @@ func WithInstance(instance interface{}) (source.Driver, error) {
|
||||||
bn := &Bindata{
|
bn := &Bindata{
|
||||||
path: "<go-bindata>",
|
path: "<go-bindata>",
|
||||||
assetSource: as,
|
assetSource: as,
|
||||||
|
migrations: source.NewMigrations(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse file names and create internal data structure
|
|
||||||
bn.files = make(map[uint]map[direction]file)
|
|
||||||
for _, fi := range as.Names {
|
for _, fi := range as.Names {
|
||||||
pf, err := parseFilename(fi)
|
m, err := source.DefaultParse(fi)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue // ignore files that we can't parse
|
continue // ignore files that we can't parse
|
||||||
}
|
}
|
||||||
|
|
||||||
if bn.files[pf.version] == nil {
|
if !bn.migrations.Append(m) {
|
||||||
bn.files[pf.version] = make(map[direction]file)
|
return nil, fmt.Errorf("unable to parse file %v", fi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// reject duplicate versions
|
|
||||||
if dupf, dup := bn.files[pf.version][pf.direction]; dup {
|
|
||||||
return nil, fmt.Errorf("duplicate file: %v and %v", dupf.filename, fi)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bn.files[pf.version][pf.direction] = *pf
|
|
||||||
}
|
|
||||||
|
|
||||||
// create index and sort
|
|
||||||
bn.filesIndex = make(uintSlice, 0)
|
|
||||||
for version, _ := range bn.files {
|
|
||||||
bn.filesIndex = append(bn.filesIndex, version)
|
|
||||||
}
|
|
||||||
sort.Sort(bn.filesIndex)
|
|
||||||
|
|
||||||
return bn, nil
|
return bn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,113 +73,47 @@ func (b *Bindata) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bindata) First() (version uint, err error) {
|
func (b *Bindata) First() (version uint, err error) {
|
||||||
if len(b.filesIndex) == 0 {
|
if v, ok := b.migrations.First(); !ok {
|
||||||
return 0, &os.PathError{"first", b.path, os.ErrNotExist}
|
return 0, &os.PathError{"first", b.path, os.ErrNotExist}
|
||||||
|
} else {
|
||||||
|
return v, nil
|
||||||
}
|
}
|
||||||
return b.filesIndex[0], nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bindata) Prev(version uint) (prevVersion uint, err error) {
|
func (b *Bindata) Prev(version uint) (prevVersion uint, err error) {
|
||||||
pos := b.findPos(version)
|
if v, ok := b.migrations.Prev(version); !ok {
|
||||||
if pos >= 1 && len(b.filesIndex) > pos-1 {
|
|
||||||
return b.filesIndex[pos-1], nil
|
|
||||||
}
|
|
||||||
return 0, &os.PathError{fmt.Sprintf("prev for version %v", version), b.path, os.ErrNotExist}
|
return 0, &os.PathError{fmt.Sprintf("prev for version %v", version), b.path, os.ErrNotExist}
|
||||||
|
} else {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bindata) Next(version uint) (nextVersion uint, err error) {
|
func (b *Bindata) Next(version uint) (nextVersion uint, err error) {
|
||||||
pos := b.findPos(version)
|
if v, ok := b.migrations.Next(version); !ok {
|
||||||
if pos >= 0 && len(b.filesIndex) > pos+1 {
|
|
||||||
return b.filesIndex[pos+1], nil
|
|
||||||
}
|
|
||||||
return 0, &os.PathError{fmt.Sprintf("next for version %v", version), b.path, os.ErrNotExist}
|
return 0, &os.PathError{fmt.Sprintf("next for version %v", version), b.path, os.ErrNotExist}
|
||||||
|
} else {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bindata) ReadUp(version uint) (r io.ReadCloser, identifier string, err error) {
|
func (b *Bindata) ReadUp(version uint) (r io.ReadCloser, identifier string, err error) {
|
||||||
if _, ok := b.files[version]; ok {
|
if m, ok := b.migrations.Up(version); ok {
|
||||||
if upFile, ok := b.files[version][up]; ok {
|
body, err := b.assetSource.AssetFunc(m.Raw)
|
||||||
body, err := b.assetSource.AssetFunc(upFile.filename)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
return ioutil.NopCloser(bytes.NewReader(body)), upFile.name, nil
|
return ioutil.NopCloser(bytes.NewReader(body)), m.Identifier, nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil, "", &os.PathError{fmt.Sprintf("read version %v", version), b.path, os.ErrNotExist}
|
return nil, "", &os.PathError{fmt.Sprintf("read version %v", version), b.path, os.ErrNotExist}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bindata) ReadDown(version uint) (r io.ReadCloser, identifier string, err error) {
|
func (b *Bindata) ReadDown(version uint) (r io.ReadCloser, identifier string, err error) {
|
||||||
if _, ok := b.files[version]; ok {
|
if m, ok := b.migrations.Down(version); ok {
|
||||||
if downFile, ok := b.files[version][down]; ok {
|
body, err := b.assetSource.AssetFunc(m.Raw)
|
||||||
body, err := b.assetSource.AssetFunc(downFile.filename)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
return ioutil.NopCloser(bytes.NewReader(body)), downFile.name, nil
|
return ioutil.NopCloser(bytes.NewReader(body)), m.Identifier, nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil, "", &os.PathError{fmt.Sprintf("read version %v", version), b.path, os.ErrNotExist}
|
return nil, "", &os.PathError{fmt.Sprintf("read version %v", version), b.path, os.ErrNotExist}
|
||||||
}
|
}
|
||||||
|
|
||||||
// findPos finds the position of a file in the index
|
|
||||||
// returns -1 if the version can't be found
|
|
||||||
func (b *Bindata) findPos(version uint) int {
|
|
||||||
if len(b.filesIndex) > 0 {
|
|
||||||
for i, v := range b.filesIndex {
|
|
||||||
if v == version {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
// file contains parsed filename details
|
|
||||||
type file struct {
|
|
||||||
version uint
|
|
||||||
name string
|
|
||||||
direction direction
|
|
||||||
extension string
|
|
||||||
filename string
|
|
||||||
}
|
|
||||||
|
|
||||||
var errParseFilenameNoMatch = fmt.Errorf("no match")
|
|
||||||
|
|
||||||
func parseFilename(filename string) (*file, error) {
|
|
||||||
m := filenameRegex.FindStringSubmatch(filename)
|
|
||||||
if len(m) == 5 {
|
|
||||||
versionUint64, err := strconv.ParseUint(m[1], 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &file{
|
|
||||||
version: uint(versionUint64),
|
|
||||||
name: m[2],
|
|
||||||
direction: direction(m[3]),
|
|
||||||
extension: m[4],
|
|
||||||
filename: filename,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return nil, errParseFilenameNoMatch
|
|
||||||
}
|
|
||||||
|
|
||||||
type direction string
|
|
||||||
|
|
||||||
const (
|
|
||||||
down direction = "down"
|
|
||||||
up = "up"
|
|
||||||
)
|
|
||||||
|
|
||||||
type uintSlice []uint
|
|
||||||
|
|
||||||
func (s uintSlice) Len() int {
|
|
||||||
return len(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s uintSlice) Swap(i, j int) {
|
|
||||||
s[i], s[j] = s[j], s[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s uintSlice) Less(i, j int) bool {
|
|
||||||
return s[i] < s[j]
|
|
||||||
}
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ func Test(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWithInstance(t *testing.T) {
|
func TestWithInstance(t *testing.T) {
|
||||||
// wrap assets into Resource first
|
// wrap assets into Resource
|
||||||
s := Resource(testdata.AssetNames(),
|
s := Resource(testdata.AssetNames(),
|
||||||
func(name string) ([]byte, error) {
|
func(name string) ([]byte, error) {
|
||||||
return testdata.Asset(name)
|
return testdata.Asset(name)
|
||||||
|
|
Loading…
Reference in New Issue