update go-bindata with latest source.Migration helper

This commit is contained in:
Matthias Kadenbach 2017-02-07 22:59:12 -08:00
parent 3889c93b63
commit f7699f1dec
4 changed files with 30 additions and 119 deletions

View File

@ -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

View File

@ -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)
}) })

View File

@ -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]
}

View File

@ -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)