forked from golang-migrate/migrate
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add http.FileSystem migration source driver support
This PR adds a new migration source driver capable of reading files from any source that implements http.FileSystem interface. Notable http.FileSystem interface implementations: * http.Dir() - wrapper over local file-system * github.com/shurcooL/vfsgen Because user of this package is responsible for getting an implementation of http.FileSystem, this driver does not support creating instances from driver URLs.
- Loading branch information
Showing
11 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# httpfs | ||
|
||
## Usage | ||
|
||
To create migration data source from `http.FileSystem` instance use | ||
`WithInstance()` function. Users of this package are responsible for getting | ||
`http.FileSystem` instance. It is not possible to create httpfs instance from | ||
URL. | ||
|
||
Example of using `http.Dir()` to read migrations from `sql` directory: | ||
|
||
```go | ||
src, err := httpfs.WithInstance(http.Dir("sql"), "") | ||
m, err := migrate.NewWithSourceInstance("httpfs", src, "database://url") | ||
err = m.Up() | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
package httpfs | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"os" | ||
"path" | ||
|
||
"github.com/golang-migrate/migrate/v4/source" | ||
) | ||
|
||
// driver is a migration source driver for reading migrations from | ||
// http.FileSystem instances. It implements source.Driver interface and can be | ||
// used as a migration source for the main migrate library. | ||
type driver struct { | ||
migrations *source.Migrations | ||
fs http.FileSystem | ||
path string | ||
} | ||
|
||
// WithInstance creates new migrate source driver from a http.FileSystem | ||
// instance and a relative path to migration files within the virtual FS. | ||
func WithInstance(fs http.FileSystem, path string) (source.Driver, error) { | ||
root, err := fs.Open(path) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer root.Close() | ||
|
||
files, err := root.Readdir(0) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
ms := source.NewMigrations() | ||
for _, file := range files { | ||
if file.IsDir() { | ||
continue | ||
} | ||
|
||
m, err := source.DefaultParse(file.Name()) | ||
if err != nil { | ||
continue // ignore files that we can't parse | ||
} | ||
|
||
if !ms.Append(m) { | ||
return nil, fmt.Errorf("duplicate migration file: %v", file.Name()) | ||
} | ||
} | ||
|
||
return &driver{ | ||
fs: fs, | ||
path: path, | ||
migrations: ms, | ||
}, nil | ||
} | ||
|
||
// Open is part of source.Driver interface implementation. It always returns | ||
// error because http.FileSystem must be provided by the user of this package | ||
// and created using WithInstance() function. | ||
func (h *driver) Open(url string) (source.Driver, error) { | ||
return nil, fmt.Errorf("not implemented") | ||
} | ||
|
||
// Close is part of source.Driver interface implementation. This is a no-op. | ||
func (h *driver) Close() error { | ||
return nil | ||
} | ||
|
||
// First is part of source.Driver interface implementation. | ||
func (h *driver) First() (version uint, err error) { | ||
if version, ok := h.migrations.First(); ok { | ||
return version, nil | ||
} | ||
return 0, &os.PathError{ | ||
Op: "first", | ||
Path: h.path, | ||
Err: os.ErrNotExist, | ||
} | ||
} | ||
|
||
// Prev is part of source.Driver interface implementation. | ||
func (h *driver) Prev(version uint) (prevVersion uint, err error) { | ||
if version, ok := h.migrations.Prev(version); ok { | ||
return version, nil | ||
} | ||
return 0, &os.PathError{ | ||
Op: fmt.Sprintf("prev for version %v", version), | ||
Path: h.path, | ||
Err: os.ErrNotExist, | ||
} | ||
} | ||
|
||
// Next is part of source.Driver interface implementation. | ||
func (h *driver) Next(version uint) (nextVersion uint, err error) { | ||
if version, ok := h.migrations.Next(version); ok { | ||
return version, nil | ||
} | ||
return 0, &os.PathError{ | ||
Op: fmt.Sprintf("next for version %v", version), | ||
Path: h.path, | ||
Err: os.ErrNotExist, | ||
} | ||
} | ||
|
||
// ReadUp is part of source.Driver interface implementation. | ||
func (h *driver) ReadUp(version uint) (r io.ReadCloser, identifier string, err error) { | ||
m, ok := h.migrations.Up(version) | ||
if !ok { | ||
return nil, "", &os.PathError{ | ||
Op: fmt.Sprintf("read version %v", version), | ||
Path: h.path, | ||
Err: os.ErrNotExist, | ||
} | ||
} | ||
body, err := h.fs.Open(path.Join(h.path, m.Raw)) | ||
if err != nil { | ||
return nil, "", err | ||
} | ||
return body, m.Identifier, nil | ||
} | ||
|
||
// ReadDown is part of source.Driver interface implementation. | ||
func (h *driver) ReadDown(version uint) (r io.ReadCloser, identifier string, err error) { | ||
m, ok := h.migrations.Down(version) | ||
if !ok { | ||
return nil, "", &os.PathError{ | ||
Op: fmt.Sprintf("read version %v", version), | ||
Path: h.path, | ||
Err: os.ErrNotExist, | ||
} | ||
} | ||
body, err := h.fs.Open(path.Join(h.path, m.Raw)) | ||
if err != nil { | ||
return nil, "", err | ||
} | ||
return body, m.Identifier, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package httpfs | ||
|
||
import ( | ||
"net/http" | ||
"testing" | ||
|
||
st "github.com/golang-migrate/migrate/v4/source/testing" | ||
) | ||
|
||
func TestWithInstance(t *testing.T) { | ||
t.Run("empty path", func(t *testing.T) { | ||
d, err := WithInstance(http.Dir("testdata/sql"), "") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
st.Test(t, d) | ||
}) | ||
|
||
t.Run("with path", func(t *testing.T) { | ||
d, err := WithInstance(http.Dir("testdata"), "sql") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
st.Test(t, d) | ||
}) | ||
|
||
} | ||
|
||
func TestOpen(t *testing.T) { | ||
b := &driver{} | ||
d, err := b.Open("") | ||
if d != nil { | ||
t.Error("Expected Open to return nil driver") | ||
} | ||
if err == nil { | ||
t.Error("Expected Open to return error") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
1 down |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
1 up |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
3 up |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
4 down |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
4 up |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
5 down |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
7 down |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
7 up |