migrate: add support for new Go io/fs.FS
This patch adds FromFS function and lets you use the new go:embed directive to add the migration files to the binary. Also, migration tests use an in memory FS impl instead of working with tmp directories.
This commit is contained in:
committed by
Michal Jan Matczuk
parent
7980a955be
commit
fe1498fe13
@@ -10,6 +10,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -90,10 +91,20 @@ func ensureInfoTable(ctx context.Context, session gocqlx.Session) error {
|
||||
return session.ContextQuery(ctx, infoSchema, nil).ExecRelease()
|
||||
}
|
||||
|
||||
// Migrate reads the cql files from a directory and applies required migrations.
|
||||
// It also supports code based migrations, see Callback and CallbackFunc.
|
||||
// Any comment in form `-- CALL <name>;` will trigger an CallComment callback.
|
||||
// Migrate is a wrapper around FromFS.
|
||||
// It executes migrations from a directory on disk.
|
||||
//
|
||||
// Deprecated: use FromFS instead
|
||||
func Migrate(ctx context.Context, session gocqlx.Session, dir string) error {
|
||||
return FromFS(ctx, session, os.DirFS(dir))
|
||||
}
|
||||
|
||||
// FromFS executes new CQL files from a file system abstraction (io/fs.FS).
|
||||
// The provided FS has to be a flat directory containing *.cql files.
|
||||
//
|
||||
// It supports code based migrations, see Callback and CallbackFunc.
|
||||
// Any comment in form `-- CALL <name>;` will trigger an CallComment callback.
|
||||
func FromFS(ctx context.Context, session gocqlx.Session, f fs.FS) error {
|
||||
// get database migrations
|
||||
dbm, err := List(ctx, session)
|
||||
if err != nil {
|
||||
@@ -101,26 +112,26 @@ func Migrate(ctx context.Context, session gocqlx.Session, dir string) error {
|
||||
}
|
||||
|
||||
// get file migrations
|
||||
fm, err := filepath.Glob(filepath.Join(dir, "*.cql"))
|
||||
fm, err := fs.Glob(f, "*.cql")
|
||||
if err != nil {
|
||||
return fmt.Errorf("list migrations in %q: %s", dir, err)
|
||||
return fmt.Errorf("list migrations: %w", err)
|
||||
}
|
||||
if len(fm) == 0 {
|
||||
return fmt.Errorf("no migration files found in %q", dir)
|
||||
return fmt.Errorf("no migration files found")
|
||||
}
|
||||
sort.Strings(fm)
|
||||
|
||||
// verify migrations
|
||||
if len(dbm) > len(fm) {
|
||||
return fmt.Errorf("database is ahead of %q", dir)
|
||||
return fmt.Errorf("database is ahead")
|
||||
}
|
||||
|
||||
for i := 0; i < len(dbm); i++ {
|
||||
if dbm[i].Name != filepath.Base(fm[i]) {
|
||||
fmt.Println(dbm[i].Name, filepath.Base(fm[i]), i)
|
||||
if dbm[i].Name != fm[i] {
|
||||
fmt.Println(dbm[i].Name, fm[i], i)
|
||||
return errors.New("inconsistent migrations")
|
||||
}
|
||||
c, err := fileChecksum(fm[i])
|
||||
c, err := fileChecksum(f, fm[i])
|
||||
if err != nil {
|
||||
return fmt.Errorf("calculate checksum for %q: %s", fm[i], err)
|
||||
}
|
||||
@@ -132,13 +143,13 @@ func Migrate(ctx context.Context, session gocqlx.Session, dir string) error {
|
||||
// apply migrations
|
||||
if len(dbm) > 0 {
|
||||
last := len(dbm) - 1
|
||||
if err := applyMigration(ctx, session, fm[last], dbm[last].Done); err != nil {
|
||||
if err := applyMigration(ctx, session, f, fm[last], dbm[last].Done); err != nil {
|
||||
return fmt.Errorf("apply migration %q: %s", fm[last], err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := len(dbm); i < len(fm); i++ {
|
||||
if err := applyMigration(ctx, session, fm[i], 0); err != nil {
|
||||
if err := applyMigration(ctx, session, f, fm[i], 0); err != nil {
|
||||
return fmt.Errorf("apply migration %q: %s", fm[i], err)
|
||||
}
|
||||
}
|
||||
@@ -150,14 +161,14 @@ func Migrate(ctx context.Context, session gocqlx.Session, dir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyMigration(ctx context.Context, session gocqlx.Session, path string, done int) error {
|
||||
f, err := os.Open(path)
|
||||
func applyMigration(ctx context.Context, session gocqlx.Session, f fs.FS, path string, done int) error {
|
||||
file, err := f.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(f)
|
||||
f.Close()
|
||||
b, err := ioutil.ReadAll(file)
|
||||
file.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user